github.com/weaviate/weaviate@v1.24.6/adapters/handlers/graphql/local/aggregate/resolver_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 aggregate 13 14 import ( 15 "testing" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/weaviate/weaviate/entities/aggregation" 19 "github.com/weaviate/weaviate/entities/filters" 20 "github.com/weaviate/weaviate/entities/schema" 21 "github.com/weaviate/weaviate/entities/searchparams" 22 "github.com/weaviate/weaviate/usecases/config" 23 ) 24 25 type testCase struct { 26 name string 27 query string 28 expectedProps []aggregation.ParamProperty 29 resolverReturn interface{} 30 expectedResults []result 31 expectedGroupBy *filters.Path 32 expectedWhereFilter *filters.LocalFilter 33 expectedNearObjectFilter *searchparams.NearObject 34 expectedNearVectorFilter *searchparams.NearVector 35 expectedIncludeMetaCount bool 36 expectedLimit *int 37 expectedObjectLimit *int 38 } 39 40 type testCases []testCase 41 42 type result struct { 43 pathToField []string 44 expectedValue interface{} 45 } 46 47 func groupCarByMadeByManufacturerName() *filters.Path { 48 return &filters.Path{ 49 Class: schema.ClassName("Car"), 50 Property: schema.PropertyName("madeBy"), 51 Child: &filters.Path{ 52 Class: schema.ClassName("Manufacturer"), 53 Property: schema.PropertyName("name"), 54 }, 55 } 56 } 57 58 func Test_Resolve(t *testing.T) { 59 t.Parallel() 60 61 tests := testCases{ 62 testCase{ 63 name: "for gh-758 (multiple operands)", 64 query: ` 65 { 66 Aggregate { 67 Car(where:{ 68 operator:Or 69 operands:[{ 70 valueText:"Fast", 71 operator:Equal, 72 path:["modelName"] 73 }, { 74 valueText:"Slow", 75 operator:Equal, 76 path:["modelName"] 77 }] 78 }) { 79 __typename 80 modelName { 81 __typename 82 count 83 } 84 } 85 } 86 }`, 87 expectedProps: []aggregation.ParamProperty{ 88 { 89 Name: "modelName", 90 Aggregators: []aggregation.Aggregator{aggregation.CountAggregator}, 91 }, 92 }, 93 resolverReturn: []aggregation.Group{ 94 { 95 Properties: map[string]aggregation.Property{ 96 "modelName": { 97 Type: aggregation.PropertyTypeText, 98 TextAggregation: aggregation.Text{ 99 Count: 20, 100 }, 101 }, 102 }, 103 }, 104 }, 105 expectedWhereFilter: &filters.LocalFilter{ 106 Root: &filters.Clause{ 107 Operator: filters.OperatorOr, 108 Operands: []filters.Clause{ 109 { 110 Operator: filters.OperatorEqual, 111 On: &filters.Path{ 112 Class: schema.ClassName("Car"), 113 Property: schema.PropertyName("modelName"), 114 }, 115 Value: &filters.Value{ 116 Value: "Fast", 117 Type: schema.DataTypeText, 118 }, 119 }, 120 { 121 Operator: filters.OperatorEqual, 122 On: &filters.Path{ 123 Class: schema.ClassName("Car"), 124 Property: schema.PropertyName("modelName"), 125 }, 126 Value: &filters.Value{ 127 Value: "Slow", 128 Type: schema.DataTypeText, 129 }, 130 }, 131 }, 132 }, 133 }, 134 135 expectedGroupBy: nil, 136 expectedResults: []result{{ 137 pathToField: []string{"Aggregate", "Car"}, 138 expectedValue: []interface{}{ 139 map[string]interface{}{ 140 "__typename": "AggregateCar", 141 "modelName": map[string]interface{}{ 142 "count": 20, 143 "__typename": "AggregateCarmodelNameObj", 144 }, 145 }, 146 }, 147 }}, 148 }, 149 testCase{ 150 name: "without grouping prop", 151 query: `{ Aggregate { Car { horsepower { mean } } } }`, 152 expectedProps: []aggregation.ParamProperty{ 153 { 154 Name: "horsepower", 155 Aggregators: []aggregation.Aggregator{aggregation.MeanAggregator}, 156 }, 157 }, 158 resolverReturn: []aggregation.Group{ 159 { 160 Properties: map[string]aggregation.Property{ 161 "horsepower": { 162 Type: aggregation.PropertyTypeNumerical, 163 NumericalAggregations: map[string]interface{}{ 164 "mean": 275.7773, 165 }, 166 }, 167 }, 168 }, 169 }, 170 171 expectedGroupBy: nil, 172 expectedResults: []result{{ 173 pathToField: []string{"Aggregate", "Car"}, 174 expectedValue: []interface{}{ 175 map[string]interface{}{ 176 "horsepower": map[string]interface{}{"mean": 275.7773}, 177 }, 178 }, 179 }}, 180 }, 181 testCase{ 182 name: "setting limits overall", 183 query: `{ Aggregate { Car(limit:20) { horsepower { mean } } } }`, 184 expectedProps: []aggregation.ParamProperty{ 185 { 186 Name: "horsepower", 187 Aggregators: []aggregation.Aggregator{aggregation.MeanAggregator}, 188 }, 189 }, 190 resolverReturn: []aggregation.Group{ 191 { 192 Properties: map[string]aggregation.Property{ 193 "horsepower": { 194 Type: aggregation.PropertyTypeNumerical, 195 NumericalAggregations: map[string]interface{}{ 196 "mean": 275.7773, 197 }, 198 }, 199 }, 200 }, 201 }, 202 203 expectedGroupBy: nil, 204 expectedLimit: ptInt(20), 205 expectedResults: []result{{ 206 pathToField: []string{"Aggregate", "Car"}, 207 expectedValue: []interface{}{ 208 map[string]interface{}{ 209 "horsepower": map[string]interface{}{"mean": 275.7773}, 210 }, 211 }, 212 }}, 213 }, 214 testCase{ 215 name: "with props formerly contained only in Meta", 216 query: `{ Aggregate { Car { 217 stillInProduction { type count totalTrue percentageTrue totalFalse percentageFalse } 218 modelName { type count topOccurrences { value occurs } } 219 madeBy { type pointingTo } 220 meta { count } 221 } } } `, 222 expectedIncludeMetaCount: true, 223 expectedProps: []aggregation.ParamProperty{ 224 { 225 Name: "stillInProduction", 226 Aggregators: []aggregation.Aggregator{ 227 aggregation.TypeAggregator, 228 aggregation.CountAggregator, 229 aggregation.TotalTrueAggregator, 230 aggregation.PercentageTrueAggregator, 231 aggregation.TotalFalseAggregator, 232 aggregation.PercentageFalseAggregator, 233 }, 234 }, 235 { 236 Name: "modelName", 237 Aggregators: []aggregation.Aggregator{ 238 aggregation.TypeAggregator, 239 aggregation.CountAggregator, 240 aggregation.NewTopOccurrencesAggregator(ptInt(5)), 241 }, 242 }, 243 { 244 Name: "madeBy", 245 Aggregators: []aggregation.Aggregator{ 246 aggregation.TypeAggregator, 247 aggregation.PointingToAggregator, 248 }, 249 }, 250 }, 251 resolverReturn: []aggregation.Group{ 252 { 253 Count: 10, 254 Properties: map[string]aggregation.Property{ 255 "stillInProduction": { 256 SchemaType: "boolean", 257 Type: aggregation.PropertyTypeBoolean, 258 BooleanAggregation: aggregation.Boolean{ 259 TotalTrue: 23, 260 TotalFalse: 17, 261 PercentageTrue: 60, 262 PercentageFalse: 40, 263 Count: 40, 264 }, 265 }, 266 "modelName": { 267 SchemaType: "string", 268 Type: aggregation.PropertyTypeText, 269 TextAggregation: aggregation.Text{ 270 Count: 40, 271 Items: []aggregation.TextOccurrence{ 272 { 273 Value: "fastcar", 274 Occurs: 39, 275 }, 276 { 277 Value: "slowcar", 278 Occurs: 1, 279 }, 280 }, 281 }, 282 }, 283 "madeBy": { 284 SchemaType: "cref", 285 Type: aggregation.PropertyTypeReference, 286 ReferenceAggregation: aggregation.Reference{ 287 PointingTo: []string{"Manufacturer"}, 288 }, 289 }, 290 }, 291 }, 292 }, 293 294 expectedGroupBy: nil, 295 expectedResults: []result{{ 296 pathToField: []string{"Aggregate", "Car"}, 297 expectedValue: []interface{}{ 298 map[string]interface{}{ 299 "stillInProduction": map[string]interface{}{ 300 "type": "boolean", 301 "totalTrue": 23, 302 "totalFalse": 17, 303 "percentageTrue": 60.0, 304 "percentageFalse": 40.0, 305 "count": 40, 306 }, 307 "modelName": map[string]interface{}{ 308 "count": 40, 309 "type": "string", 310 "topOccurrences": []interface{}{ 311 map[string]interface{}{ 312 "value": "fastcar", 313 "occurs": 39, 314 }, 315 map[string]interface{}{ 316 "value": "slowcar", 317 "occurs": 1, 318 }, 319 }, 320 }, 321 "madeBy": map[string]interface{}{ 322 "type": "cref", 323 "pointingTo": []interface{}{"Manufacturer"}, 324 }, 325 "meta": map[string]interface{}{ 326 "count": 10, 327 }, 328 }, 329 }, 330 }}, 331 }, 332 testCase{ 333 name: "with custom limit in topOccurrences", 334 query: `{ Aggregate { Car { 335 modelName { topOccurrences(limit: 7) { value occurs } } 336 } } } `, 337 expectedProps: []aggregation.ParamProperty{ 338 { 339 Name: "modelName", 340 Aggregators: []aggregation.Aggregator{ 341 aggregation.NewTopOccurrencesAggregator(ptInt(7)), 342 }, 343 }, 344 }, 345 resolverReturn: []aggregation.Group{ 346 { 347 Count: 10, 348 Properties: map[string]aggregation.Property{ 349 "modelName": { 350 SchemaType: "string", 351 Type: aggregation.PropertyTypeText, 352 TextAggregation: aggregation.Text{ 353 Items: []aggregation.TextOccurrence{ 354 { 355 Value: "fastcar", 356 Occurs: 39, 357 }, 358 { 359 Value: "slowcar", 360 Occurs: 1, 361 }, 362 }, 363 }, 364 }, 365 }, 366 }, 367 }, 368 369 expectedGroupBy: nil, 370 expectedResults: []result{{ 371 pathToField: []string{"Aggregate", "Car"}, 372 expectedValue: []interface{}{ 373 map[string]interface{}{ 374 "modelName": map[string]interface{}{ 375 "topOccurrences": []interface{}{ 376 map[string]interface{}{ 377 "value": "fastcar", 378 "occurs": 39, 379 }, 380 map[string]interface{}{ 381 "value": "slowcar", 382 "occurs": 1, 383 }, 384 }, 385 }, 386 }, 387 }, 388 }}, 389 }, 390 testCase{ 391 name: "single prop: mean (with type)", 392 query: `{ Aggregate { Car(groupBy:["madeBy", "Manufacturer", "name"]) { horsepower { mean type } } } }`, 393 expectedProps: []aggregation.ParamProperty{ 394 { 395 Name: "horsepower", 396 Aggregators: []aggregation.Aggregator{aggregation.MeanAggregator, aggregation.TypeAggregator}, 397 }, 398 }, 399 resolverReturn: []aggregation.Group{ 400 { 401 Properties: map[string]aggregation.Property{ 402 "horsepower": { 403 Type: aggregation.PropertyTypeNumerical, 404 SchemaType: "int", 405 NumericalAggregations: map[string]interface{}{ 406 "mean": 275.7773, 407 }, 408 }, 409 }, 410 }, 411 }, 412 413 expectedGroupBy: groupCarByMadeByManufacturerName(), 414 expectedResults: []result{{ 415 pathToField: []string{"Aggregate", "Car"}, 416 expectedValue: []interface{}{ 417 map[string]interface{}{ 418 "horsepower": map[string]interface{}{ 419 "mean": 275.7773, 420 "type": "int", 421 }, 422 }, 423 }, 424 }}, 425 }, 426 427 testCase{ 428 name: "single prop: mean with groupedBy path/value", 429 query: `{ Aggregate { Car(groupBy:["madeBy", "Manufacturer", "name"]) { horsepower { mean } groupedBy { value path } } } }`, 430 expectedProps: []aggregation.ParamProperty{ 431 { 432 Name: "horsepower", 433 Aggregators: []aggregation.Aggregator{aggregation.MeanAggregator}, 434 }, 435 }, 436 resolverReturn: []aggregation.Group{ 437 { 438 GroupedBy: &aggregation.GroupedBy{ 439 Path: []string{"madeBy", "Manufacturer", "name"}, 440 Value: "best-manufacturer", 441 }, 442 Properties: map[string]aggregation.Property{ 443 "horsepower": { 444 Type: aggregation.PropertyTypeNumerical, 445 NumericalAggregations: map[string]interface{}{ 446 "mean": 275.7773, 447 }, 448 }, 449 }, 450 }, 451 }, 452 expectedGroupBy: groupCarByMadeByManufacturerName(), 453 expectedResults: []result{{ 454 pathToField: []string{"Aggregate", "Car"}, 455 expectedValue: []interface{}{ 456 map[string]interface{}{ 457 "horsepower": map[string]interface{}{"mean": 275.7773}, 458 "groupedBy": map[string]interface{}{ 459 "path": []interface{}{"madeBy", "Manufacturer", "name"}, 460 "value": "best-manufacturer", 461 }, 462 }, 463 }, 464 }}, 465 }, 466 467 testCase{ 468 name: "single prop: mean with a where filter", 469 query: `{ 470 Aggregate { 471 Car( 472 groupBy:["madeBy", "Manufacturer", "name"] 473 where: { 474 operator: LessThan, 475 valueInt: 200, 476 path: ["horsepower"], 477 } 478 ) { 479 horsepower { 480 mean 481 } 482 } 483 } 484 }`, 485 expectedProps: []aggregation.ParamProperty{ 486 { 487 Name: "horsepower", 488 Aggregators: []aggregation.Aggregator{aggregation.MeanAggregator}, 489 }, 490 }, 491 resolverReturn: []aggregation.Group{ 492 { 493 GroupedBy: &aggregation.GroupedBy{ 494 Path: []string{"madeBy", "Manufacturer", "name"}, 495 Value: "best-manufacturer", 496 }, 497 Properties: map[string]aggregation.Property{ 498 "horsepower": { 499 Type: aggregation.PropertyTypeNumerical, 500 NumericalAggregations: map[string]interface{}{ 501 "mean": 275.7773, 502 }, 503 }, 504 }, 505 }, 506 }, 507 expectedGroupBy: groupCarByMadeByManufacturerName(), 508 expectedResults: []result{{ 509 pathToField: []string{"Aggregate", "Car"}, 510 expectedValue: []interface{}{ 511 map[string]interface{}{ 512 "horsepower": map[string]interface{}{ 513 "mean": 275.7773, 514 }, 515 }, 516 }, 517 }}, 518 expectedWhereFilter: &filters.LocalFilter{ 519 Root: &filters.Clause{ 520 On: &filters.Path{ 521 Class: schema.ClassName("Car"), 522 Property: schema.PropertyName("horsepower"), 523 }, 524 Value: &filters.Value{ 525 Value: 200, 526 Type: schema.DataTypeInt, 527 }, 528 Operator: filters.OperatorLessThan, 529 }, 530 }, 531 }, 532 533 testCase{ 534 name: "all int props", 535 query: `{ Aggregate { Car(groupBy:["madeBy", "Manufacturer", "name"]) { horsepower { mean, median, mode, maximum, minimum, count, sum } } } }`, 536 expectedProps: []aggregation.ParamProperty{ 537 { 538 Name: "horsepower", 539 Aggregators: []aggregation.Aggregator{aggregation.MeanAggregator, aggregation.MedianAggregator, aggregation.ModeAggregator, aggregation.MaximumAggregator, aggregation.MinimumAggregator, aggregation.CountAggregator, aggregation.SumAggregator}, 540 }, 541 }, 542 resolverReturn: []aggregation.Group{ 543 { 544 GroupedBy: &aggregation.GroupedBy{ 545 Path: []string{"madeBy", "Manufacturer", "name"}, 546 Value: "best-manufacturer", 547 }, 548 Properties: map[string]aggregation.Property{ 549 "horsepower": { 550 Type: aggregation.PropertyTypeNumerical, 551 NumericalAggregations: map[string]interface{}{ 552 "maximum": 610.0, 553 "minimum": 89.0, 554 "mean": 275.7, 555 "median": 289.0, 556 "mode": 115.0, 557 "count": 23, 558 "sum": 6343.0, 559 }, 560 }, 561 }, 562 }, 563 }, 564 expectedGroupBy: groupCarByMadeByManufacturerName(), 565 expectedResults: []result{ 566 { 567 pathToField: []string{"Aggregate", "Car"}, 568 expectedValue: []interface{}{ 569 map[string]interface{}{ 570 "horsepower": map[string]interface{}{ 571 "maximum": 610.0, 572 "minimum": 89.0, 573 "mean": 275.7, 574 "median": 289.0, 575 "mode": 115.0, 576 "count": 23, 577 "sum": 6343.0, 578 }, 579 }, 580 }, 581 }, 582 }, 583 }, 584 585 testCase{ 586 name: "single prop: string", 587 query: `{ Aggregate { Car(groupBy:["madeBy", "Manufacturer", "name"]) { modelName { count } } } }`, 588 expectedProps: []aggregation.ParamProperty{ 589 { 590 Name: "modelName", 591 Aggregators: []aggregation.Aggregator{aggregation.CountAggregator}, 592 }, 593 }, 594 resolverReturn: []aggregation.Group{ 595 { 596 GroupedBy: &aggregation.GroupedBy{ 597 Path: []string{"madeBy", "Manufacturer", "name"}, 598 Value: "best-manufacturer", 599 }, 600 Properties: map[string]aggregation.Property{ 601 "modelName": { 602 Type: aggregation.PropertyTypeText, 603 TextAggregation: aggregation.Text{ 604 Count: 7, 605 }, 606 }, 607 }, 608 }, 609 }, 610 expectedGroupBy: groupCarByMadeByManufacturerName(), 611 expectedResults: []result{{ 612 pathToField: []string{"Aggregate", "Car"}, 613 expectedValue: []interface{}{ 614 map[string]interface{}{ 615 "modelName": map[string]interface{}{ 616 "count": 7, 617 }, 618 }, 619 }, 620 }}, 621 }, 622 623 testCase{ 624 name: "with objectLimit + nearObject (distance)", 625 query: ` 626 { 627 Aggregate{ 628 Car( 629 objectLimit: 1 630 nearObject: { 631 id: "123" 632 distance: 0.3 633 } 634 ) { 635 modelName { 636 count 637 } 638 } 639 } 640 } 641 `, 642 expectedProps: []aggregation.ParamProperty{ 643 { 644 Name: "modelName", 645 Aggregators: []aggregation.Aggregator{aggregation.CountAggregator}, 646 }, 647 }, 648 expectedObjectLimit: ptInt(1), 649 expectedNearObjectFilter: &searchparams.NearObject{ 650 ID: "123", 651 Beacon: "", 652 Distance: 0.3, 653 WithDistance: true, 654 }, 655 resolverReturn: []aggregation.Group{ 656 { 657 Properties: map[string]aggregation.Property{ 658 "modelName": { 659 Type: aggregation.PropertyTypeText, 660 TextAggregation: aggregation.Text{ 661 Count: 7, 662 }, 663 }, 664 }, 665 }, 666 }, 667 expectedResults: []result{{ 668 pathToField: []string{"Aggregate", "Car"}, 669 expectedValue: []interface{}{ 670 map[string]interface{}{ 671 "modelName": map[string]interface{}{ 672 "count": 7, 673 }, 674 }, 675 }, 676 }}, 677 }, 678 679 testCase{ 680 name: "with objectLimit + nearObject (certainty)", 681 query: ` 682 { 683 Aggregate{ 684 Car( 685 objectLimit: 1 686 nearObject: { 687 id: "123" 688 certainty: 0.7 689 } 690 ) { 691 modelName { 692 count 693 } 694 } 695 } 696 } 697 `, 698 expectedProps: []aggregation.ParamProperty{ 699 { 700 Name: "modelName", 701 Aggregators: []aggregation.Aggregator{aggregation.CountAggregator}, 702 }, 703 }, 704 expectedObjectLimit: ptInt(1), 705 expectedNearObjectFilter: &searchparams.NearObject{ 706 ID: "123", 707 Beacon: "", 708 Certainty: 0.7, 709 }, 710 resolverReturn: []aggregation.Group{ 711 { 712 Properties: map[string]aggregation.Property{ 713 "modelName": { 714 Type: aggregation.PropertyTypeText, 715 TextAggregation: aggregation.Text{ 716 Count: 7, 717 }, 718 }, 719 }, 720 }, 721 }, 722 expectedResults: []result{{ 723 pathToField: []string{"Aggregate", "Car"}, 724 expectedValue: []interface{}{ 725 map[string]interface{}{ 726 "modelName": map[string]interface{}{ 727 "count": 7, 728 }, 729 }, 730 }, 731 }}, 732 }, 733 734 testCase{ 735 name: "with objectLimit + nearVector (distance)", 736 query: ` 737 { 738 Aggregate{ 739 Car( 740 objectLimit: 1 741 nearVector: { 742 vector: [1, 2, 3] 743 distance: 0.3 744 } 745 ) { 746 modelName { 747 count 748 } 749 } 750 } 751 } 752 `, 753 expectedProps: []aggregation.ParamProperty{ 754 { 755 Name: "modelName", 756 Aggregators: []aggregation.Aggregator{aggregation.CountAggregator}, 757 }, 758 }, 759 expectedObjectLimit: ptInt(1), 760 expectedNearVectorFilter: &searchparams.NearVector{ 761 Vector: []float32{1, 2, 3}, 762 Distance: 0.3, 763 WithDistance: true, 764 }, 765 resolverReturn: []aggregation.Group{ 766 { 767 Properties: map[string]aggregation.Property{ 768 "modelName": { 769 Type: aggregation.PropertyTypeText, 770 TextAggregation: aggregation.Text{ 771 Count: 7, 772 }, 773 }, 774 }, 775 }, 776 }, 777 expectedResults: []result{{ 778 pathToField: []string{"Aggregate", "Car"}, 779 expectedValue: []interface{}{ 780 map[string]interface{}{ 781 "modelName": map[string]interface{}{ 782 "count": 7, 783 }, 784 }, 785 }, 786 }}, 787 }, 788 789 testCase{ 790 name: "with objectLimit + nearVector (certainty)", 791 query: ` 792 { 793 Aggregate{ 794 Car( 795 objectLimit: 1 796 nearVector: { 797 vector: [1, 2, 3] 798 certainty: 0.7 799 } 800 ) { 801 modelName { 802 count 803 } 804 } 805 } 806 } 807 `, 808 expectedProps: []aggregation.ParamProperty{ 809 { 810 Name: "modelName", 811 Aggregators: []aggregation.Aggregator{aggregation.CountAggregator}, 812 }, 813 }, 814 expectedObjectLimit: ptInt(1), 815 expectedNearVectorFilter: &searchparams.NearVector{ 816 Vector: []float32{1, 2, 3}, 817 Certainty: 0.7, 818 }, 819 resolverReturn: []aggregation.Group{ 820 { 821 Properties: map[string]aggregation.Property{ 822 "modelName": { 823 Type: aggregation.PropertyTypeText, 824 TextAggregation: aggregation.Text{ 825 Count: 7, 826 }, 827 }, 828 }, 829 }, 830 }, 831 expectedResults: []result{{ 832 pathToField: []string{"Aggregate", "Car"}, 833 expectedValue: []interface{}{ 834 map[string]interface{}{ 835 "modelName": map[string]interface{}{ 836 "count": 7, 837 }, 838 }, 839 }, 840 }}, 841 }, 842 testCase{ 843 name: "[deprecated string] for gh-758 (multiple operands)", 844 query: ` 845 { 846 Aggregate { 847 Car(where:{ 848 operator:Or 849 operands:[{ 850 valueString:"Fast", 851 operator:Equal, 852 path:["modelName"] 853 }, { 854 valueString:"Slow", 855 operator:Equal, 856 path:["modelName"] 857 }] 858 }) { 859 __typename 860 modelName { 861 __typename 862 count 863 } 864 } 865 } 866 }`, 867 expectedProps: []aggregation.ParamProperty{ 868 { 869 Name: "modelName", 870 Aggregators: []aggregation.Aggregator{aggregation.CountAggregator}, 871 }, 872 }, 873 resolverReturn: []aggregation.Group{ 874 { 875 Properties: map[string]aggregation.Property{ 876 "modelName": { 877 Type: aggregation.PropertyTypeText, 878 TextAggregation: aggregation.Text{ 879 Count: 20, 880 }, 881 }, 882 }, 883 }, 884 }, 885 expectedWhereFilter: &filters.LocalFilter{ 886 Root: &filters.Clause{ 887 Operator: filters.OperatorOr, 888 Operands: []filters.Clause{ 889 { 890 Operator: filters.OperatorEqual, 891 On: &filters.Path{ 892 Class: schema.ClassName("Car"), 893 Property: schema.PropertyName("modelName"), 894 }, 895 Value: &filters.Value{ 896 Value: "Fast", 897 Type: schema.DataTypeString, 898 }, 899 }, 900 { 901 Operator: filters.OperatorEqual, 902 On: &filters.Path{ 903 Class: schema.ClassName("Car"), 904 Property: schema.PropertyName("modelName"), 905 }, 906 Value: &filters.Value{ 907 Value: "Slow", 908 Type: schema.DataTypeString, 909 }, 910 }, 911 }, 912 }, 913 }, 914 915 expectedGroupBy: nil, 916 expectedResults: []result{{ 917 pathToField: []string{"Aggregate", "Car"}, 918 expectedValue: []interface{}{ 919 map[string]interface{}{ 920 "__typename": "AggregateCar", 921 "modelName": map[string]interface{}{ 922 "count": 20, 923 "__typename": "AggregateCarmodelNameObj", 924 }, 925 }, 926 }, 927 }}, 928 }, 929 } 930 931 tests.AssertExtraction(t, "Car") 932 } 933 934 func (tests testCases) AssertExtraction(t *testing.T, className string) { 935 for _, testCase := range tests { 936 t.Run(testCase.name, func(t *testing.T) { 937 resolver := newMockResolver(config.Config{}) 938 939 expectedParams := &aggregation.Params{ 940 ClassName: schema.ClassName(className), 941 Properties: testCase.expectedProps, 942 GroupBy: testCase.expectedGroupBy, 943 Filters: testCase.expectedWhereFilter, 944 NearObject: testCase.expectedNearObjectFilter, 945 NearVector: testCase.expectedNearVectorFilter, 946 IncludeMetaCount: testCase.expectedIncludeMetaCount, 947 Limit: testCase.expectedLimit, 948 ObjectLimit: testCase.expectedObjectLimit, 949 } 950 951 resolver.On("Aggregate", expectedParams). 952 Return(testCase.resolverReturn, nil).Once() 953 954 result := resolver.AssertResolve(t, testCase.query) 955 956 for _, expectedResult := range testCase.expectedResults { 957 value := result.Get(expectedResult.pathToField...).Result 958 959 assert.Equal(t, expectedResult.expectedValue, value) 960 } 961 }) 962 } 963 } 964 965 func ptInt(in int) *int { 966 return &in 967 }