github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/query/query4_test.go (about)

     1  /*
     2   * Copyright 2019 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package query
    18  
    19  import (
    20  	"context"
    21  	// "encoding/json"
    22  	// "fmt"
    23  	// "strings"
    24  	"testing"
    25  
    26  	"github.com/stretchr/testify/require"
    27  	// "google.golang.org/grpc/metadata"
    28  )
    29  
    30  func TestDeleteAndReaddIndex(t *testing.T) {
    31  	// Add new predicate with several indices.
    32  	s1 := testSchema + "\n numerology: string @index(exact, term, fulltext) .\n"
    33  	setSchema(s1)
    34  	triples := `
    35  		<0x666> <numerology> "This number is evil"  .
    36  		<0x777> <numerology> "This number is good"  .
    37  	`
    38  	addTriplesToCluster(triples)
    39  
    40  	// Verify fulltext index works as expected.
    41  	q1 := `
    42  	{
    43  		me(func: anyoftext(numerology, "numbers")) {
    44  			uid
    45  			numerology
    46  		}
    47  	}`
    48  	js := processQueryNoErr(t, q1)
    49  	require.JSONEq(t, `{"data": {"me": [
    50  		{"uid": "0x666", "numerology": "This number is evil"},
    51  		{"uid": "0x777", "numerology": "This number is good"}
    52  	]}}`, js)
    53  
    54  	// Remove the fulltext index and verify the previous query is no longer supported.
    55  	s2 := testSchema + "\n numerology: string @index(exact, term) .\n"
    56  	setSchema(s2)
    57  	_, err := processQuery(context.Background(), t, q1)
    58  	require.Error(t, err)
    59  	require.Contains(t, err.Error(), "Attribute numerology is not indexed with type fulltext")
    60  
    61  	// Verify term index still works as expected.
    62  	q2 := `
    63  	{
    64  		me(func: anyofterms(numerology, "number")) {
    65  			uid
    66  			numerology
    67  		}
    68  	}`
    69  	js = processQueryNoErr(t, q2)
    70  	require.JSONEq(t, `{"data": {"me": [
    71  		{"uid": "0x666", "numerology": "This number is evil"},
    72  		{"uid": "0x777", "numerology": "This number is good"}
    73  	]}}`, js)
    74  
    75  	// Re-add index and verify that the original query works again.
    76  	setSchema(s1)
    77  	js = processQueryNoErr(t, q1)
    78  	require.JSONEq(t, `{"data": {"me": [
    79  		{"uid": "0x666", "numerology": "This number is evil"},
    80  		{"uid": "0x777", "numerology": "This number is good"}
    81  	]}}`, js)
    82  
    83  	// Finally, drop the predicate and restore schema.
    84  	dropPredicate("numerology")
    85  	setSchema(testSchema)
    86  }
    87  
    88  func TestDeleteAndReaddCount(t *testing.T) {
    89  	// Add new predicate with count index.
    90  	s1 := testSchema + "\n numerology: string @count .\n"
    91  	setSchema(s1)
    92  	triples := `
    93  		<0x666> <numerology> "This number is evil"  .
    94  		<0x777> <numerology> "This number is good"  .
    95  	`
    96  	addTriplesToCluster(triples)
    97  
    98  	// Verify count index works as expected.
    99  	q1 := `
   100  	{
   101  		me(func: gt(count(numerology), 0)) {
   102  			uid
   103  			numerology
   104  		}
   105  	}`
   106  	js := processQueryNoErr(t, q1)
   107  	require.JSONEq(t, `{"data": {"me": [
   108  		{"uid": "0x666", "numerology": "This number is evil"},
   109  		{"uid": "0x777", "numerology": "This number is good"}
   110  	]}}`, js)
   111  
   112  	// Remove the count index and verify the previous query is no longer supported.
   113  	s2 := testSchema + "\n numerology: string .\n"
   114  	setSchema(s2)
   115  	_, err := processQuery(context.Background(), t, q1)
   116  	require.Error(t, err)
   117  	require.Contains(t, err.Error(), "Need @count directive in schema for attr: numerology")
   118  
   119  	// Re-add count index and verify that the original query works again.
   120  	setSchema(s1)
   121  	js = processQueryNoErr(t, q1)
   122  	require.JSONEq(t, `{"data": {"me": [
   123  		{"uid": "0x666", "numerology": "This number is evil"},
   124  		{"uid": "0x777", "numerology": "This number is good"}
   125  	]}}`, js)
   126  
   127  	// Finally, drop the predicate and restore schema.
   128  	dropPredicate("numerology")
   129  	setSchema(testSchema)
   130  }
   131  
   132  func TestDeleteAndReaddReverse(t *testing.T) {
   133  	// Add new predicate with a reverse edge.
   134  	s1 := testSchema + "\n child_pred: uid @reverse .\n"
   135  	setSchema(s1)
   136  	triples := `<0x666> <child_pred> <0x777>  .`
   137  	addTriplesToCluster(triples)
   138  
   139  	// Verify reverse edges works as expected.
   140  	q1 := `
   141  	{
   142  		me(func: uid(0x777)) {
   143  			~child_pred {
   144  				uid
   145  			}
   146  		}
   147  	}`
   148  	js := processQueryNoErr(t, q1)
   149  	require.JSONEq(t, `{"data": {"me": [{"~child_pred": [{"uid": "0x666"}]}]}}`, js)
   150  
   151  	// Remove the reverse edges and verify the previous query is no longer supported.
   152  	s2 := testSchema + "\n child_pred: uid .\n"
   153  	setSchema(s2)
   154  	_, err := processQuery(context.Background(), t, q1)
   155  	require.Error(t, err)
   156  	require.Contains(t, err.Error(), "Predicate child_pred doesn't have reverse edge")
   157  
   158  	// Re-add reverse edges and verify that the original query works again.
   159  	setSchema(s1)
   160  	js = processQueryNoErr(t, q1)
   161  	require.JSONEq(t, `{"data": {"me": [{"~child_pred": [{"uid": "0x666"}]}]}}`, js)
   162  
   163  	// Finally, drop the predicate and restore schema.
   164  	dropPredicate("child_pred")
   165  	setSchema(testSchema)
   166  }
   167  
   168  func TestDropPredicate(t *testing.T) {
   169  	// Add new predicate with several indices.
   170  	s1 := testSchema + "\n numerology: string @index(term) .\n"
   171  	setSchema(s1)
   172  	triples := `
   173  		<0x666> <numerology> "This number is evil"  .
   174  		<0x777> <numerology> "This number is good"  .
   175  	`
   176  	addTriplesToCluster(triples)
   177  
   178  	// Verify queries work as expected.
   179  	q1 := `
   180  	{
   181  		me(func: anyofterms(numerology, "number")) {
   182  			uid
   183  			numerology
   184  		}
   185  	}`
   186  	js := processQueryNoErr(t, q1)
   187  	require.JSONEq(t, `{"data": {"me": [
   188  		{"uid": "0x666", "numerology": "This number is evil"},
   189  		{"uid": "0x777", "numerology": "This number is good"}
   190  	]}}`, js)
   191  
   192  	// Finally, drop the predicate and verify the query no longer works because
   193  	// the index was dropped when all the data for that predicate was deleted.
   194  	dropPredicate("numerology")
   195  	_, err := processQuery(context.Background(), t, q1)
   196  	require.Error(t, err)
   197  	require.Contains(t, err.Error(), "Attribute numerology is not indexed with type term")
   198  
   199  	// Finally, restore the schema.
   200  	setSchema(testSchema)
   201  }
   202  
   203  func TestNestedExpandAll(t *testing.T) {
   204  	query := `{
   205  		q(func: has(node)) {
   206  			uid
   207  			expand(_all_) {
   208  				uid
   209  				node {
   210  					uid
   211  					expand(_all_)
   212  				}
   213  			}
   214  		}
   215  	}`
   216  	js := processQueryNoErr(t, query)
   217  	require.JSONEq(t, `{"data": {
   218      "q": [
   219        {
   220          "uid": "0x2b5c",
   221          "name": "expand",
   222          "node": [
   223            {
   224              "uid": "0x2b5c",
   225              "node": [
   226                {
   227                  "uid": "0x2b5c",
   228                  "name": "expand"
   229                }
   230              ]
   231            }
   232          ]
   233        }
   234      ]}}`, js)
   235  }
   236  
   237  func TestNoResultsFilter(t *testing.T) {
   238  	query := `{
   239  		q(func: has(nonexistent_pred)) @filter(le(name, "abc")) {
   240  			uid
   241  		}
   242  	}`
   243  	js := processQueryNoErr(t, query)
   244  	require.JSONEq(t, `{"data": {"q": []}}`, js)
   245  }
   246  
   247  func TestNoResultsPagination(t *testing.T) {
   248  	query := `{
   249  		q(func: has(nonexistent_pred), first: 50) {
   250  			uid
   251  		}
   252  	}`
   253  	js := processQueryNoErr(t, query)
   254  	require.JSONEq(t, `{"data": {"q": []}}`, js)
   255  }
   256  
   257  func TestNoResultsGroupBy(t *testing.T) {
   258  	query := `{
   259  		q(func: has(nonexistent_pred)) @groupby(name) {
   260  			count(uid)
   261  		}
   262  	}`
   263  	js := processQueryNoErr(t, query)
   264  	require.JSONEq(t, `{"data": {}}`, js)
   265  }
   266  
   267  func TestNoResultsOrder(t *testing.T) {
   268  	query := `{
   269  		q(func: has(nonexistent_pred), orderasc: name) {
   270  			uid
   271  		}
   272  	}`
   273  	js := processQueryNoErr(t, query)
   274  	require.JSONEq(t, `{"data": {"q": []}}`, js)
   275  }
   276  
   277  func TestNoResultsCount(t *testing.T) {
   278  	query := `{
   279  		q(func: has(nonexistent_pred)) {
   280  			uid
   281  			count(friend)
   282  		}
   283  	}`
   284  	js := processQueryNoErr(t, query)
   285  	require.JSONEq(t, `{"data": {"q": []}}`, js)
   286  }
   287  
   288  func TestTypeExpandAll(t *testing.T) {
   289  	query := `{
   290  		q(func: eq(make, "Ford")) {
   291  			expand(_all_) {
   292  				uid
   293  			}
   294  		}
   295  	}`
   296  	js := processQueryNoErr(t, query)
   297  	require.JSONEq(t, `{"data": {"q":[
   298  		{"make":"Ford","model":"Focus","year":2008, "~previous_model": [{"uid":"0xc9"}]},
   299  		{"make":"Ford","model":"Focus","year":2009, "previous_model": {"uid":"0xc8"}}
   300  	]}}`, js)
   301  }
   302  
   303  func TestTypeExpandForward(t *testing.T) {
   304  	query := `{
   305  		q(func: eq(make, "Ford")) {
   306  			expand(_forward_) {
   307  				uid
   308  			}
   309  		}
   310  	}`
   311  	js := processQueryNoErr(t, query)
   312  	require.JSONEq(t, `{"data": {"q":[
   313  		{"make":"Ford","model":"Focus","year":2008},
   314  		{"make":"Ford","model":"Focus","year":2009, "previous_model": {"uid":"0xc8"}}
   315  	]}}`, js)
   316  }
   317  
   318  func TestTypeExpandReverse(t *testing.T) {
   319  	query := `{
   320  		q(func: eq(make, "Ford")) {
   321  			expand(_reverse_) {
   322  				uid
   323  			}
   324  		}
   325  	}`
   326  	js := processQueryNoErr(t, query)
   327  	require.JSONEq(t, `{"data": {"q":[
   328  		{"~previous_model": [{"uid":"0xc9"}]}
   329  	]}}`, js)
   330  }
   331  
   332  func TestTypeExpandLang(t *testing.T) {
   333  	query := `{
   334  		q(func: eq(make, "Toyota")) {
   335  			expand(_all_) {
   336  				uid
   337  			}
   338  		}
   339  	}`
   340  	js := processQueryNoErr(t, query)
   341  	require.JSONEq(t, `{"data": {"q":[
   342  		{"make":"Toyota","model":"Prius", "model@jp":"プリウス", "year":2009}]}}`, js)
   343  }