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

     1  /*
     2   * Copyright 2017-2018 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  	"fmt"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/require"
    25  )
    26  
    27  var (
    28  	facetSetupDone = false
    29  )
    30  
    31  func populateClusterWithFacets() {
    32  	// Return immediately if the setup has been performed already.
    33  	if facetSetupDone {
    34  		return
    35  	}
    36  
    37  	triples := `
    38  		<25> <name> "Daryl Dixon" .
    39  		<31> <name> "Andrea" .
    40  		<33> <name> "Michale" .
    41  		<320> <name> "Test facet"@en (type = "Test facet with lang") .
    42  
    43  		<31> <friend> <24> .
    44  
    45  		<33> <schools> <2433> .
    46  
    47  		<1> <gender> "female" .
    48  		<23> <gender> "male" .
    49  
    50  		<202> <model> "Prius" (type = "Electric") .
    51  	`
    52  
    53  	friendFacets1 := "(since = 2006-01-02T15:04:05)"
    54  	friendFacets2 := "(since = 2005-05-02T15:04:05, close = true, family = false, age = 33)"
    55  	friendFacets3 := "(since = 2004-05-02T15:04:05, close = true, family = true, tag = \"Domain3\")"
    56  	friendFacets4 := "(since = 2007-05-02T15:04:05, close = false, family = true, tag = 34)"
    57  	friendFacets5 := "(games = \"football basketball chess tennis\", close = false, age = 35)"
    58  	friendFacets6 := "(games = \"football basketball hockey\", close = false)"
    59  
    60  	triples += fmt.Sprintf("<1> <friend> <23> %s .\n", friendFacets1)
    61  	triples += fmt.Sprintf("<1> <friend> <24> %s .\n", friendFacets3)
    62  	triples += fmt.Sprintf("<1> <friend> <25> %s .\n", friendFacets4)
    63  	triples += fmt.Sprintf("<1> <friend> <31> %s .\n", friendFacets1)
    64  	triples += fmt.Sprintf("<1> <friend> <101> %s .\n", friendFacets2)
    65  	triples += fmt.Sprintf("<23> <friend> <1> %s .\n", friendFacets1)
    66  	triples += fmt.Sprintf("<31> <friend> <1> %s .\n", friendFacets5)
    67  	triples += fmt.Sprintf("<31> <friend> <25> %s .\n", friendFacets6)
    68  
    69  	nameFacets := "(origin = \"french\")"
    70  	triples += fmt.Sprintf("<1> <name> \"Michonne\" %s .\n", nameFacets)
    71  	triples += fmt.Sprintf("<23> <name> \"Rick Grimes\" %s .\n", nameFacets)
    72  	triples += fmt.Sprintf("<24> <name> \"Glenn Rhee\" %s .\n", nameFacets)
    73  
    74  	addTriplesToCluster(triples)
    75  
    76  	// Mark the setup as done so that the next tests do not have to perform it.
    77  	facetSetupDone = true
    78  }
    79  
    80  func TestRetrieveFacetsSimple(t *testing.T) {
    81  	populateClusterWithFacets()
    82  	query := `
    83  		{
    84  			me(func: uid(0x1)) {
    85  				name @facets
    86  				gender @facets
    87  			}
    88  		}
    89  	`
    90  
    91  	js := processQueryNoErr(t, query)
    92  	require.JSONEq(t,
    93  		`{"data":{"me":[{"name|origin":"french","name":"Michonne","gender":"female"}]}}`,
    94  		js)
    95  }
    96  
    97  func TestOrderFacets(t *testing.T) {
    98  	populateClusterWithFacets()
    99  	// to see how friend @facets are positioned in output.
   100  	query := `
   101  		{
   102  			me(func: uid(1)) {
   103  				friend @facets(orderasc:since) {
   104  					name
   105  				}
   106  			}
   107  		}
   108  	`
   109  
   110  	js := processQueryNoErr(t, query)
   111  	require.JSONEq(t,
   112  		`{"data":{"me":[{"friend":[{"name":"Glenn Rhee","friend|since":"2004-05-02T15:04:05Z"},{"friend|since":"2005-05-02T15:04:05Z"},{"name":"Rick Grimes","friend|since":"2006-01-02T15:04:05Z"},{"name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},{"name":"Daryl Dixon","friend|since":"2007-05-02T15:04:05Z"}]}]}}`,
   113  		js)
   114  }
   115  
   116  func TestOrderdescFacets(t *testing.T) {
   117  	populateClusterWithFacets()
   118  	// to see how friend @facets are positioned in output.
   119  	query := `
   120  		{
   121  			me(func: uid(1)) {
   122  				friend @facets(orderdesc:since) {
   123  					name
   124  				}
   125  			}
   126  		}
   127  	`
   128  
   129  	js := processQueryNoErr(t, query)
   130  	require.JSONEq(t,
   131  		`{"data":{"me":[{"friend":[{"name":"Daryl Dixon","friend|since":"2007-05-02T15:04:05Z"},{"name":"Rick Grimes","friend|since":"2006-01-02T15:04:05Z"},{"name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},{"friend|since":"2005-05-02T15:04:05Z"},{"name":"Glenn Rhee","friend|since":"2004-05-02T15:04:05Z"}]}]}}`,
   132  		js)
   133  }
   134  
   135  func TestOrderdescFacetsWithFilters(t *testing.T) {
   136  	populateClusterWithFacets()
   137  	query := `
   138  		{
   139  
   140  			var(func: uid(1)) {
   141  				f as friend
   142  			}
   143  
   144  			me(func: uid(1)) {
   145  				friend @filter(uid(f)) @facets(orderdesc:since) {
   146  					name
   147  				}
   148  			}
   149  		}
   150  	`
   151  
   152  	js := processQueryNoErr(t, query)
   153  	require.JSONEq(t,
   154  		`{"data":{"me":[{"friend":[{"name":"Daryl Dixon","friend|since":"2007-05-02T15:04:05Z"},{"name":"Rick Grimes","friend|since":"2006-01-02T15:04:05Z"},{"name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},{"friend|since":"2005-05-02T15:04:05Z"},{"name":"Glenn Rhee","friend|since":"2004-05-02T15:04:05Z"}]}]}}`,
   155  		js)
   156  }
   157  
   158  func TestRetrieveFacetsAsVars(t *testing.T) {
   159  	populateClusterWithFacets()
   160  	// to see how friend @facets are positioned in output.
   161  	query := `
   162  		{
   163  			var(func: uid(0x1)) {
   164  				friend @facets(a as since)
   165  			}
   166  
   167  			me(func: uid( 23)) {
   168  				name
   169  				val(a)
   170  			}
   171  		}
   172  	`
   173  
   174  	js := processQueryNoErr(t, query)
   175  	require.JSONEq(t,
   176  		`{"data": {"me":[{"name":"Rick Grimes","val(a)":"2006-01-02T15:04:05Z"}]}}`,
   177  		js)
   178  }
   179  
   180  func TestRetrieveFacetsUidValues(t *testing.T) {
   181  	populateClusterWithFacets()
   182  	// to see how friend @facets are positioned in output.
   183  	query := `
   184  		{
   185  			me(func: uid(0x1)) {
   186  				friend @facets {
   187  					name @facets
   188  				}
   189  			}
   190  		}
   191  	`
   192  
   193  	js := processQueryNoErr(t, query)
   194  	require.JSONEq(t,
   195  		`{"data":{"me":[{"friend":[{"name|origin":"french","name":"Rick Grimes","friend|since":"2006-01-02T15:04:05Z"},{"name|origin":"french","name":"Glenn Rhee","friend|close":true,"friend|family":true,"friend|since":"2004-05-02T15:04:05Z","friend|tag":"Domain3"},{"name":"Daryl Dixon","friend|close":false,"friend|family":true,"friend|since":"2007-05-02T15:04:05Z","friend|tag":34},{"name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},{"friend|age":33,"friend|close":true,"friend|family":false,"friend|since":"2005-05-02T15:04:05Z"}]}]}}`,
   196  		js)
   197  }
   198  
   199  func TestRetrieveFacetsAll(t *testing.T) {
   200  	populateClusterWithFacets()
   201  	query := `
   202  		{
   203  			me(func: uid(0x1)) {
   204  				name @facets
   205  				friend @facets {
   206  					name @facets
   207  					gender @facets
   208  				}
   209  				gender @facets
   210  			}
   211  		}
   212  	`
   213  
   214  	js := processQueryNoErr(t, query)
   215  	require.JSONEq(t,
   216  		`{"data":{"me":[{"name|origin":"french","name":"Michonne","friend":[{"name|origin":"french","name":"Rick Grimes","gender":"male","friend|since":"2006-01-02T15:04:05Z"},{"name|origin":"french","name":"Glenn Rhee","friend|close":true,"friend|family":true,"friend|since":"2004-05-02T15:04:05Z","friend|tag":"Domain3"},{"name":"Daryl Dixon","friend|close":false,"friend|family":true,"friend|since":"2007-05-02T15:04:05Z","friend|tag":34},{"name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},{"friend|age":33,"friend|close":true,"friend|family":false,"friend|since":"2005-05-02T15:04:05Z"}],"gender":"female"}]}}`,
   217  		js)
   218  }
   219  
   220  func TestFacetsNotInQuery(t *testing.T) {
   221  	populateClusterWithFacets()
   222  	query := `
   223  		{
   224  			me(func: uid(0x1)) {
   225  				name
   226  				gender
   227  				friend {
   228  					name
   229  					gender
   230  				}
   231  			}
   232  		}
   233  	`
   234  
   235  	js := processQueryNoErr(t, query)
   236  	require.JSONEq(t,
   237  		`{"data": {"me":[{"friend":[{"gender":"male","name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}],"gender":"female","name":"Michonne"}]}}`,
   238  		js)
   239  }
   240  
   241  func TestSubjectWithNoFacets(t *testing.T) {
   242  	populateClusterWithFacets()
   243  	// id 33 does not have any facets associated with name and school
   244  	query := `
   245  		{
   246  			me(func: uid(0x21)) {
   247  				name @facets
   248  				school @facets {
   249  					name
   250  				}
   251  			}
   252  		}
   253  	`
   254  	js := processQueryNoErr(t, query)
   255  	require.JSONEq(t,
   256  		`{"data": {"me":[{"name":"Michale"}]}}`,
   257  		js)
   258  }
   259  
   260  func TestFetchingFewFacets(t *testing.T) {
   261  	populateClusterWithFacets()
   262  	// only 1 friend of 1 has facet : "close" and she/he has no name
   263  	query := `
   264  		{
   265  			me(func: uid(0x1)) {
   266  				name
   267  				friend @facets(close) {
   268  					name
   269  				}
   270  			}
   271  		}
   272  	`
   273  
   274  	js := processQueryNoErr(t, query)
   275  	require.JSONEq(t,
   276  		`{"data":{"me":[{"name":"Michonne","friend":[{"name":"Rick Grimes"},{"name":"Glenn Rhee","friend|close":true},{"name":"Daryl Dixon","friend|close":false},{"name":"Andrea"},{"friend|close":true}]}]}}`,
   277  		js)
   278  }
   279  
   280  func TestFetchingNoFacets(t *testing.T) {
   281  	populateClusterWithFacets()
   282  	// TestFetchingFewFacets but without the facet.  Returns no facets.
   283  	query := `
   284  		{
   285  			me(func: uid(0x1)) {
   286  				name
   287  				friend @facets() {
   288  					name
   289  				}
   290  			}
   291  		}
   292  	`
   293  
   294  	js := processQueryNoErr(t, query)
   295  	require.JSONEq(t,
   296  		`{"data": {"me":[{"friend":[{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}],"name":"Michonne"}]}}`,
   297  		js)
   298  }
   299  
   300  func TestFacetsSortOrder(t *testing.T) {
   301  	populateClusterWithFacets()
   302  	// order of facets in gql query should not matter.
   303  	query := `
   304  		{
   305  			me(func: uid(0x1)) {
   306  				name
   307  				friend @facets(family, close) {
   308  					name
   309  				}
   310  			}
   311  		}
   312  	`
   313  
   314  	js := processQueryNoErr(t, query)
   315  	require.JSONEq(t,
   316  		`{"data":{"me":[{"name":"Michonne","friend":[{"name":"Rick Grimes"},{"name":"Glenn Rhee","friend|close":true,"friend|family":true},{"name":"Daryl Dixon","friend|close":false,"friend|family":true},{"name":"Andrea"},{"friend|close":true,"friend|family":false}]}]}}`,
   317  		js)
   318  }
   319  
   320  func TestUnknownFacets(t *testing.T) {
   321  	populateClusterWithFacets()
   322  	// uknown facets should be ignored.
   323  	query := `
   324  		{
   325  			me(func: uid(0x1)) {
   326  				name
   327  				friend @facets(unknownfacets1, unknownfacets2) {
   328  					name
   329  				}
   330  			}
   331  		}
   332  	`
   333  
   334  	js := processQueryNoErr(t, query)
   335  	require.JSONEq(t,
   336  		`{"data": {"me":[{"friend":[{"name":"Rick Grimes"},{"name":"Glenn Rhee"},{"name":"Daryl Dixon"},{"name":"Andrea"}],"name":"Michonne"}]}}`,
   337  		js)
   338  }
   339  
   340  func TestFacetsMutation(t *testing.T) {
   341  	populateClusterWithFacets()
   342  
   343  	// Delete friendship between Michonne and Glenn
   344  	deleteTriplesInCluster("<1> <friend> <24> .")
   345  	friendFacets := "(since = 2001-11-10T00:00:00Z, close = false, family = false)"
   346  	// 101 is not close friend now.
   347  	addTriplesToCluster(fmt.Sprintf(`<1> <friend> <101> %s .`, friendFacets))
   348  	// This test messes with the test setup, so set facetSetupDone to false so
   349  	// the next test redoes the setup.
   350  	facetSetupDone = false
   351  
   352  	query := `
   353  		{
   354  			me(func: uid(0x1)) {
   355  				name
   356  				friend @facets {
   357  					name
   358  				}
   359  			}
   360  		}
   361  	`
   362  
   363  	js := processQueryNoErr(t, query)
   364  	require.JSONEq(t,
   365  		`{"data":{"me":[{"name":"Michonne","friend":[{"name":"Rick Grimes","friend|since":"2006-01-02T15:04:05Z"},{"name":"Daryl Dixon","friend|close":false,"friend|family":true,"friend|since":"2007-05-02T15:04:05Z","friend|tag":34},{"name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},{"friend|close":false,"friend|family":false,"friend|since":"2001-11-10T00:00:00Z"}]}]}}`,
   366  		js)
   367  }
   368  
   369  func TestFacetsFilterSimple(t *testing.T) {
   370  	populateClusterWithFacets()
   371  	// find close friends of 1
   372  	query := `
   373  		{
   374  			me(func: uid(0x1)) {
   375  				name
   376  				friend @facets(eq(close, true)) {
   377  					name
   378  					uid
   379  				}
   380  			}
   381  		}
   382  	`
   383  
   384  	js := processQueryNoErr(t, query)
   385  	// 0x65 does not have name.
   386  	require.JSONEq(t,
   387  		`{"data": {"me":[{"friend":[{"uid":"0x18","name":"Glenn Rhee"},{"uid":"0x65"}],"name":"Michonne"}]}}`,
   388  		js)
   389  }
   390  
   391  func TestFacetsFilterSimple2(t *testing.T) {
   392  	populateClusterWithFacets()
   393  	// find close friends of 1
   394  	query := `
   395  		{
   396  			me(func: uid(0x1)) {
   397  				name
   398  				friend @facets(eq(tag, "Domain3")) {
   399  					name
   400  					uid
   401  				}
   402  			}
   403  		}
   404  	`
   405  
   406  	js := processQueryNoErr(t, query)
   407  	require.JSONEq(t,
   408  		`{"data": {"me":[{"friend":[{"uid":"0x18","name":"Glenn Rhee"}],"name":"Michonne"}]}}`,
   409  		js)
   410  }
   411  
   412  func TestFacetsFilterSimple3(t *testing.T) {
   413  	populateClusterWithFacets()
   414  	// find close friends of 1
   415  	query := `
   416  		{
   417  			me(func: uid(0x1)) {
   418  				name
   419  				friend @facets(eq(tag, "34")) {
   420  					name
   421  					uid
   422  				}
   423  			}
   424  		}
   425  	`
   426  
   427  	js := processQueryNoErr(t, query)
   428  	require.JSONEq(t,
   429  		`{"data": {"me":[{"friend":[{"uid":"0x19","name":"Daryl Dixon"}],"name":"Michonne"}]}}`,
   430  		js)
   431  }
   432  
   433  func TestFacetsFilterOr(t *testing.T) {
   434  	populateClusterWithFacets()
   435  	// find close or family friends of 1
   436  	query := `
   437  		{
   438  			me(func: uid(0x1)) {
   439  				name
   440  				friend @facets(eq(close, true) OR eq(family, true)) {
   441  					name
   442  					uid
   443  				}
   444  			}
   445  		}
   446  	`
   447  
   448  	js := processQueryNoErr(t, query)
   449  	// 0x65 (101) does not have name.
   450  	require.JSONEq(t,
   451  		`{"data": {"me":[{"friend":[{"uid":"0x18","name":"Glenn Rhee"},{"uid":"0x19","name":"Daryl Dixon"},{"uid":"0x65"}],"name":"Michonne"}]}}`,
   452  		js)
   453  }
   454  
   455  func TestFacetsFilterAnd(t *testing.T) {
   456  	populateClusterWithFacets()
   457  	// unknown filters do not have any effect on results.
   458  	query := `
   459  		{
   460  			me(func: uid(0x1)) {
   461  				name
   462  				friend @facets(eq(close, true) AND eq(family, false)) {
   463  					name
   464  					uid
   465  				}
   466  			}
   467  		}
   468  	`
   469  
   470  	js := processQueryNoErr(t, query)
   471  	require.JSONEq(t,
   472  		`{"data": {"me":[{"friend":[{"uid":"0x65"}],"name":"Michonne"}]}}`,
   473  		js)
   474  }
   475  
   476  func TestFacetsFilterle(t *testing.T) {
   477  	populateClusterWithFacets()
   478  	// find friends of 1 below 36 years of age.
   479  	query := `
   480  		{
   481  			me(func: uid(0x1)) {
   482  				name
   483  				friend @facets(le(age, 35)) {
   484  					name
   485  					uid
   486  				}
   487  			}
   488  		}
   489  	`
   490  
   491  	js := processQueryNoErr(t, query)
   492  	require.JSONEq(t,
   493  		`{"data": {"me":[{"friend":[{"uid":"0x65"}],"name":"Michonne"}]}}`,
   494  		js)
   495  }
   496  
   497  func TestFacetsFilterge(t *testing.T) {
   498  	populateClusterWithFacets()
   499  	// find friends of 1 above 32 years of age.
   500  	query := `
   501  		{
   502  			me(func: uid(0x1)) {
   503  				name
   504  				friend @facets(ge(age, 33)) {
   505  					name
   506  					uid
   507  				}
   508  			}
   509  		}
   510  	`
   511  
   512  	js := processQueryNoErr(t, query)
   513  	require.JSONEq(t,
   514  		`{"data": {"me":[{"friend":[{"uid":"0x65"}],"name":"Michonne"}]}}`,
   515  		js)
   516  }
   517  
   518  func TestFacetsFilterAndOrle(t *testing.T) {
   519  	populateClusterWithFacets()
   520  	// find close or family friends of 1 before 2007-01-10
   521  	query := `
   522  		{
   523  			me(func: uid(0x1)) {
   524  				name
   525  				friend @facets(eq(close, true) OR eq(family, true) AND le(since, "2007-01-10")) {
   526  					name
   527  					uid
   528  				}
   529  			}
   530  		}
   531  	`
   532  
   533  	js := processQueryNoErr(t, query)
   534  	// 0x65 (101) does not have name.
   535  	require.JSONEq(t,
   536  		`{"data": {"me":[{"friend":[{"uid":"0x18","name":"Glenn Rhee"},{"uid":"0x65"}],"name":"Michonne"}]}}`,
   537  		js)
   538  }
   539  
   540  func TestFacetsFilterAndOrge2(t *testing.T) {
   541  	populateClusterWithFacets()
   542  	// find close or family friends of 1 after 2007-01-10
   543  	query := `
   544  		{
   545  			me(func: uid(0x1)) {
   546  				name
   547  				friend @facets(eq(close, false) OR eq(family, true) AND ge(since, "2007-01-10")) {
   548  					name
   549  					uid
   550  				}
   551  			}
   552  		}
   553  	`
   554  
   555  	js := processQueryNoErr(t, query)
   556  	require.JSONEq(t,
   557  		`{"data": {"me":[{"friend":[{"uid":"0x19","name":"Daryl Dixon"}],"name":"Michonne"}]}}`,
   558  		js)
   559  }
   560  
   561  func TestFacetsFilterNotAndOrgeMutuallyExclusive(t *testing.T) {
   562  	populateClusterWithFacets()
   563  	// find Not (close or family friends of 1 after 2007-01-10)
   564  	// Mutually exclusive of above result : TestFacetsFilterNotAndOrge
   565  	query := `
   566  		{
   567  			me(func: uid(0x1)) {
   568  				name
   569  				friend @facets(not (eq(close, false) OR eq(family, true) AND ge(since, "2007-01-10"))) {
   570  					name
   571  					uid
   572  				}
   573  			}
   574  		}
   575  	`
   576  
   577  	js := processQueryNoErr(t, query)
   578  	require.JSONEq(t,
   579  		`{"data": {"me":[{"friend":[{"uid":"0x17","name":"Rick Grimes"},{"uid":"0x18","name":"Glenn Rhee"},{"uid":"0x1f","name":"Andrea"},{"uid":"0x65"}],"name":"Michonne"}]}}`,
   580  		js)
   581  }
   582  
   583  func TestFacetsFilterUnknownFacets(t *testing.T) {
   584  	populateClusterWithFacets()
   585  	// unknown facets should filter out edges.
   586  	query := `
   587  		{
   588  			me(func: uid(0x1)) {
   589  				name
   590  				friend @facets(ge(dob, "2007-01-10")) {
   591  					name
   592  					uid
   593  				}
   594  			}
   595  		}
   596  	`
   597  
   598  	js := processQueryNoErr(t, query)
   599  	require.JSONEq(t,
   600  		`{"data": {"me":[{"name":"Michonne"}]}}`,
   601  		js)
   602  }
   603  
   604  func TestFacetsFilterUnknownOrKnown(t *testing.T) {
   605  	populateClusterWithFacets()
   606  	// unknown filters with OR do not have any effect on results
   607  	query := `
   608  		{
   609  			me(func: uid(0x1)) {
   610  				name
   611  				friend @facets(ge(dob, "2007-01-10") OR eq(family, true)) {
   612  					name
   613  					uid
   614  				}
   615  			}
   616  		}
   617  	`
   618  
   619  	js := processQueryNoErr(t, query)
   620  	require.JSONEq(t,
   621  		`{"data": {"me":[{"friend":[{"uid":"0x18","name":"Glenn Rhee"},{"uid":"0x19","name":"Daryl Dixon"}],"name":"Michonne"}]}}`,
   622  		js)
   623  }
   624  
   625  func TestFacetsFilterallofterms(t *testing.T) {
   626  	populateClusterWithFacets()
   627  	query := `
   628  		{
   629  			me(func: uid(31)) {
   630  				name
   631  				friend @facets(allofterms(games, "football chess tennis")) {
   632  					name
   633  					uid
   634  				}
   635  			}
   636  		}
   637  	`
   638  
   639  	js := processQueryNoErr(t, query)
   640  	require.JSONEq(t,
   641  		`{"data": {"me":[{"friend":[{"name":"Michonne","uid":"0x1"}],"name":"Andrea"}]}}`,
   642  		js)
   643  }
   644  
   645  func TestFacetsFilterAllofMultiple(t *testing.T) {
   646  	populateClusterWithFacets()
   647  	query := `
   648  		{
   649  			me(func: uid(31)) {
   650  				name
   651  				friend @facets(allofterms(games, "football basketball")) {
   652  					name
   653  					uid
   654  				}
   655  			}
   656  		}
   657  	`
   658  
   659  	js := processQueryNoErr(t, query)
   660  	require.JSONEq(t,
   661  		`{"data": {"me":[{"friend":[{"name":"Michonne","uid":"0x1"}, {"name":"Daryl Dixon","uid":"0x19"}],"name":"Andrea"}]}}`,
   662  		js)
   663  }
   664  
   665  func TestFacetsFilterAllofNone(t *testing.T) {
   666  	populateClusterWithFacets()
   667  	// nothing matches in allofterms
   668  	query := `
   669  		{
   670  			me(func: uid(31)) {
   671  				name
   672  				friend @facets(allofterms(games, "football chess tennis cricket")) {
   673  					name
   674  					uid
   675  				}
   676  			}
   677  		}
   678  	`
   679  
   680  	js := processQueryNoErr(t, query)
   681  	require.JSONEq(t,
   682  		`{"data": {"me":[{"name":"Andrea"}]}}`,
   683  		js)
   684  }
   685  
   686  func TestFacetsFilteranyofterms(t *testing.T) {
   687  	populateClusterWithFacets()
   688  	query := `
   689  		{
   690  			me(func: uid(31)) {
   691  				name
   692  				friend @facets(anyofterms(games, "tennis cricket")) {
   693  					name
   694  					uid
   695  				}
   696  			}
   697  		}
   698  	`
   699  
   700  	js := processQueryNoErr(t, query)
   701  	require.JSONEq(t,
   702  		`{"data": {"me":[{"friend":[{"uid":"0x1","name":"Michonne"}],"name":"Andrea"}]}}`,
   703  		js)
   704  }
   705  
   706  func TestFacetsFilterAnyofNone(t *testing.T) {
   707  	populateClusterWithFacets()
   708  	query := `
   709  		{
   710  			me(func: uid(31)) {
   711  				name
   712  				friend @facets(anyofterms(games, "cricket")) {
   713  					name
   714  					uid
   715  				}
   716  			}
   717  		}
   718  	`
   719  
   720  	js := processQueryNoErr(t, query)
   721  	require.JSONEq(t,
   722  		`{"data": {"me":[{"name":"Andrea"}]}}`,
   723  		js)
   724  }
   725  
   726  func TestFacetsFilterAllofanyofterms(t *testing.T) {
   727  	populateClusterWithFacets()
   728  	query := `
   729  		{
   730  			me(func: uid(31)) {
   731  				name
   732  				friend @facets(allofterms(games, "basketball hockey") OR anyofterms(games, "chess")) {
   733  					name
   734  					uid
   735  				}
   736  			}
   737  		}
   738  	`
   739  
   740  	js := processQueryNoErr(t, query)
   741  	require.JSONEq(t,
   742  		`{"data": {"me":[{"friend":[{"uid":"0x1","name":"Michonne"},{"uid":"0x19","name":"Daryl Dixon"}],"name":"Andrea"}]}}`,
   743  		js)
   744  }
   745  
   746  func TestFacetsFilterAllofAndanyofterms(t *testing.T) {
   747  	populateClusterWithFacets()
   748  	query := `
   749  		{
   750  			me(func: uid(31)) {
   751  				name
   752  				friend @facets(allofterms(games, "hockey") AND anyofterms(games, "football basketball")) {
   753  					name
   754  					uid
   755  				}
   756  			}
   757  		}
   758  	`
   759  
   760  	js := processQueryNoErr(t, query)
   761  	require.JSONEq(t,
   762  		`{"data": {"me":[{"friend":[{"uid":"0x19","name":"Daryl Dixon"}],"name":"Andrea"}]}}`,
   763  		js)
   764  }
   765  
   766  func TestFacetsFilterAtValueFail(t *testing.T) {
   767  	populateClusterWithFacets()
   768  	// facet filtering is not supported at value level.
   769  	query := `
   770  	{
   771  		me(func: uid(1)) {
   772  			friend {
   773  				name @facets(eq(origin, "french"))
   774  			}
   775  		}
   776  	}
   777  `
   778  
   779  	_, err := processQuery(context.Background(), t, query)
   780  	require.Error(t, err)
   781  }
   782  
   783  func TestFacetsFilterAndRetrieval(t *testing.T) {
   784  	populateClusterWithFacets()
   785  	// Close should not be retrieved.. only used for filtering.
   786  	query := `
   787  		{
   788  			me(func: uid(1)) {
   789  				name
   790  				friend @facets(eq(close, true)) @facets(family) {
   791  					name
   792  					uid
   793  				}
   794  			}
   795  		}
   796  	`
   797  
   798  	js := processQueryNoErr(t, query)
   799  	require.JSONEq(t,
   800  		`{"data":{"me":[{"name":"Michonne","friend":[{"name":"Glenn Rhee","uid":"0x18","friend|family":true},{"uid":"0x65","friend|family":false}]}]}}`,
   801  		js)
   802  }
   803  
   804  func TestFacetWithLang(t *testing.T) {
   805  	populateClusterWithFacets()
   806  	query := `
   807  		{
   808  			me(func: uid(320)) {
   809  				name@en @facets
   810  			}
   811  		}
   812  	`
   813  
   814  	js := processQueryNoErr(t, query)
   815  	require.JSONEq(t, `{"data":{"me":[{"name@en|type":"Test facet with lang","name@en":"Test facet"}]}}`, js)
   816  }
   817  
   818  func TestFilterUidFacetMismatch(t *testing.T) {
   819  	populateClusterWithFacets()
   820  	query := `
   821  	{
   822  		me(func: uid(0x1)) {
   823  			friend @filter(uid(24, 101)) @facets {
   824  				name
   825  			}
   826  		}
   827  	}
   828  	`
   829  	js := processQueryNoErr(t, query)
   830  	require.JSONEq(t, `{"data":{"me":[{"friend":[{"name":"Glenn Rhee","friend|close":true,"friend|family":true,"friend|since":"2004-05-02T15:04:05Z","friend|tag":"Domain3"},{"friend|age":33,"friend|close":true,"friend|family":false,"friend|since":"2005-05-02T15:04:05Z"}]}]}}`, js)
   831  }
   832  
   833  func TestRecurseFacetOrder(t *testing.T) {
   834  	populateClusterWithFacets()
   835  	query := `
   836      {
   837  		me(func: uid(1)) @recurse(depth: 2) {
   838  			friend @facets(orderdesc: since)
   839  			uid
   840  			name
   841  		}
   842  	}
   843    `
   844  	js := processQueryNoErr(t, query)
   845  	require.JSONEq(t, `{"data":{"me":[{"friend":[
   846  			{"uid":"0x19","name":"Daryl Dixon","friend|since":"2007-05-02T15:04:05Z"},
   847  			{"uid":"0x17","name":"Rick Grimes","friend|since":"2006-01-02T15:04:05Z"},
   848  			{"uid":"0x1f","name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},
   849  			{"uid":"0x65","friend|since":"2005-05-02T15:04:05Z"},
   850  			{"uid":"0x18","name":"Glenn Rhee","friend|since":"2004-05-02T15:04:05Z"}],
   851  		"uid":"0x1","name":"Michonne"}]}}`, js)
   852  
   853  	query = `
   854      {
   855  		me(func: uid(1)) @recurse(depth: 2) {
   856  			friend @facets(orderasc: since)
   857  			uid
   858  			name
   859  		}
   860  	}
   861    `
   862  	js = processQueryNoErr(t, query)
   863  	require.JSONEq(t, `{"data":{"me":[{"friend":[
   864  			{"uid":"0x18","name":"Glenn Rhee","friend|since":"2004-05-02T15:04:05Z"},
   865  			{"uid":"0x65","friend|since":"2005-05-02T15:04:05Z"},
   866  			{"uid":"0x17","name":"Rick Grimes","friend|since":"2006-01-02T15:04:05Z"},
   867  			{"uid":"0x1f","name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},
   868  			{"uid":"0x19","name":"Daryl Dixon","friend|since":"2007-05-02T15:04:05Z"}],
   869  		"uid":"0x1","name":"Michonne"}]}}`, js)
   870  }
   871  
   872  func TestFacetsAlias(t *testing.T) {
   873  	populateClusterWithFacets()
   874  	query := `
   875  		{
   876  			me(func: uid(0x1)) {
   877  				name @facets(o: origin)
   878  				friend @facets(family, tagalias: tag, since) {
   879  					name @facets(o: origin)
   880  				}
   881  			}
   882  		}
   883  	`
   884  
   885  	js := processQueryNoErr(t, query)
   886  	require.Equal(t, `{"data":{"me":[{"o":"french","name":"Michonne","friend":[{"o":"french","name":"Rick Grimes","friend|since":"2006-01-02T15:04:05Z"},{"o":"french","name":"Glenn Rhee","friend|family":true,"friend|since":"2004-05-02T15:04:05Z","tagalias":"Domain3"},{"name":"Daryl Dixon","friend|family":true,"friend|since":"2007-05-02T15:04:05Z","tagalias":34},{"name":"Andrea","friend|since":"2006-01-02T15:04:05Z"},{"friend|family":false,"friend|since":"2005-05-02T15:04:05Z"}]}]}}`, js)
   887  }
   888  
   889  func TestFacetsAlias2(t *testing.T) {
   890  	populateClusterWithFacets()
   891  	query := `
   892  		{
   893  			me2(func: uid(0x1)) {
   894  				friend @facets(f: family, a as since, orderdesc: tag, close)
   895  			}
   896  
   897  			me(func: uid(23)) {
   898  				name
   899  				val(a)
   900  			}
   901  		}
   902  	`
   903  
   904  	js := processQueryNoErr(t, query)
   905  	require.JSONEq(t, `{"data":{"me2":[{"friend":[{"friend|close":true,"f":false,"friend|since":"2005-05-02T15:04:05Z"},{"friend|since":"2006-01-02T15:04:05Z"},{"friend|since":"2006-01-02T15:04:05Z"},{"friend|close":true,"f":true,"friend|since":"2004-05-02T15:04:05Z","friend|tag":"Domain3"},{"friend|close":false,"f":true,"friend|since":"2007-05-02T15:04:05Z","friend|tag":34}]}],"me":[{"name":"Rick Grimes", "val(a)":"2006-01-02T15:04:05Z"}]}}`, js)
   906  }
   907  
   908  func TestTypeExpandFacets(t *testing.T) {
   909  	query := `{
   910  		q(func: eq(make, "Toyota")) {
   911  			expand(_all_) {
   912  				uid
   913  			}
   914  		}
   915  	}`
   916  	js := processQueryNoErr(t, query)
   917  	require.JSONEq(t, `{"data": {"q":[
   918  		{"make":"Toyota","model":"Prius", "model@jp":"プリウス", "model|type":"Electric",
   919  			"year":2009}]}}`, js)
   920  }