github.com/weaviate/weaviate@v1.24.6/test/acceptance/graphql_resolvers/local_aggregate_matrix_setup_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package test
    13  
    14  import (
    15  	"fmt"
    16  	"time"
    17  
    18  	"github.com/weaviate/weaviate/entities/models"
    19  	"github.com/weaviate/weaviate/entities/schema"
    20  	graphqlhelper "github.com/weaviate/weaviate/test/helper/graphql"
    21  )
    22  
    23  const notExistingObjectId = "cfa3b21e-ca5f-4db7-a412-ffffffffffff"
    24  
    25  const (
    26  	arrayClassName = "ArrayClass"
    27  
    28  	objectArrayClassID1_4el   = "cfa3b21e-ca5f-4db7-a412-5fc6a23c534a"
    29  	objectArrayClassID2_3el   = "cfa3b21e-ca5f-4db7-a412-5fc6a23c534b"
    30  	objectArrayClassID3_2el   = "cfa3b21e-ca5f-4db7-a412-5fc6a23c535a"
    31  	objectArrayClassID4_1el   = "cfa3b21e-ca5f-4db7-a412-5fc6a23c535b"
    32  	objectArrayClassID5_0el   = "cfa3b21e-ca5f-4db7-a412-5fc6a23c536a"
    33  	objectArrayClassID6_nils  = "cfa3b21e-ca5f-4db7-a412-5fc6a23c536b"
    34  	objectArrayClassID7_empty = "cfa3b21e-ca5f-4db7-a412-5fc6a23c536c"
    35  )
    36  
    37  const (
    38  	noPropsClassName = "ClassWithoutProperties"
    39  
    40  	objectNoPropsClassID1 = "dfa3b21e-ca5f-4db7-a412-5fc6a23c5301"
    41  	objectNoPropsClassID2 = "dfa3b21e-ca5f-4db7-a412-5fc6a23c5311"
    42  )
    43  
    44  const (
    45  	cityClassName = "City"
    46  )
    47  
    48  const (
    49  	duplicatesClassName = "DuplicatesClass"
    50  
    51  	objectDuplicatesClassID1_4el = "a8076f34-ec16-4333-a963-00c89c5ba001"
    52  	objectDuplicatesClassID2_3el = "a8076f34-ec16-4333-a963-00c89c5ba002"
    53  	objectDuplicatesClassID3_2el = "a8076f34-ec16-4333-a963-00c89c5ba003"
    54  )
    55  
    56  func arrayClassSchema() *models.Class {
    57  	return &models.Class{
    58  		Class: arrayClassName,
    59  		ModuleConfig: map[string]interface{}{
    60  			"text2vec-contextionary": map[string]interface{}{
    61  				"vectorizeClassName": true,
    62  			},
    63  		},
    64  		InvertedIndexConfig: &models.InvertedIndexConfig{IndexPropertyLength: true, IndexNullState: true},
    65  		Properties: []*models.Property{
    66  			{
    67  				Name:         "texts",
    68  				DataType:     schema.DataTypeTextArray.PropString(),
    69  				Tokenization: models.PropertyTokenizationWord,
    70  			},
    71  			{
    72  				Name:     "numbers",
    73  				DataType: []string{"number[]"},
    74  			},
    75  			{
    76  				Name:     "ints",
    77  				DataType: []string{"int[]"},
    78  			},
    79  			{
    80  				Name:     "booleans",
    81  				DataType: []string{"boolean[]"},
    82  			},
    83  			{
    84  				Name:     "dates",
    85  				DataType: []string{"date[]"},
    86  			},
    87  		},
    88  	}
    89  }
    90  
    91  func arrayClassObjects() []*models.Object {
    92  	return []*models.Object{
    93  		objectArrayClass4el(),
    94  		objectArrayClass3el(),
    95  		objectArrayClass2el(),
    96  		objectArrayClass1el(),
    97  		objectArrayClass0el(),
    98  		objectArrayClassNils(),
    99  		objectArrayClassEmpty(),
   100  	}
   101  }
   102  
   103  func objectArrayClass4el() *models.Object {
   104  	return &models.Object{
   105  		Class: arrayClassName,
   106  		ID:    objectArrayClassID1_4el,
   107  		Properties: map[string]interface{}{
   108  			"texts":    []string{"Alpha", "Bravo", "Charlie", "Delta"},
   109  			"numbers":  []float64{1.0, 2.0, 3.0, 4.0},
   110  			"ints":     []int{101, 102, 103, 104},
   111  			"booleans": []bool{true, true, true, false},
   112  			"dates": []string{
   113  				"2021-06-01T22:18:59.640162Z",
   114  				"2022-06-02T22:18:59.640162Z",
   115  				"2023-06-03T22:18:59.640162Z",
   116  				"2024-06-04T22:18:59.640162Z",
   117  			},
   118  		},
   119  	}
   120  }
   121  
   122  func objectArrayClass3el() *models.Object {
   123  	return &models.Object{
   124  		Class: arrayClassName,
   125  		ID:    objectArrayClassID2_3el,
   126  		Properties: map[string]interface{}{
   127  			"texts":    []string{"Alpha", "Bravo", "Charlie"},
   128  			"numbers":  []float64{1.0, 2.0, 3.0},
   129  			"ints":     []int{101, 102, 103},
   130  			"booleans": []bool{true, true, false},
   131  			"dates": []string{
   132  				"2021-06-01T22:18:59.640162Z",
   133  				"2022-06-02T22:18:59.640162Z",
   134  				"2023-06-03T22:18:59.640162Z",
   135  			},
   136  		},
   137  	}
   138  }
   139  
   140  func objectArrayClass2el() *models.Object {
   141  	return &models.Object{
   142  		Class: arrayClassName,
   143  		ID:    objectArrayClassID3_2el,
   144  		Properties: map[string]interface{}{
   145  			"texts":    []string{"Alpha", "Bravo"},
   146  			"numbers":  []float64{1.0, 2.0},
   147  			"ints":     []int{101, 102},
   148  			"booleans": []bool{true, false},
   149  			"dates": []string{
   150  				"2021-06-01T22:18:59.640162Z",
   151  				"2022-06-02T22:18:59.640162Z",
   152  			},
   153  		},
   154  	}
   155  }
   156  
   157  func objectArrayClass1el() *models.Object {
   158  	return &models.Object{
   159  		Class: arrayClassName,
   160  		ID:    objectArrayClassID4_1el,
   161  		Properties: map[string]interface{}{
   162  			"texts":    []string{"Alpha"},
   163  			"numbers":  []float64{1.0},
   164  			"ints":     []int{101},
   165  			"booleans": []bool{false},
   166  			"dates": []string{
   167  				"2021-06-01T22:18:59.640162Z",
   168  			},
   169  		},
   170  	}
   171  }
   172  
   173  func objectArrayClass0el() *models.Object {
   174  	return &models.Object{
   175  		Class: arrayClassName,
   176  		ID:    objectArrayClassID5_0el,
   177  		Properties: map[string]interface{}{
   178  			"texts":    []string{},
   179  			"numbers":  []float64{},
   180  			"ints":     []int{},
   181  			"booleans": []bool{},
   182  			"dates":    []time.Time{},
   183  		},
   184  	}
   185  }
   186  
   187  func objectArrayClassNils() *models.Object {
   188  	return &models.Object{
   189  		Class: arrayClassName,
   190  		ID:    objectArrayClassID6_nils,
   191  		Properties: map[string]interface{}{
   192  			"texts":    nil,
   193  			"numbers":  nil,
   194  			"ints":     nil,
   195  			"booleans": nil,
   196  			"dates":    nil,
   197  		},
   198  	}
   199  }
   200  
   201  func objectArrayClassEmpty() *models.Object {
   202  	return &models.Object{
   203  		Class: arrayClassName,
   204  		ID:    objectArrayClassID7_empty,
   205  	}
   206  }
   207  
   208  func aggregateArrayClassQuery(filters, groupBy string) string {
   209  	query := `{
   210  			Aggregate {
   211  				%s
   212  				%s
   213  				{
   214  					meta{
   215  						count
   216  					}
   217  					booleans{
   218  						count
   219  						type
   220  						totalTrue
   221  						totalFalse
   222  						percentageTrue
   223  						percentageFalse
   224  					}
   225  					texts{
   226  						count
   227  						type
   228  						topOccurrences {
   229  							value
   230  							occurs
   231  						}
   232  					}
   233  					numbers{
   234  						count
   235  						type
   236  						minimum
   237  						maximum
   238  						mean
   239  						median
   240  						mode
   241  						sum
   242  					}
   243  					ints{
   244  						count
   245  						type
   246  						minimum
   247  						maximum
   248  						mean
   249  						median
   250  						mode
   251  						sum
   252  					}
   253  					dates{
   254  						count
   255  					}
   256  					%s
   257  				}
   258  			}
   259  		}`
   260  
   261  	params := ""
   262  	if filters != "" || groupBy != "" {
   263  		params = fmt.Sprintf(
   264  			`(
   265  				%s
   266  				%s
   267  			)`, filters, groupBy)
   268  	}
   269  	groupedBy := ""
   270  	if groupBy != "" {
   271  		groupedBy = `groupedBy{
   272  						value
   273  						path
   274  					}`
   275  	}
   276  
   277  	return fmt.Sprintf(query, arrayClassName, params, groupedBy)
   278  }
   279  
   280  func extractAggregateResult(result *graphqlhelper.GraphQLResult, className string) []interface{} {
   281  	return result.Get("Aggregate", className).AsSlice()
   282  }
   283  
   284  func noPropsClassSchema() *models.Class {
   285  	return &models.Class{
   286  		Class: noPropsClassName,
   287  		ModuleConfig: map[string]interface{}{
   288  			"text2vec-contextionary": map[string]interface{}{
   289  				"vectorizeClassName": true,
   290  			},
   291  		},
   292  	}
   293  }
   294  
   295  func noPropsClassObjects() []*models.Object {
   296  	return []*models.Object{
   297  		objectNoPropsClass1(),
   298  		objectNoPropsClass2(),
   299  	}
   300  }
   301  
   302  func objectNoPropsClass1() *models.Object {
   303  	return &models.Object{
   304  		Class: noPropsClassName,
   305  		ID:    objectNoPropsClassID1,
   306  	}
   307  }
   308  
   309  func objectNoPropsClass2() *models.Object {
   310  	return &models.Object{
   311  		Class: noPropsClassName,
   312  		ID:    objectNoPropsClassID2,
   313  	}
   314  }
   315  
   316  func aggregateNoPropsQuery(filters string) string {
   317  	query := `
   318  			{
   319  				Aggregate {
   320  					%s
   321  					%s
   322  					{
   323  						meta{
   324  							count
   325  						}
   326  					}
   327  				}
   328  			}
   329  		`
   330  
   331  	params := ""
   332  	if filters != "" {
   333  		params = fmt.Sprintf(
   334  			`(
   335  				%s
   336  			)`, filters)
   337  	}
   338  
   339  	return fmt.Sprintf(query, noPropsClassName, params)
   340  }
   341  
   342  func aggregateCityQuery(filters, groupBy string) string {
   343  	query := `{
   344  			Aggregate {
   345  				%s
   346  				%s
   347  				{
   348  					meta {
   349  						count
   350  					}
   351  					name {
   352  						count
   353  						type
   354  						topOccurrences {
   355  							value
   356  							occurs
   357  						}
   358  					}
   359  					cityArea {
   360  						count
   361  						type
   362  						minimum
   363  						maximum
   364  						mean
   365  						median
   366  						mode
   367  						sum
   368  					}
   369  					isCapital {
   370  						count
   371  						type
   372  						totalTrue
   373  						totalFalse
   374  						percentageTrue
   375  						percentageFalse
   376  					}
   377  					population {
   378  						count
   379  						type
   380  						minimum
   381  						maximum
   382  						mean
   383  						median
   384  						mode
   385  						sum
   386  					}
   387  					cityRights {
   388  						count
   389  					}
   390  					history {
   391  						count
   392  						type
   393  						topOccurrences {
   394  							value
   395  							occurs
   396  						}
   397  					}
   398  					museums {
   399  						count
   400  						type
   401  						topOccurrences {
   402  							value
   403  							occurs
   404  						}
   405  					}
   406  					timezones {
   407  						count
   408  						type
   409  						topOccurrences {
   410  							value
   411  							occurs
   412  						}
   413  					}
   414  					inCountry {
   415  						pointingTo
   416  						type
   417  					}
   418  					%s
   419  				}
   420  			}
   421  		}`
   422  
   423  	params := ""
   424  	if filters != "" || groupBy != "" {
   425  		params = fmt.Sprintf(
   426  			`(
   427  				%s
   428  				%s
   429  			)`, filters, groupBy)
   430  	}
   431  	groupedBy := ""
   432  	if groupBy != "" {
   433  		groupedBy = `groupedBy{
   434  						value
   435  						path
   436  					}`
   437  	}
   438  
   439  	return fmt.Sprintf(query, cityClassName, params, groupedBy)
   440  }
   441  
   442  func duplicatesClassSchema() *models.Class {
   443  	return &models.Class{
   444  		Class: duplicatesClassName,
   445  		ModuleConfig: map[string]interface{}{
   446  			"text2vec-contextionary": map[string]interface{}{
   447  				"vectorizeClassName": true,
   448  			},
   449  		},
   450  		Properties: []*models.Property{
   451  			{
   452  				Name:         "texts",
   453  				DataType:     schema.DataTypeTextArray.PropString(),
   454  				Tokenization: models.PropertyTokenizationWord,
   455  			},
   456  			{
   457  				Name:     "numbers",
   458  				DataType: []string{"number[]"},
   459  			},
   460  			{
   461  				Name:     "ints",
   462  				DataType: []string{"int[]"},
   463  			},
   464  			{
   465  				Name:     "booleans",
   466  				DataType: []string{"boolean[]"},
   467  			},
   468  			{
   469  				Name:     "dates",
   470  				DataType: []string{"date[]"},
   471  			},
   472  		},
   473  	}
   474  }
   475  
   476  func duplicatesClassObjects() []*models.Object {
   477  	return []*models.Object{
   478  		objectDuplicatesClass4el(),
   479  		objectDuplicatesClass3el(),
   480  		objectDuplicatesClass2el(),
   481  	}
   482  }
   483  
   484  func objectDuplicatesClass4el() *models.Object {
   485  	return &models.Object{
   486  		Class: duplicatesClassName,
   487  		ID:    objectDuplicatesClassID1_4el,
   488  		Properties: map[string]interface{}{
   489  			"texts":    []string{"Alpha", "Alpha", "Alpha", "Bravo"},
   490  			"numbers":  []float64{1.0, 1.0, 1.0, 2.0},
   491  			"ints":     []int{101, 101, 101, 102},
   492  			"booleans": []bool{true, true, true, false},
   493  			"dates": []string{
   494  				"2021-06-01T22:18:59.640162Z",
   495  				"2021-06-01T22:18:59.640162Z",
   496  				"2021-06-01T22:18:59.640162Z",
   497  				"2022-06-02T22:18:59.640162Z",
   498  			},
   499  		},
   500  	}
   501  }
   502  
   503  func objectDuplicatesClass3el() *models.Object {
   504  	return &models.Object{
   505  		Class: duplicatesClassName,
   506  		ID:    objectDuplicatesClassID2_3el,
   507  		Properties: map[string]interface{}{
   508  			"texts":    []string{"Alpha", "Alpha", "Bravo"},
   509  			"numbers":  []float64{1.0, 1.0, 2.0},
   510  			"ints":     []int{101, 101, 102},
   511  			"booleans": []bool{true, true, false},
   512  			"dates": []string{
   513  				"2021-06-01T22:18:59.640162Z",
   514  				"2021-06-01T22:18:59.640162Z",
   515  				"2022-06-02T22:18:59.640162Z",
   516  			},
   517  		},
   518  	}
   519  }
   520  
   521  func objectDuplicatesClass2el() *models.Object {
   522  	return &models.Object{
   523  		Class: duplicatesClassName,
   524  		ID:    objectDuplicatesClassID3_2el,
   525  		Properties: map[string]interface{}{
   526  			"texts":    []string{"Alpha", "Bravo"},
   527  			"numbers":  []float64{1.0, 2.0},
   528  			"ints":     []int{101, 102},
   529  			"booleans": []bool{true, false},
   530  			"dates": []string{
   531  				"2021-06-01T22:18:59.640162Z",
   532  				"2022-06-02T22:18:59.640162Z",
   533  			},
   534  		},
   535  	}
   536  }
   537  
   538  func aggregateDuplicatesClassQuery(filters, groupBy string) string {
   539  	query := `{
   540  			Aggregate {
   541  				%s
   542  				%s
   543  				{
   544  					meta{
   545  						count
   546  					}
   547  					booleans{
   548  						count
   549  						type
   550  						totalTrue
   551  						totalFalse
   552  						percentageTrue
   553  						percentageFalse
   554  					}
   555  					texts{
   556  						count
   557  						type
   558  						topOccurrences {
   559  							value
   560  							occurs
   561  						}
   562  					}
   563  					numbers{
   564  						count
   565  						type
   566  						minimum
   567  						maximum
   568  						mean
   569  						median
   570  						mode
   571  						sum
   572  					}
   573  					ints{
   574  						count
   575  						type
   576  						minimum
   577  						maximum
   578  						mean
   579  						median
   580  						mode
   581  						sum
   582  					}
   583  					dates{
   584  						count
   585  					}
   586  					%s
   587  				}
   588  			}
   589  		}`
   590  
   591  	params := ""
   592  	if filters != "" || groupBy != "" {
   593  		params = fmt.Sprintf(
   594  			`(
   595  				%s
   596  				%s
   597  			)`, filters, groupBy)
   598  	}
   599  	groupedBy := ""
   600  	if groupBy != "" {
   601  		groupedBy = `groupedBy{
   602  						value
   603  						path
   604  					}`
   605  	}
   606  
   607  	return fmt.Sprintf(query, duplicatesClassName, params, groupedBy)
   608  }
   609  
   610  type aggregateTestCase struct {
   611  	name              string
   612  	filters           string
   613  	groupedAssertions map[string][]assertFunc // map[groupedBy]assertionsForGroup
   614  }
   615  
   616  type aggregateArrayClassTestCases struct{}
   617  
   618  func (tc *aggregateArrayClassTestCases) WithoutFilters(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   619  	return aggregateTestCase{
   620  		name:              "without filters",
   621  		groupedAssertions: groupedAssertions,
   622  	}
   623  }
   624  
   625  func (tc *aggregateArrayClassTestCases) WithWhereFilter_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   626  	return aggregateTestCase{
   627  		name: "with where filter (all results)",
   628  		filters: `
   629  			where: {
   630  				operator: Like
   631  				path: ["id"]
   632  				valueText: "*"
   633  			}`,
   634  		groupedAssertions: groupedAssertions,
   635  	}
   636  }
   637  
   638  func (tc *aggregateArrayClassTestCases) WithWhereFilter_ResultsWithData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   639  	return aggregateTestCase{
   640  		name: "with where filter (results with data)",
   641  		filters: fmt.Sprintf(`
   642  			where: {
   643  				operator: Like
   644  				path: ["id"]
   645  				valueText: "%s"
   646  			}`, objectArrayClassID1_4el[:35]+"?"),
   647  		groupedAssertions: groupedAssertions,
   648  	}
   649  }
   650  
   651  func (tc *aggregateArrayClassTestCases) WithWhereFilter_ResultsWithoutData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   652  	return aggregateTestCase{
   653  		name: "with where filter (results without data)",
   654  		filters: fmt.Sprintf(`
   655  			where: {
   656  				operator: Like
   657  				path: ["id"]
   658  				valueText: "%s"
   659  			}`, objectArrayClassID5_0el[:35]+"?"),
   660  		groupedAssertions: groupedAssertions,
   661  	}
   662  }
   663  
   664  func (tc *aggregateArrayClassTestCases) WithWhereFilter_NoResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   665  	return aggregateTestCase{
   666  		name: "with where filter (no results)",
   667  		filters: fmt.Sprintf(`
   668  			where: {
   669  				operator: Like
   670  				path: ["id"]
   671  				valueText: "%s"
   672  			}`, notExistingObjectId),
   673  		groupedAssertions: groupedAssertions,
   674  	}
   675  }
   676  
   677  func (tc *aggregateArrayClassTestCases) WithNearObjectFilter_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   678  	return aggregateTestCase{
   679  		name: "with nearObject filter (all results)",
   680  		filters: fmt.Sprintf(`
   681  			nearObject: {
   682  				id: "%s"
   683  				certainty: 0.7
   684  			}`, objectArrayClassID1_4el),
   685  		groupedAssertions: groupedAssertions,
   686  	}
   687  }
   688  
   689  func (tc *aggregateArrayClassTestCases) WithNearObjectFilter_ResultsWithData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   690  	return aggregateTestCase{
   691  		name: "with nearObject filter (results with data)",
   692  		filters: fmt.Sprintf(`
   693  			nearObject: {
   694  				id: "%s"
   695  				certainty: 0.97
   696  			}`, objectArrayClassID1_4el),
   697  		groupedAssertions: groupedAssertions,
   698  	}
   699  }
   700  
   701  func (tc *aggregateArrayClassTestCases) WithNearObjectFilter_ResultsWithoutData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   702  	return aggregateTestCase{
   703  		name: "with nearObject filter (results without data)",
   704  		filters: fmt.Sprintf(`
   705  			nearObject: {
   706  				id: "%s"
   707  				certainty: 1
   708  			}`, objectArrayClassID5_0el),
   709  		groupedAssertions: groupedAssertions,
   710  	}
   711  }
   712  
   713  func (tc *aggregateArrayClassTestCases) WithWhereAndNearObjectFilters_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   714  	return aggregateTestCase{
   715  		name: "with where & nearObject filters (all results)",
   716  		filters: fmt.Sprintf(`
   717  			where: {
   718  				operator: Like
   719  				path: ["id"]
   720  				valueText: "*"
   721  			}
   722  			nearObject: {
   723  				id: "%s"
   724  				certainty: 0.7
   725  			}`, objectArrayClassID1_4el),
   726  		groupedAssertions: groupedAssertions,
   727  	}
   728  }
   729  
   730  func (tc *aggregateArrayClassTestCases) WithWhereAndNearObjectFilters_ResultsWithData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   731  	return aggregateTestCase{
   732  		name: "with where & nearObject filters (results with data)",
   733  		filters: fmt.Sprintf(`
   734  			where: {
   735  				operator: Like
   736  				path: ["id"]
   737  				valueText: "%s"
   738  			}
   739  			nearObject: {
   740  				id: "%s"
   741  				certainty: 0.97
   742  			}`, objectArrayClassID1_4el[:35]+"?", objectArrayClassID1_4el),
   743  		groupedAssertions: groupedAssertions,
   744  	}
   745  }
   746  
   747  func (tc *aggregateArrayClassTestCases) WithWhereAndNearObjectFilters_ResultsWithoutData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   748  	return aggregateTestCase{
   749  		name: "with where & nearObject filters (results without data)",
   750  		filters: fmt.Sprintf(`
   751  			where: {
   752  				operator: Like
   753  				path: ["id"]
   754  				valueText: "%s"
   755  			}
   756  			nearObject: {
   757  				id: "%s"
   758  				certainty: 1
   759  			}`, objectArrayClassID5_0el[:35]+"?", objectArrayClassID5_0el),
   760  		groupedAssertions: groupedAssertions,
   761  	}
   762  }
   763  
   764  func (tc *aggregateArrayClassTestCases) WithWhereAndNearObjectFilters_NoResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   765  	return aggregateTestCase{
   766  		name: "with where & nearObject filters (no results)",
   767  		filters: fmt.Sprintf(`
   768  			where: {
   769  				operator: Like
   770  				path: ["id"]
   771  				valueText: "%s"
   772  			}
   773  			nearObject: {
   774  				id: "%s"
   775  				certainty: 0.8
   776  			}`, notExistingObjectId, objectArrayClassID1_4el),
   777  		groupedAssertions: groupedAssertions,
   778  	}
   779  }
   780  
   781  type aggregateNoPropsClassTestCases struct{}
   782  
   783  func (tc *aggregateNoPropsClassTestCases) WithoutFilters(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   784  	return aggregateTestCase{
   785  		name:              "without filters",
   786  		groupedAssertions: groupedAssertions,
   787  	}
   788  }
   789  
   790  func (tc *aggregateNoPropsClassTestCases) WithWhereFilter_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   791  	return aggregateTestCase{
   792  		name: "with where filter (all results)",
   793  		filters: `
   794  			where: {
   795  				operator: Like
   796  				path: ["id"]
   797  				valueText: "*"
   798  			}`,
   799  		groupedAssertions: groupedAssertions,
   800  	}
   801  }
   802  
   803  func (tc *aggregateNoPropsClassTestCases) WithWhereFilter_SomeResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   804  	return aggregateTestCase{
   805  		name: "with where filter (some results)",
   806  		filters: fmt.Sprintf(`
   807  			where: {
   808  				operator: Like
   809  				path: ["id"]
   810  				valueText: "%s"
   811  			}`, objectNoPropsClassID1[:35]+"?"),
   812  		groupedAssertions: groupedAssertions,
   813  	}
   814  }
   815  
   816  func (tc *aggregateNoPropsClassTestCases) WithWhereFilter_NoResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   817  	return aggregateTestCase{
   818  		name: "with where filter (no results)",
   819  		filters: fmt.Sprintf(`
   820  			where: {
   821  				operator: Like
   822  				path: ["id"]
   823  				valueText: "%s"
   824  			}`, notExistingObjectId),
   825  		groupedAssertions: groupedAssertions,
   826  	}
   827  }
   828  
   829  func (tc *aggregateNoPropsClassTestCases) WithNearObjectFilter_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   830  	return aggregateTestCase{
   831  		name: "with nearObject filter (all results)",
   832  		filters: fmt.Sprintf(`
   833  			nearObject: {
   834  				id: "%s"
   835  				certainty: 0.1
   836  			}`, objectNoPropsClassID1),
   837  		groupedAssertions: groupedAssertions,
   838  	}
   839  }
   840  
   841  func (tc *aggregateNoPropsClassTestCases) WithWhereAndNearObjectFilters_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   842  	return aggregateTestCase{
   843  		name: "with where & nearObject filters (all results)",
   844  		filters: fmt.Sprintf(`
   845  			where: {
   846  				operator: Like
   847  				path: ["id"]
   848  				valueText: "*"
   849  			}
   850  			nearObject: {
   851  				id: "%s"
   852  				certainty: 0.1
   853  			}`, objectNoPropsClassID1),
   854  		groupedAssertions: groupedAssertions,
   855  	}
   856  }
   857  
   858  func (tc *aggregateNoPropsClassTestCases) WithWhereAndNearObjectFilters_SomeResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   859  	return aggregateTestCase{
   860  		name: "with where & nearObject filters (some results)",
   861  		filters: fmt.Sprintf(`
   862  			where: {
   863  				operator: Like
   864  				path: ["id"]
   865  				valueText: "%s"
   866  			}
   867  			nearObject: {
   868  				id: "%s"
   869  				certainty: 1
   870  			}`, objectNoPropsClassID1[:35]+"?", objectNoPropsClassID1),
   871  		groupedAssertions: groupedAssertions,
   872  	}
   873  }
   874  
   875  func (tc *aggregateNoPropsClassTestCases) WithWhereAndNearObjectFilters_NoResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   876  	return aggregateTestCase{
   877  		name: "with where & nearObject filters (no results)",
   878  		filters: fmt.Sprintf(`
   879  			where: {
   880  				operator: Like
   881  				path: ["id"]
   882  				valueText: "%s"
   883  			}
   884  			nearObject: {
   885  				id: "%s"
   886  				certainty: 0.1
   887  			}`, notExistingObjectId, objectNoPropsClassID1),
   888  		groupedAssertions: groupedAssertions,
   889  	}
   890  }
   891  
   892  type aggregateCityTestCases struct{}
   893  
   894  func (tc *aggregateCityTestCases) WithoutFilters(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   895  	return aggregateTestCase{
   896  		name:              "without filters",
   897  		groupedAssertions: groupedAssertions,
   898  	}
   899  }
   900  
   901  func (tc *aggregateCityTestCases) WithWhereFilter_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   902  	return aggregateTestCase{
   903  		name: "with where filter (all results)",
   904  		filters: `
   905  			where: {
   906  				operator: Like
   907  				path: ["id"]
   908  				valueText: "*"
   909  			}`,
   910  		groupedAssertions: groupedAssertions,
   911  	}
   912  }
   913  
   914  func (tc *aggregateCityTestCases) WithWhereFilter_ResultsWithData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   915  	return aggregateTestCase{
   916  		name: "with where filter (results with data)",
   917  		filters: `
   918  			where: {
   919  				operator: Equal,
   920  				path: ["isCapital"],
   921  				valueBoolean: true
   922  			}`,
   923  		groupedAssertions: groupedAssertions,
   924  	}
   925  }
   926  
   927  func (tc *aggregateCityTestCases) WithWhereFilter_ResultsWithoutData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   928  	return aggregateTestCase{
   929  		name: "with where filter (results without data)",
   930  		filters: fmt.Sprintf(`
   931  			where: {
   932  				operator: Like
   933  				path: ["id"]
   934  				valueText: "%s"
   935  			}`, nullisland),
   936  		groupedAssertions: groupedAssertions,
   937  	}
   938  }
   939  
   940  func (tc *aggregateCityTestCases) WithWhereFilter_NoResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   941  	return aggregateTestCase{
   942  		name: "with where filter (no results)",
   943  		filters: fmt.Sprintf(`
   944  			where: {
   945  				operator: Like
   946  				path: ["id"]
   947  				valueText: "%s"
   948  			}`, notExistingObjectId),
   949  		groupedAssertions: groupedAssertions,
   950  	}
   951  }
   952  
   953  func (tc *aggregateCityTestCases) WithNearObjectFilter_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   954  	return aggregateTestCase{
   955  		name: "with nearObject filter (all results)",
   956  		filters: fmt.Sprintf(`
   957  			nearObject: {
   958  				id: "%s"
   959  				certainty: 0.1
   960  			}`, berlin),
   961  		groupedAssertions: groupedAssertions,
   962  	}
   963  }
   964  
   965  func (tc *aggregateCityTestCases) WithNearObjectFilter_ResultsWithData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   966  	return aggregateTestCase{
   967  		name: "with nearObject filter (results with data)",
   968  		filters: fmt.Sprintf(`
   969  			nearObject: {
   970  				id: "%s"
   971  				certainty: 0.81
   972  			}`, berlin),
   973  		groupedAssertions: groupedAssertions,
   974  	}
   975  }
   976  
   977  func (tc *aggregateCityTestCases) WithNearObjectFilter_ResultsWithoutData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   978  	return aggregateTestCase{
   979  		name: "with nearObject filter (results without data)",
   980  		filters: fmt.Sprintf(`
   981  			nearObject: {
   982  				id: "%s"
   983  				certainty: 0.9
   984  			}`, nullisland),
   985  		groupedAssertions: groupedAssertions,
   986  	}
   987  }
   988  
   989  func (tc *aggregateCityTestCases) WithWhereAndNearObjectFilters_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
   990  	return aggregateTestCase{
   991  		name: "with where & nearObject filters (all results)",
   992  		filters: fmt.Sprintf(`
   993  			where: {
   994  				operator: Like
   995  				path: ["id"]
   996  				valueText: "*"
   997  			}
   998  			nearObject: {
   999  				id: "%s"
  1000  				certainty: 0.1
  1001  			}`, berlin),
  1002  		groupedAssertions: groupedAssertions,
  1003  	}
  1004  }
  1005  
  1006  func (tc *aggregateCityTestCases) WithWhereAndNearObjectFilters_ResultsWithData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
  1007  	return aggregateTestCase{
  1008  		name: "with where & nearObject filters (results with data)",
  1009  		filters: fmt.Sprintf(`
  1010  			where: {
  1011  				operator: Equal,
  1012  				path: ["isCapital"],
  1013  				valueBoolean: true
  1014  			}
  1015  			nearObject: {
  1016  				id: "%s"
  1017  				certainty: 0.81
  1018  			}`, berlin),
  1019  		groupedAssertions: groupedAssertions,
  1020  	}
  1021  }
  1022  
  1023  func (tc *aggregateCityTestCases) WithWhereAndNearObjectFilters_ResultsWithoutData(groupedAssertions map[string][]assertFunc) aggregateTestCase {
  1024  	return aggregateTestCase{
  1025  		name: "with where & nearObject filters (results without data)",
  1026  		filters: fmt.Sprintf(`
  1027  			where: {
  1028  				operator: Like
  1029  				path: ["id"]
  1030  				valueText: "%s"
  1031  			}
  1032  			nearObject: {
  1033  				id: "%s"
  1034  				certainty: 0.9
  1035  			}`, nullisland, nullisland),
  1036  		groupedAssertions: groupedAssertions,
  1037  	}
  1038  }
  1039  
  1040  func (tc *aggregateCityTestCases) WithWhereAndNearObjectFilters_NoResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
  1041  	return aggregateTestCase{
  1042  		name: "with where & nearObject filters (no results)",
  1043  		filters: fmt.Sprintf(`
  1044  			where: {
  1045  				operator: Like
  1046  				path: ["id"]
  1047  				valueText: "%s"
  1048  			}
  1049  			nearObject: {
  1050  				id: "%s"
  1051  				certainty: 0.1
  1052  			}`, notExistingObjectId, berlin),
  1053  		groupedAssertions: groupedAssertions,
  1054  	}
  1055  }
  1056  
  1057  type aggregateDuplicatesClassTestCases struct{}
  1058  
  1059  func (tc *aggregateDuplicatesClassTestCases) WithoutFilters(groupedAssertions map[string][]assertFunc) aggregateTestCase {
  1060  	return aggregateTestCase{
  1061  		name:              "without filters",
  1062  		groupedAssertions: groupedAssertions,
  1063  	}
  1064  }
  1065  
  1066  func (tc *aggregateDuplicatesClassTestCases) WithWhereFilter_AllResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
  1067  	return aggregateTestCase{
  1068  		name: "with where filter (all results)",
  1069  		filters: `
  1070  			where: {
  1071  				operator: Like
  1072  				path: ["id"]
  1073  				valueText: "*"
  1074  			}`,
  1075  		groupedAssertions: groupedAssertions,
  1076  	}
  1077  }
  1078  
  1079  func (tc *aggregateDuplicatesClassTestCases) WithWhereFilter_SomeResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
  1080  	return aggregateTestCase{
  1081  		name: "with where filter (some results)",
  1082  		filters: fmt.Sprintf(`
  1083  			where: {
  1084  				operator: Like
  1085  				path: ["id"]
  1086  				valueText: "%s"
  1087  			}`, objectDuplicatesClassID1_4el),
  1088  		groupedAssertions: groupedAssertions,
  1089  	}
  1090  }
  1091  
  1092  func (tc *aggregateDuplicatesClassTestCases) WithWhereFilter_NoResults(groupedAssertions map[string][]assertFunc) aggregateTestCase {
  1093  	return aggregateTestCase{
  1094  		name: "with where filter (no results)",
  1095  		filters: fmt.Sprintf(`
  1096  			where: {
  1097  				operator: Like
  1098  				path: ["id"]
  1099  				valueText: "%s"
  1100  			}`, notExistingObjectId),
  1101  		groupedAssertions: groupedAssertions,
  1102  	}
  1103  }