From fe668a2aaaa842a103582aa49eaac99f691e19b5 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Tue, 17 Sep 2024 16:59:21 -0700 Subject: [PATCH 1/5] add inline array filter types --- internal/connor/all.go | 105 ++++++ internal/connor/and.go | 2 +- internal/connor/any.go | 105 ++++++ internal/connor/connor.go | 6 + internal/connor/eq.go | 28 +- internal/connor/none.go | 12 + internal/planner/mapper/mapper.go | 8 +- internal/request/graphql/schema/generate.go | 14 +- internal/request/graphql/schema/manager.go | 58 +++- internal/request/graphql/schema/types/base.go | 184 ++++++++++- .../graphql/schema/types/descriptions.go | 10 + .../inline_array/with_filter_all_test.go | 305 ++++++++++++++++++ .../inline_array/with_filter_any_test.go | 305 ++++++++++++++++++ .../inline_array/with_filter_none_test.go | 305 ++++++++++++++++++ .../schema/aggregates/inline_array_test.go | 108 ++++--- 15 files changed, 1467 insertions(+), 88 deletions(-) create mode 100644 internal/connor/all.go create mode 100644 internal/connor/any.go create mode 100644 internal/connor/none.go create mode 100644 tests/integration/query/inline_array/with_filter_all_test.go create mode 100644 tests/integration/query/inline_array/with_filter_any_test.go create mode 100644 tests/integration/query/inline_array/with_filter_none_test.go diff --git a/internal/connor/all.go b/internal/connor/all.go new file mode 100644 index 0000000000..52aa0f670b --- /dev/null +++ b/internal/connor/all.go @@ -0,0 +1,105 @@ +package connor + +import ( + "github.com/sourcenetwork/defradb/client" + + "github.com/sourcenetwork/immutable" +) + +// all is an operator which allows the evaluation of +// a number of conditions over a list of values +// matching if all of them match. +func all(condition, data any) (bool, error) { + switch t := data.(type) { + case []string: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + + case []immutable.Option[string]: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + + case []int64: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + + case []immutable.Option[int64]: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + + case []bool: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + + case []immutable.Option[bool]: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + + case []float64: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + + case []immutable.Option[float64]: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + + default: + return false, client.NewErrUnhandledType("data", data) + } +} diff --git a/internal/connor/and.go b/internal/connor/and.go index 054718ee6a..be2e097309 100644 --- a/internal/connor/and.go +++ b/internal/connor/and.go @@ -14,8 +14,8 @@ func and(condition, data any) (bool, error) { return false, nil } } - return true, nil + default: return false, client.NewErrUnhandledType("condition", cn) } diff --git a/internal/connor/any.go b/internal/connor/any.go new file mode 100644 index 0000000000..78dfc4934f --- /dev/null +++ b/internal/connor/any.go @@ -0,0 +1,105 @@ +package connor + +import ( + "github.com/sourcenetwork/defradb/client" + + "github.com/sourcenetwork/immutable" +) + +// anyOp is an operator which allows the evaluation of +// a number of conditions over a list of values +// matching if any of them match. +func anyOp(condition, data any) (bool, error) { + switch t := data.(type) { + case []string: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil + + case []immutable.Option[string]: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil + + case []int64: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil + + case []immutable.Option[int64]: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil + + case []bool: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil + + case []immutable.Option[bool]: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil + + case []float64: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil + + case []immutable.Option[float64]: + for _, c := range t { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil + + default: + return false, client.NewErrUnhandledType("data", data) + } +} diff --git a/internal/connor/connor.go b/internal/connor/connor.go index 927b1dfffd..086ba0cd49 100644 --- a/internal/connor/connor.go +++ b/internal/connor/connor.go @@ -18,6 +18,10 @@ func matchWith(op string, conditions, data any) (bool, error) { switch op { case "_and": return and(conditions, data) + case "_any": + return anyOp(conditions, data) + case "_all": + return all(conditions, data) case "_eq": return eq(conditions, data) case "_ge": @@ -44,6 +48,8 @@ func matchWith(op string, conditions, data any) (bool, error) { return ilike(conditions, data) case "_nilike": return nilike(conditions, data) + case "_none": + return none(conditions, data) case "_not": return not(conditions, data) default: diff --git a/internal/connor/eq.go b/internal/connor/eq.go index 86888eef37..343bc44bc1 100644 --- a/internal/connor/eq.go +++ b/internal/connor/eq.go @@ -29,28 +29,32 @@ func eq(condition, data any) (bool, error) { return false, nil case immutable.Option[bool]: - if !arr.HasValue() { - return condition == nil, nil + if arr.HasValue() { + data = arr.Value() + } else { + data = nil } - data = arr.Value() case immutable.Option[int64]: - if !arr.HasValue() { - return condition == nil, nil + if arr.HasValue() { + data = arr.Value() + } else { + data = nil } - data = arr.Value() case immutable.Option[float64]: - if !arr.HasValue() { - return condition == nil, nil + if arr.HasValue() { + data = arr.Value() + } else { + data = nil } - data = arr.Value() case immutable.Option[string]: - if !arr.HasValue() { - return condition == nil, nil + if arr.HasValue() { + data = arr.Value() + } else { + data = nil } - data = arr.Value() } switch cn := condition.(type) { diff --git a/internal/connor/none.go b/internal/connor/none.go new file mode 100644 index 0000000000..16613b3e46 --- /dev/null +++ b/internal/connor/none.go @@ -0,0 +1,12 @@ +package connor + +// none is an operator which allows the evaluation of +// a number of conditions over a list of values +// matching if all of them do not match. +func none(condition, data any) (bool, error) { + m, err := anyOp(condition, data) + if err != nil { + return false, err + } + return !m, nil +} diff --git a/internal/planner/mapper/mapper.go b/internal/planner/mapper/mapper.go index 706f9235de..ac6bb80c78 100644 --- a/internal/planner/mapper/mapper.go +++ b/internal/planner/mapper/mapper.go @@ -1348,13 +1348,15 @@ func toFilterMap( returnClause := map[connor.FilterKey]any{} for innerSourceKey, innerSourceValue := range typedClause { var innerMapping *core.DocumentMapping - switch innerSourceValue.(type) { - case map[string]any: + // innerSourceValue may refer to a child mapping or + // an inline array if we don't have a child mapping + _, ok := innerSourceValue.(map[string]any) + if ok && index < len(mapping.ChildMappings) { // If the innerSourceValue is also a map, then we should parse the nested clause // using the child mapping, as this key must refer to a host property in a join // and deeper keys must refer to properties on the child items. innerMapping = mapping.ChildMappings[index] - default: + } else { innerMapping = mapping } rKey, rValue := toFilterMap(innerSourceKey, innerSourceValue, innerMapping) diff --git a/internal/request/graphql/schema/generate.go b/internal/request/graphql/schema/generate.go index 8ae36d230f..16edf25bca 100644 --- a/internal/request/graphql/schema/generate.go +++ b/internal/request/graphql/schema/generate.go @@ -1151,11 +1151,17 @@ func (g *Generator) genTypeFilterArgInput(obj *gql.Object) *gql.InputObject { } // scalars (leafs) if gql.IsLeafType(field.Type) { - if _, isList := field.Type.(*gql.List); isList { - // Filtering by inline array value is currently not supported - continue + var operatorName string + if list, isList := field.Type.(*gql.List); isList { + if notNull, isNotNull := list.OfType.(*gql.NonNull); isNotNull { + operatorName = "NotNull" + notNull.OfType.Name() + "ListOperatorBlock" + } else { + operatorName = list.OfType.Name() + "ListOperatorBlock" + } + } else { + operatorName = field.Type.Name() + "OperatorBlock" } - operatorType, isFilterable := g.manager.schema.TypeMap()[field.Type.Name()+"OperatorBlock"] + operatorType, isFilterable := g.manager.schema.TypeMap()[operatorName] if !isFilterable { continue } diff --git a/internal/request/graphql/schema/manager.go b/internal/request/graphql/schema/manager.go index 0385c50ac9..792535fda0 100644 --- a/internal/request/graphql/schema/manager.go +++ b/internal/request/graphql/schema/manager.go @@ -188,6 +188,22 @@ func defaultTypes( blobScalarType := schemaTypes.BlobScalarType() jsonScalarType := schemaTypes.JSONScalarType() + idOpBlock := schemaTypes.IDOperatorBlock() + intOpBlock := schemaTypes.IntOperatorBlock() + floatOpBlock := schemaTypes.FloatOperatorBlock() + booleanOpBlock := schemaTypes.BooleanOperatorBlock() + stringOpBlock := schemaTypes.StringOperatorBlock() + jsonOpBlock := schemaTypes.JSONOperatorBlock(jsonScalarType) + blobOpBlock := schemaTypes.BlobOperatorBlock(blobScalarType) + dateTimeOpBlock := schemaTypes.DateTimeOperatorBlock() + + notNullIntOpBlock := schemaTypes.NotNullIntOperatorBlock() + notNullFloatOpBlock := schemaTypes.NotNullFloatOperatorBlock() + notNullBooleanOpBlock := schemaTypes.NotNullBooleanOperatorBlock() + notNullStringOpBlock := schemaTypes.NotNullStringOperatorBlock() + notNullJSONOpBlock := schemaTypes.NotNullJSONOperatorBlock(jsonScalarType) + notNullBlobOpBlock := schemaTypes.NotNullBlobOperatorBlock(blobScalarType) + return []gql.Type{ // Base Scalar types gql.Boolean, @@ -207,20 +223,34 @@ func defaultTypes( orderEnum, // Filter scalar blocks - schemaTypes.BooleanOperatorBlock(), - schemaTypes.NotNullBooleanOperatorBlock(), - schemaTypes.DateTimeOperatorBlock(), - schemaTypes.FloatOperatorBlock(), - schemaTypes.NotNullFloatOperatorBlock(), - schemaTypes.IdOperatorBlock(), - schemaTypes.IntOperatorBlock(), - schemaTypes.NotNullIntOperatorBlock(), - schemaTypes.StringOperatorBlock(), - schemaTypes.NotNullstringOperatorBlock(), - schemaTypes.JSONOperatorBlock(jsonScalarType), - schemaTypes.NotNullJSONOperatorBlock(jsonScalarType), - schemaTypes.BlobOperatorBlock(blobScalarType), - schemaTypes.NotNullBlobOperatorBlock(blobScalarType), + idOpBlock, + intOpBlock, + floatOpBlock, + booleanOpBlock, + stringOpBlock, + jsonOpBlock, + blobOpBlock, + dateTimeOpBlock, + + // Filter non null scalar blocks + notNullIntOpBlock, + notNullFloatOpBlock, + notNullBooleanOpBlock, + notNullStringOpBlock, + notNullJSONOpBlock, + notNullBlobOpBlock, + + // Filter scalar list blocks + schemaTypes.IntListOperatorBlock(intOpBlock), + schemaTypes.FloatListOperatorBlock(floatOpBlock), + schemaTypes.BooleanListOperatorBlock(booleanOpBlock), + schemaTypes.StringListOperatorBlock(stringOpBlock), + + // Filter non null scalar list blocks + schemaTypes.NotNullIntListOperatorBlock(notNullIntOpBlock), + schemaTypes.NotNullFloatListOperatorBlock(notNullFloatOpBlock), + schemaTypes.NotNullBooleanListOperatorBlock(notNullBooleanOpBlock), + schemaTypes.NotNullStringListOperatorBlock(notNullStringOpBlock), commitsOrderArg, commitLinkObject, diff --git a/internal/request/graphql/schema/types/base.go b/internal/request/graphql/schema/types/base.go index fd49fbb45a..4675169989 100644 --- a/internal/request/graphql/schema/types/base.go +++ b/internal/request/graphql/schema/types/base.go @@ -40,6 +40,28 @@ func BooleanOperatorBlock() *gql.InputObject { }) } +// BooleanListOperatorBlock filter block for [Boolean] types. +func BooleanListOperatorBlock(op *gql.InputObject) *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "BooleanListOperatorBlock", + Description: "These are the set of filter operators available for use when filtering on [Boolean] values.", + Fields: gql.InputObjectConfigFieldMap{ + "_any": &gql.InputObjectFieldConfig{ + Description: anyOperatorDescription, + Type: op, + }, + "_all": &gql.InputObjectFieldConfig{ + Description: allOperatorDescription, + Type: op, + }, + "_none": &gql.InputObjectFieldConfig{ + Description: noneOperatorDescription, + Type: op, + }, + }, + }) +} + // NotNullBooleanOperatorBlock filter block for boolean! types. func NotNullBooleanOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ @@ -66,6 +88,28 @@ func NotNullBooleanOperatorBlock() *gql.InputObject { }) } +// NotNullBooleanListOperatorBlock filter block for [Boolean!] types. +func NotNullBooleanListOperatorBlock(op *gql.InputObject) *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "NotNullBooleanListOperatorBlock", + Description: "These are the set of filter operators available for use when filtering on [Boolean!] values.", + Fields: gql.InputObjectConfigFieldMap{ + "_any": &gql.InputObjectFieldConfig{ + Description: anyOperatorDescription, + Type: op, + }, + "_all": &gql.InputObjectFieldConfig{ + Description: allOperatorDescription, + Type: op, + }, + "_none": &gql.InputObjectFieldConfig{ + Description: noneOperatorDescription, + Type: op, + }, + }, + }) +} + // DateTimeOperatorBlock filter block for DateTime types. func DateTimeOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ @@ -150,6 +194,28 @@ func FloatOperatorBlock() *gql.InputObject { }) } +// FloatListOperatorBlock filter block for [Float] types. +func FloatListOperatorBlock(op *gql.InputObject) *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "FloatListOperatorBlock", + Description: "These are the set of filter operators available for use when filtering on [Float] values.", + Fields: gql.InputObjectConfigFieldMap{ + "_any": &gql.InputObjectFieldConfig{ + Description: anyOperatorDescription, + Type: op, + }, + "_all": &gql.InputObjectFieldConfig{ + Description: allOperatorDescription, + Type: op, + }, + "_none": &gql.InputObjectFieldConfig{ + Description: noneOperatorDescription, + Type: op, + }, + }, + }) +} + // NotNullFloatOperatorBlock filter block for Float! types. func NotNullFloatOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ @@ -192,6 +258,28 @@ func NotNullFloatOperatorBlock() *gql.InputObject { }) } +// NotNullFloatListOperatorBlock filter block for [NotNullFloat] types. +func NotNullFloatListOperatorBlock(op *gql.InputObject) *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "NotNullFloatListOperatorBlock", + Description: "These are the set of filter operators available for use when filtering on [Float!] values.", + Fields: gql.InputObjectConfigFieldMap{ + "_any": &gql.InputObjectFieldConfig{ + Description: anyOperatorDescription, + Type: op, + }, + "_all": &gql.InputObjectFieldConfig{ + Description: allOperatorDescription, + Type: op, + }, + "_none": &gql.InputObjectFieldConfig{ + Description: noneOperatorDescription, + Type: op, + }, + }, + }) +} + // IntOperatorBlock filter block for Int types. func IntOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ @@ -234,6 +322,28 @@ func IntOperatorBlock() *gql.InputObject { }) } +// IntListOperatorBlock filter block for [Int] types. +func IntListOperatorBlock(op *gql.InputObject) *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "IntListOperatorBlock", + Description: "These are the set of filter operators available for use when filtering on [Int] values.", + Fields: gql.InputObjectConfigFieldMap{ + "_any": &gql.InputObjectFieldConfig{ + Description: anyOperatorDescription, + Type: op, + }, + "_all": &gql.InputObjectFieldConfig{ + Description: allOperatorDescription, + Type: op, + }, + "_none": &gql.InputObjectFieldConfig{ + Description: noneOperatorDescription, + Type: op, + }, + }, + }) +} + // NotNullIntOperatorBlock filter block for Int! types. func NotNullIntOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ @@ -276,6 +386,28 @@ func NotNullIntOperatorBlock() *gql.InputObject { }) } +// NotNullIntListOperatorBlock filter block for [NotNullInt] types. +func NotNullIntListOperatorBlock(op *gql.InputObject) *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "NotNullIntListOperatorBlock", + Description: "These are the set of filter operators available for use when filtering on [Int!] values.", + Fields: gql.InputObjectConfigFieldMap{ + "_any": &gql.InputObjectFieldConfig{ + Description: anyOperatorDescription, + Type: op, + }, + "_all": &gql.InputObjectFieldConfig{ + Description: allOperatorDescription, + Type: op, + }, + "_none": &gql.InputObjectFieldConfig{ + Description: noneOperatorDescription, + Type: op, + }, + }, + }) +} + // StringOperatorBlock filter block for string types. func StringOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ @@ -318,8 +450,30 @@ func StringOperatorBlock() *gql.InputObject { }) } -// NotNullstringOperatorBlock filter block for string! types. -func NotNullstringOperatorBlock() *gql.InputObject { +// StringListOperatorBlock filter block for [String] types. +func StringListOperatorBlock(op *gql.InputObject) *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "StringListOperatorBlock", + Description: "These are the set of filter operators available for use when filtering on [String] values.", + Fields: gql.InputObjectConfigFieldMap{ + "_any": &gql.InputObjectFieldConfig{ + Description: anyOperatorDescription, + Type: op, + }, + "_all": &gql.InputObjectFieldConfig{ + Description: allOperatorDescription, + Type: op, + }, + "_none": &gql.InputObjectFieldConfig{ + Description: noneOperatorDescription, + Type: op, + }, + }, + }) +} + +// NotNullStringOperatorBlock filter block for string! types. +func NotNullStringOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ Name: "NotNullStringOperatorBlock", Description: notNullStringOperatorBlockDescription, @@ -360,6 +514,28 @@ func NotNullstringOperatorBlock() *gql.InputObject { }) } +// NotNullStringListOperatorBlock filter block for [String!] types. +func NotNullStringListOperatorBlock(op *gql.InputObject) *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "NotNullStringListOperatorBlock", + Description: "These are the set of filter operators available for use when filtering on [String!] values.", + Fields: gql.InputObjectConfigFieldMap{ + "_any": &gql.InputObjectFieldConfig{ + Description: anyOperatorDescription, + Type: op, + }, + "_all": &gql.InputObjectFieldConfig{ + Description: allOperatorDescription, + Type: op, + }, + "_none": &gql.InputObjectFieldConfig{ + Description: noneOperatorDescription, + Type: op, + }, + }, + }) +} + // JSONOperatorBlock filter block for string types. func JSONOperatorBlock(jsonScalarType *gql.Scalar) *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ @@ -527,8 +703,8 @@ func NotNullBlobOperatorBlock(blobScalarType *gql.Scalar) *gql.InputObject { }) } -// IdOperatorBlock filter block for ID types. -func IdOperatorBlock() *gql.InputObject { +// IDOperatorBlock filter block for ID types. +func IDOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ Name: "IDOperatorBlock", Description: idOperatorBlockDescription, diff --git a/internal/request/graphql/schema/types/descriptions.go b/internal/request/graphql/schema/types/descriptions.go index 27cd3a6f74..213266d891 100644 --- a/internal/request/graphql/schema/types/descriptions.go +++ b/internal/request/graphql/schema/types/descriptions.go @@ -222,6 +222,16 @@ The or operator - only one check within this clause must pass in order for this NotOperatorDescription string = ` The negative operator - this check will only pass if all checks within it fail. ` + anyOperatorDescription string = ` +The any operator - only one check within this clause must pass on each item in order for this check to pass. +` + allOperatorDescription string = ` +The all operator - all checks within this clause must pass on each item in order for this check to pass. +` + noneOperatorDescription string = ` +The none operator - only one check within this clause must fail on one item in order for this check to pass. +` + ascOrderDescription string = ` Sort the results in ascending order, e.g. null,1,2,3,a,b,c. ` diff --git a/tests/integration/query/inline_array/with_filter_all_test.go b/tests/integration/query/inline_array/with_filter_all_test.go new file mode 100644 index 0000000000..bad0377188 --- /dev/null +++ b/tests/integration/query/inline_array/with_filter_all_test.go @@ -0,0 +1,305 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package inline_array + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQueryInlineStringArrayWithAllFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered all of string array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageHeaders": ["first", "second"] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageHeaders": [null, "second"] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageHeaders: {_all: {_ne: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullStringArrayWithAllFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered all of non null string array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "preferredStrings": ["first", "second"] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "preferredStrings": ["", "second"] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {preferredStrings: {_all: {_ne: ""}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineIntArrayWithAllFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered all of int array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "testScores": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "testScores": [null, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {testScores: {_all: {_ne: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullIntArrayWithAllFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered all of non null int array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "testScores": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "testScores": [0, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {testScores: {_all: {_lt: 70}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineFloatArrayWithAllFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered all of float array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageRatings": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageRatings": [null, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageRatings: {_all: {_ne: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullFloatArrayWithAllFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered all of non null float array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageRatings": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageRatings": [0, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageRatings: {_all: {_lt: 70}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineBooleanArrayWithAllFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered all of boolean array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "indexLikesDislikes": [false, false] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "indexLikesDislikes": [null, true] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {indexLikesDislikes: {_all: {_ne: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullBooleanArrayWithAllFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered all of non null boolean array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "likedIndexes": [false, false] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "likedIndexes": [true, true] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {likedIndexes: {_all: {_eq: true}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} diff --git a/tests/integration/query/inline_array/with_filter_any_test.go b/tests/integration/query/inline_array/with_filter_any_test.go new file mode 100644 index 0000000000..8b4bfcde0d --- /dev/null +++ b/tests/integration/query/inline_array/with_filter_any_test.go @@ -0,0 +1,305 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package inline_array + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQueryInlineStringArrayWithAnyFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered any of string array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageHeaders": ["first", "second"] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageHeaders": [null, "second"] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageHeaders: {_any: {_eq: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullStringArrayWithAnyFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered any of non null string array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "preferredStrings": ["first", "second"] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "preferredStrings": ["", "second"] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {preferredStrings: {_any: {_eq: ""}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineIntArrayWithAnyFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered any of int array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "testScores": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "testScores": [null, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {testScores: {_any: {_eq: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullIntArrayWithAnyFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered any of non null int array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "testScores": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "testScores": [0, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {testScores: {_any: {_gt: 70}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineFloatArrayWithAnyFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered any of float array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageRatings": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageRatings": [null, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageRatings: {_any: {_eq: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullFloatArrayWithAnyFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered any of non null float array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageRatings": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageRatings": [0, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageRatings: {_any: {_gt: 70}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineBooleanArrayWithAnyFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered any of boolean array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "indexLikesDislikes": [false, false] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "indexLikesDislikes": [null, true] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {indexLikesDislikes: {_any: {_eq: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullBooleanArrayWithAnyFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered any of non null boolean array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "likedIndexes": [false, false] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "likedIndexes": [true, true] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {likedIndexes: {_any: {_eq: true}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} diff --git a/tests/integration/query/inline_array/with_filter_none_test.go b/tests/integration/query/inline_array/with_filter_none_test.go new file mode 100644 index 0000000000..0dcb45b4f7 --- /dev/null +++ b/tests/integration/query/inline_array/with_filter_none_test.go @@ -0,0 +1,305 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package inline_array + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQueryInlineStringArrayWithNoneFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered none of string array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageHeaders": ["first", "second"] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageHeaders": [null, "second"] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageHeaders: {_none: {_eq: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullStringArrayWithNoneFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered none of non null string array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "preferredStrings": ["first", "second"] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "preferredStrings": ["", "second"] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {preferredStrings: {_none: {_eq: ""}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineIntArrayWithNoneFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered none of int array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "testScores": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "testScores": [null, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {testScores: {_none: {_eq: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullIntArrayWithNoneFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered none of non null int array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "testScores": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "testScores": [0, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {testScores: {_none: {_gt: 70}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineFloatArrayWithNoneFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered none of float array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageRatings": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageRatings": [null, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageRatings: {_none: {_eq: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullFloatArrayWithNoneFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered none of non null float array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "pageRatings": [50, 80] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "pageRatings": [0, 60] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {pageRatings: {_none: {_gt: 70}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineBooleanArrayWithNoneFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered none of boolean array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "indexLikesDislikes": [false, false] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "indexLikesDislikes": [null, true] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {indexLikesDislikes: {_none: {_eq: null}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Shahzad", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} + +func TestQueryInlineNonNullBooleanArrayWithNoneFilter(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple inline array, filtered none of non null boolean array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "name": "Shahzad", + "likedIndexes": [false, false] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred", + "likedIndexes": [true, true] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {likedIndexes: {_none: {_ne: true}}}) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} diff --git a/tests/integration/schema/aggregates/inline_array_test.go b/tests/integration/schema/aggregates/inline_array_test.go index 1dfaa4a858..a7fa6518fa 100644 --- a/tests/integration/schema/aggregates/inline_array_test.go +++ b/tests/integration/schema/aggregates/inline_array_test.go @@ -388,59 +388,67 @@ func TestSchemaAggregateInlineArrayCreatesUsersAverage(t *testing.T) { } */ -var aggregateGroupArg = map[string]any{ - "name": "_group", - "type": map[string]any{ - "name": "Users__CountSelector", - "inputFields": []any{ - map[string]any{ - "name": "filter", - "type": map[string]any{ - "name": "UsersFilterArg", - "inputFields": []any{ - map[string]any{ - "name": "_and", - "type": map[string]any{ - "name": nil, +func aggregateGroupArg(fieldType string) map[string]any { + return map[string]any{ + "name": "_group", + "type": map[string]any{ + "name": "Users__CountSelector", + "inputFields": []any{ + map[string]any{ + "name": "filter", + "type": map[string]any{ + "name": "UsersFilterArg", + "inputFields": []any{ + map[string]any{ + "name": "Favourites", + "type": map[string]any{ + "name": fieldType + "ListOperatorBlock", + }, }, - }, - map[string]any{ - "name": "_docID", - "type": map[string]any{ - "name": "IDOperatorBlock", + map[string]any{ + "name": "_and", + "type": map[string]any{ + "name": nil, + }, }, - }, - map[string]any{ - "name": "_not", - "type": map[string]any{ - "name": "UsersFilterArg", + map[string]any{ + "name": "_docID", + "type": map[string]any{ + "name": "IDOperatorBlock", + }, }, - }, - map[string]any{ - "name": "_or", - "type": map[string]any{ - "name": nil, + map[string]any{ + "name": "_not", + "type": map[string]any{ + "name": "UsersFilterArg", + }, + }, + map[string]any{ + "name": "_or", + "type": map[string]any{ + "name": nil, + }, }, }, }, }, - }, - map[string]any{ - "name": "limit", - "type": map[string]any{ - "name": "Int", - "inputFields": nil, + map[string]any{ + "name": "limit", + "type": map[string]any{ + "name": "Int", + "inputFields": nil, + }, }, - }, - map[string]any{ - "name": "offset", - "type": map[string]any{ - "name": "Int", - "inputFields": nil, + map[string]any{ + "name": "offset", + "type": map[string]any{ + "name": "Int", + "inputFields": nil, + }, }, }, }, - }, + } } var aggregateVersionArg = map[string]any{ @@ -578,7 +586,7 @@ func TestSchemaAggregateInlineArrayCreatesUsersNillableBooleanCountFilter(t *tes }, }, }, - aggregateGroupArg, + aggregateGroupArg("Boolean"), aggregateVersionArg, }, }, @@ -704,7 +712,7 @@ func TestSchemaAggregateInlineArrayCreatesUsersBooleanCountFilter(t *testing.T) }, }, }, - aggregateGroupArg, + aggregateGroupArg("NotNullBoolean"), aggregateVersionArg, }, }, @@ -854,7 +862,7 @@ func TestSchemaAggregateInlineArrayCreatesUsersNillableIntegerCountFilter(t *tes }, }, }, - aggregateGroupArg, + aggregateGroupArg("Int"), aggregateVersionArg, }, }, @@ -1004,7 +1012,7 @@ func TestSchemaAggregateInlineArrayCreatesUsersIntegerCountFilter(t *testing.T) }, }, }, - aggregateGroupArg, + aggregateGroupArg("NotNullInt"), aggregateVersionArg, }, }, @@ -1154,7 +1162,7 @@ func TestSchemaAggregateInlineArrayCreatesUsersNillableFloatCountFilter(t *testi }, }, }, - aggregateGroupArg, + aggregateGroupArg("Float"), aggregateVersionArg, }, }, @@ -1304,7 +1312,7 @@ func TestSchemaAggregateInlineArrayCreatesUsersFloatCountFilter(t *testing.T) { }, }, }, - aggregateGroupArg, + aggregateGroupArg("NotNullFloat"), aggregateVersionArg, }, }, @@ -1454,7 +1462,7 @@ func TestSchemaAggregateInlineArrayCreatesUsersNillableStringCountFilter(t *test }, }, }, - aggregateGroupArg, + aggregateGroupArg("String"), aggregateVersionArg, }, }, @@ -1604,7 +1612,7 @@ func TestSchemaAggregateInlineArrayCreatesUsersStringCountFilter(t *testing.T) { }, }, }, - aggregateGroupArg, + aggregateGroupArg("NotNullString"), aggregateVersionArg, }, }, From 9c1b05965827a469d51de8d62e8ed9e9a561c90b Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Wed, 18 Sep 2024 10:37:09 -0700 Subject: [PATCH 2/5] simplify with generics --- internal/connor/all.go | 92 +++++++++--------------------------------- internal/connor/any.go | 92 +++++++++--------------------------------- internal/connor/eq.go | 73 +++++++++++++-------------------- 3 files changed, 67 insertions(+), 190 deletions(-) diff --git a/internal/connor/all.go b/internal/connor/all.go index 52aa0f670b..0b9800de89 100644 --- a/internal/connor/all.go +++ b/internal/connor/all.go @@ -12,94 +12,42 @@ import ( func all(condition, data any) (bool, error) { switch t := data.(type) { case []string: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if !m { - return false, nil - } - } - return true, nil + return allSlice(condition, t) case []immutable.Option[string]: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if !m { - return false, nil - } - } - return true, nil + return allSlice(condition, t) case []int64: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if !m { - return false, nil - } - } - return true, nil + return allSlice(condition, t) case []immutable.Option[int64]: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if !m { - return false, nil - } - } - return true, nil + return allSlice(condition, t) case []bool: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if !m { - return false, nil - } - } - return true, nil + return allSlice(condition, t) case []immutable.Option[bool]: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if !m { - return false, nil - } - } - return true, nil + return allSlice(condition, t) case []float64: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if !m { - return false, nil - } - } - return true, nil + return allSlice(condition, t) case []immutable.Option[float64]: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if !m { - return false, nil - } - } - return true, nil + return allSlice(condition, t) default: return false, client.NewErrUnhandledType("data", data) } } + +func allSlice[T any](condition any, data []T) (bool, error) { + for _, c := range data { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil +} diff --git a/internal/connor/any.go b/internal/connor/any.go index 78dfc4934f..a9c02b1369 100644 --- a/internal/connor/any.go +++ b/internal/connor/any.go @@ -12,94 +12,42 @@ import ( func anyOp(condition, data any) (bool, error) { switch t := data.(type) { case []string: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if m { - return true, nil - } - } - return false, nil + return anySlice(condition, t) case []immutable.Option[string]: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if m { - return true, nil - } - } - return false, nil + return anySlice(condition, t) case []int64: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if m { - return true, nil - } - } - return false, nil + return anySlice(condition, t) case []immutable.Option[int64]: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if m { - return true, nil - } - } - return false, nil + return anySlice(condition, t) case []bool: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if m { - return true, nil - } - } - return false, nil + return anySlice(condition, t) case []immutable.Option[bool]: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if m { - return true, nil - } - } - return false, nil + return anySlice(condition, t) case []float64: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if m { - return true, nil - } - } - return false, nil + return anySlice(condition, t) case []immutable.Option[float64]: - for _, c := range t { - m, err := eq(condition, c) - if err != nil { - return false, err - } else if m { - return true, nil - } - } - return false, nil + return anySlice(condition, t) default: return false, client.NewErrUnhandledType("data", data) } } + +func anySlice[T any](condition any, data []T) (bool, error) { + for _, c := range data { + m, err := eq(condition, c) + if err != nil { + return false, err + } else if m { + return true, nil + } + } + return false, nil +} diff --git a/internal/connor/eq.go b/internal/connor/eq.go index 343bc44bc1..3f849348b8 100644 --- a/internal/connor/eq.go +++ b/internal/connor/eq.go @@ -16,78 +16,59 @@ import ( func eq(condition, data any) (bool, error) { switch arr := data.(type) { case []core.Doc: - for _, item := range arr { - m, err := eq(condition, item) - if err != nil { - return false, err - } - - if m { - return true, nil - } - } - return false, nil + return anySlice(condition, arr) case immutable.Option[bool]: - if arr.HasValue() { - data = arr.Value() - } else { - data = nil - } + data = immutableValueOrNil(arr) case immutable.Option[int64]: - if arr.HasValue() { - data = arr.Value() - } else { - data = nil - } + data = immutableValueOrNil(arr) case immutable.Option[float64]: - if arr.HasValue() { - data = arr.Value() - } else { - data = nil - } + data = immutableValueOrNil(arr) case immutable.Option[string]: - if arr.HasValue() { - data = arr.Value() - } else { - data = nil - } + data = immutableValueOrNil(arr) } switch cn := condition.(type) { + case map[FilterKey]any: + for prop, cond := range cn { + m, err := matchWith(prop.GetOperatorOrDefault("_eq"), cond, prop.GetProp(data)) + if err != nil { + return false, err + } else if !m { + return false, nil + } + } + return true, nil + case string: if d, ok := data.(string); ok { return d == cn, nil } return false, nil + case int64: return numbers.Equal(cn, data), nil + case int32: return numbers.Equal(cn, data), nil + case float64: return numbers.Equal(cn, data), nil - case map[FilterKey]any: - m := true - for prop, cond := range cn { - var err error - m, err = matchWith(prop.GetOperatorOrDefault("_eq"), cond, prop.GetProp(data)) - if err != nil { - return false, err - } - - if !m { - // No need to evaluate after we fail - break - } - } - return m, nil case time.Time: return ctime.Equal(cn, data), nil + default: return reflect.DeepEqual(condition, data), nil } } + +func immutableValueOrNil[T any](data immutable.Option[T]) any { + if data.HasValue() { + return data.Value() + } + return nil +} From 4b4c822a0cd5c027e460151d1eb7bcdcab880fdb Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Wed, 18 Sep 2024 10:37:22 -0700 Subject: [PATCH 3/5] add compound tests. update test names --- .../inline_array/with_filter_all_test.go | 16 +++---- .../inline_array/with_filter_any_test.go | 16 +++---- .../query/simple/with_filter/utils.go | 1 + .../query/simple/with_filter/with_and_test.go | 39 +++++++++++++++++ .../query/simple/with_filter/with_or_test.go | 42 +++++++++++++++++++ 5 files changed, 98 insertions(+), 16 deletions(-) diff --git a/tests/integration/query/inline_array/with_filter_all_test.go b/tests/integration/query/inline_array/with_filter_all_test.go index bad0377188..1661c54731 100644 --- a/tests/integration/query/inline_array/with_filter_all_test.go +++ b/tests/integration/query/inline_array/with_filter_all_test.go @@ -16,7 +16,7 @@ import ( testUtils "github.com/sourcenetwork/defradb/tests/integration" ) -func TestQueryInlineStringArrayWithAllFilter(t *testing.T) { +func TestQueryInlineStringArray_WithAllFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered all of string array", Actions: []any{ @@ -52,7 +52,7 @@ func TestQueryInlineStringArrayWithAllFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineNonNullStringArrayWithAllFilter(t *testing.T) { +func TestQueryInlineNotNullStringArray_WithAllFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered all of non null string array", Actions: []any{ @@ -88,7 +88,7 @@ func TestQueryInlineNonNullStringArrayWithAllFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineIntArrayWithAllFilter(t *testing.T) { +func TestQueryInlineIntArray_WithAllFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered all of int array", Actions: []any{ @@ -124,7 +124,7 @@ func TestQueryInlineIntArrayWithAllFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineNonNullIntArrayWithAllFilter(t *testing.T) { +func TestQueryInlineNotNullIntArray_WithAllFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered all of non null int array", Actions: []any{ @@ -160,7 +160,7 @@ func TestQueryInlineNonNullIntArrayWithAllFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineFloatArrayWithAllFilter(t *testing.T) { +func TestQueryInlineFloatArray_WithAllFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered all of float array", Actions: []any{ @@ -196,7 +196,7 @@ func TestQueryInlineFloatArrayWithAllFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineNonNullFloatArrayWithAllFilter(t *testing.T) { +func TestQueryInlineNotNullFloatArray_WithAllFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered all of non null float array", Actions: []any{ @@ -232,7 +232,7 @@ func TestQueryInlineNonNullFloatArrayWithAllFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineBooleanArrayWithAllFilter(t *testing.T) { +func TestQueryInlineBooleanArray_WithAllFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered all of boolean array", Actions: []any{ @@ -268,7 +268,7 @@ func TestQueryInlineBooleanArrayWithAllFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineNonNullBooleanArrayWithAllFilter(t *testing.T) { +func TestQueryInlineNotNullBooleanArray_WithAllFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered all of non null boolean array", Actions: []any{ diff --git a/tests/integration/query/inline_array/with_filter_any_test.go b/tests/integration/query/inline_array/with_filter_any_test.go index 8b4bfcde0d..0dfc815595 100644 --- a/tests/integration/query/inline_array/with_filter_any_test.go +++ b/tests/integration/query/inline_array/with_filter_any_test.go @@ -16,7 +16,7 @@ import ( testUtils "github.com/sourcenetwork/defradb/tests/integration" ) -func TestQueryInlineStringArrayWithAnyFilter(t *testing.T) { +func TestQueryInlineStringArray_WithAnyFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered any of string array", Actions: []any{ @@ -52,7 +52,7 @@ func TestQueryInlineStringArrayWithAnyFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineNonNullStringArrayWithAnyFilter(t *testing.T) { +func TestQueryInlineNotNullStringArray_WithAnyFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered any of non null string array", Actions: []any{ @@ -88,7 +88,7 @@ func TestQueryInlineNonNullStringArrayWithAnyFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineIntArrayWithAnyFilter(t *testing.T) { +func TestQueryInlineIntArray_WithAnyFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered any of int array", Actions: []any{ @@ -124,7 +124,7 @@ func TestQueryInlineIntArrayWithAnyFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineNonNullIntArrayWithAnyFilter(t *testing.T) { +func TestQueryInlineNotNullIntArray_WithAnyFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered any of non null int array", Actions: []any{ @@ -160,7 +160,7 @@ func TestQueryInlineNonNullIntArrayWithAnyFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineFloatArrayWithAnyFilter(t *testing.T) { +func TestQueryInlineFloatArray_WithAnyFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered any of float array", Actions: []any{ @@ -196,7 +196,7 @@ func TestQueryInlineFloatArrayWithAnyFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineNonNullFloatArrayWithAnyFilter(t *testing.T) { +func TestQueryInlineNotNullFloatArray_WithAnyFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered any of non null float array", Actions: []any{ @@ -232,7 +232,7 @@ func TestQueryInlineNonNullFloatArrayWithAnyFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineBooleanArrayWithAnyFilter(t *testing.T) { +func TestQueryInlineBooleanArray_WithAnyFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered any of boolean array", Actions: []any{ @@ -268,7 +268,7 @@ func TestQueryInlineBooleanArrayWithAnyFilter(t *testing.T) { executeTestCase(t, test) } -func TestQueryInlineNonNullBooleanArrayWithAnyFilter(t *testing.T) { +func TestQueryInlineNotNullBooleanArray_WithAnyFilter_Succeeds(t *testing.T) { test := testUtils.TestCase{ Description: "Simple inline array, filtered any of non null boolean array", Actions: []any{ diff --git a/tests/integration/query/simple/with_filter/utils.go b/tests/integration/query/simple/with_filter/utils.go index 4e4375096b..cdd2abf664 100644 --- a/tests/integration/query/simple/with_filter/utils.go +++ b/tests/integration/query/simple/with_filter/utils.go @@ -23,6 +23,7 @@ var userCollectionGQLSchema = (` HeightM: Float Verified: Boolean CreatedAt: DateTime + FavoriteNumbers: [Int!] } `) diff --git a/tests/integration/query/simple/with_filter/with_and_test.go b/tests/integration/query/simple/with_filter/with_and_test.go index 81ccbeb35f..c8e35055b6 100644 --- a/tests/integration/query/simple/with_filter/with_and_test.go +++ b/tests/integration/query/simple/with_filter/with_and_test.go @@ -69,3 +69,42 @@ func TestQuerySimpleWithIntGreaterThanAndIntLessThanFilter(t *testing.T) { executeTestCase(t, test) } + +func TestQuerySimple_WithInlineIntArray_GreaterThanAndLessThanFilter_Succeeds(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple query with logical compound filter (and) on inline int array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "Name": "Bob", + "FavoriteNumbers": [0, 10, 20] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "Name": "Alice", + "FavoriteNumbers": [30, 40, 50] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {_and: [ + {FavoriteNumbers: {_all: {_ge: 0}}}, + {FavoriteNumbers: {_all: {_lt: 30}}}, + ]}) { + Name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "Name": "Bob", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_filter/with_or_test.go b/tests/integration/query/simple/with_filter/with_or_test.go index fe63d7cc62..50c396cd44 100644 --- a/tests/integration/query/simple/with_filter/with_or_test.go +++ b/tests/integration/query/simple/with_filter/with_or_test.go @@ -69,3 +69,45 @@ func TestQuerySimpleWithIntEqualToXOrYFilter(t *testing.T) { executeTestCase(t, test) } + +func TestQuerySimple_WithInlineIntArray_EqualToXOrYFilter_Succeeds(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple query with logical compound filter (or) on inline int array", + Actions: []any{ + testUtils.CreateDoc{ + Doc: `{ + "Name": "Bob", + "FavoriteNumbers": [10, 20] + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "Name": "Alice", + "FavoriteNumbers": [30, 40] + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {_or: [ + {FavoriteNumbers: {_any: {_le: 100}}}, + {FavoriteNumbers: {_any: {_ge: 0}}}, + ]}) { + Name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "Name": "Bob", + }, + { + "Name": "Alice", + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} From dfbf78a3c00804dec2a157345534555f24a742b2 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Wed, 18 Sep 2024 16:01:58 -0700 Subject: [PATCH 4/5] fix ordering of filter test results --- .../simple/with_filter/with_ge_datetime_test.go | 4 ++-- .../simple/with_filter/with_ge_float_test.go | 4 ++-- .../query/simple/with_filter/with_ge_int_test.go | 4 ++-- .../simple/with_filter/with_gt_float_test.go | 4 ++-- .../query/simple/with_filter/with_in_test.go | 16 ++++++++-------- .../simple/with_filter/with_ne_bool_test.go | 8 ++++---- .../simple/with_filter/with_ne_datetime_test.go | 4 ++-- .../simple/with_filter/with_ne_float_test.go | 4 ++-- .../query/simple/with_filter/with_not_test.go | 16 ++++++++-------- .../query/simple/with_filter/with_or_test.go | 8 ++++---- 10 files changed, 36 insertions(+), 36 deletions(-) diff --git a/tests/integration/query/simple/with_filter/with_ge_datetime_test.go b/tests/integration/query/simple/with_filter/with_ge_datetime_test.go index 4ad799d0b0..8c2344dc33 100644 --- a/tests/integration/query/simple/with_filter/with_ge_datetime_test.go +++ b/tests/integration/query/simple/with_filter/with_ge_datetime_test.go @@ -150,10 +150,10 @@ func TestQuerySimpleWithDateTimeGEFilterBlockWithNilValue(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Bob", + "Name": "John", }, { - "Name": "John", + "Name": "Bob", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ge_float_test.go b/tests/integration/query/simple/with_filter/with_ge_float_test.go index 9ea5559972..c933f12480 100644 --- a/tests/integration/query/simple/with_filter/with_ge_float_test.go +++ b/tests/integration/query/simple/with_filter/with_ge_float_test.go @@ -148,10 +148,10 @@ func TestQuerySimpleWithHeightMGEFilterBlockWithNilValue(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "Bob", }, { - "Name": "Bob", + "Name": "John", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ge_int_test.go b/tests/integration/query/simple/with_filter/with_ge_int_test.go index 1c2b629960..073766aa6c 100644 --- a/tests/integration/query/simple/with_filter/with_ge_int_test.go +++ b/tests/integration/query/simple/with_filter/with_ge_int_test.go @@ -112,10 +112,10 @@ func TestQuerySimpleWithIntGEFilterBlockWithNilValue(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Bob", + "Name": "John", }, { - "Name": "John", + "Name": "Bob", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_gt_float_test.go b/tests/integration/query/simple/with_filter/with_gt_float_test.go index a362223488..73c1f151d3 100644 --- a/tests/integration/query/simple/with_filter/with_gt_float_test.go +++ b/tests/integration/query/simple/with_filter/with_gt_float_test.go @@ -100,10 +100,10 @@ func TestQuerySimpleWithFloatGreaterThanFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "Bob", }, { - "Name": "Bob", + "Name": "John", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_in_test.go b/tests/integration/query/simple/with_filter/with_in_test.go index 5afca0c170..4af16b55f9 100644 --- a/tests/integration/query/simple/with_filter/with_in_test.go +++ b/tests/integration/query/simple/with_filter/with_in_test.go @@ -53,14 +53,14 @@ func TestQuerySimpleWithIntInFilter(t *testing.T) { }`, Results: map[string]any{ "Users": []map[string]any{ - { - "Name": "Carlo", - "Age": int64(55), - }, { "Name": "Alice", "Age": int64(19), }, + { + "Name": "Carlo", + "Age": int64(55), + }, }, }, }, @@ -164,16 +164,16 @@ func TestQuerySimpleWithIntInFilterWithNullValue(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Fred", - "Age": nil, + "Name": "Alice", + "Age": int64(19), }, { "Name": "Carlo", "Age": int64(55), }, { - "Name": "Alice", - "Age": int64(19), + "Name": "Fred", + "Age": nil, }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ne_bool_test.go b/tests/integration/query/simple/with_filter/with_ne_bool_test.go index d1acd27ad2..6f916333e9 100644 --- a/tests/integration/query/simple/with_filter/with_ne_bool_test.go +++ b/tests/integration/query/simple/with_filter/with_ne_bool_test.go @@ -90,10 +90,10 @@ func TestQuerySimpleWithBoolNotEqualsNilFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "Fred", }, { - "Name": "Fred", + "Name": "John", }, }, }, @@ -134,10 +134,10 @@ func TestQuerySimpleWithBoolNotEqualsFalseFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "Bob", }, { - "Name": "Bob", + "Name": "John", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ne_datetime_test.go b/tests/integration/query/simple/with_filter/with_ne_datetime_test.go index ecc40d3969..f119c20ae9 100644 --- a/tests/integration/query/simple/with_filter/with_ne_datetime_test.go +++ b/tests/integration/query/simple/with_filter/with_ne_datetime_test.go @@ -87,10 +87,10 @@ func TestQuerySimpleWithDateTimeNotEqualsNilFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Bob", + "Name": "John", }, { - "Name": "John", + "Name": "Bob", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ne_float_test.go b/tests/integration/query/simple/with_filter/with_ne_float_test.go index 58b2985013..c5835009a7 100644 --- a/tests/integration/query/simple/with_filter/with_ne_float_test.go +++ b/tests/integration/query/simple/with_filter/with_ne_float_test.go @@ -82,10 +82,10 @@ func TestQuerySimpleWithFloatNotEqualsNilFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "Bob", }, { - "Name": "Bob", + "Name": "John", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_not_test.go b/tests/integration/query/simple/with_filter/with_not_test.go index 15071e9c14..23446a5618 100644 --- a/tests/integration/query/simple/with_filter/with_not_test.go +++ b/tests/integration/query/simple/with_filter/with_not_test.go @@ -57,14 +57,14 @@ func TestQuerySimple_WithNotEqualToXFilter_NoError(t *testing.T) { "Name": "John", "Age": int64(21), }, - { - "Name": "Bob", - "Age": int64(32), - }, { "Name": "Alice", "Age": int64(19), }, + { + "Name": "Bob", + "Age": int64(32), + }, }, }, }, @@ -270,6 +270,10 @@ func TestQuerySimple_WithNotEqualToXAndNotYFilter_NoError(t *testing.T) { "Name": "John", "Age": int64(21), }, + { + "Name": "Alice", + "Age": int64(19), + }, { "Name": "Bob", "Age": int64(32), @@ -278,10 +282,6 @@ func TestQuerySimple_WithNotEqualToXAndNotYFilter_NoError(t *testing.T) { "Name": "Carlo", "Age": int64(55), }, - { - "Name": "Alice", - "Age": int64(19), - }, }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_or_test.go b/tests/integration/query/simple/with_filter/with_or_test.go index 50c396cd44..947e410577 100644 --- a/tests/integration/query/simple/with_filter/with_or_test.go +++ b/tests/integration/query/simple/with_filter/with_or_test.go @@ -53,14 +53,14 @@ func TestQuerySimpleWithIntEqualToXOrYFilter(t *testing.T) { }`, Results: map[string]any{ "Users": []map[string]any{ - { - "Name": "Carlo", - "Age": int64(55), - }, { "Name": "Alice", "Age": int64(19), }, + { + "Name": "Carlo", + "Age": int64(55), + }, }, }, }, From 5727a1280e7a1dce562b7f8bb3848d069473334c Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Fri, 20 Sep 2024 12:32:35 -0700 Subject: [PATCH 5/5] revert schema fixture change --- .../query/simple/with_filter/utils.go | 1 - .../query/simple/with_filter/with_and_test.go | 8 +++++++- .../with_filter/with_ge_datetime_test.go | 4 ++-- .../simple/with_filter/with_ge_float_test.go | 4 ++-- .../simple/with_filter/with_ge_int_test.go | 4 ++-- .../simple/with_filter/with_gt_float_test.go | 4 ++-- .../query/simple/with_filter/with_in_test.go | 16 +++++++-------- .../simple/with_filter/with_ne_bool_test.go | 8 ++++---- .../with_filter/with_ne_datetime_test.go | 4 ++-- .../simple/with_filter/with_ne_float_test.go | 4 ++-- .../query/simple/with_filter/with_not_test.go | 16 +++++++-------- .../query/simple/with_filter/with_or_test.go | 20 ++++++++++++------- 12 files changed, 52 insertions(+), 41 deletions(-) diff --git a/tests/integration/query/simple/with_filter/utils.go b/tests/integration/query/simple/with_filter/utils.go index cdd2abf664..4e4375096b 100644 --- a/tests/integration/query/simple/with_filter/utils.go +++ b/tests/integration/query/simple/with_filter/utils.go @@ -23,7 +23,6 @@ var userCollectionGQLSchema = (` HeightM: Float Verified: Boolean CreatedAt: DateTime - FavoriteNumbers: [Int!] } `) diff --git a/tests/integration/query/simple/with_filter/with_and_test.go b/tests/integration/query/simple/with_filter/with_and_test.go index c8e35055b6..eb566fd751 100644 --- a/tests/integration/query/simple/with_filter/with_and_test.go +++ b/tests/integration/query/simple/with_filter/with_and_test.go @@ -74,6 +74,12 @@ func TestQuerySimple_WithInlineIntArray_GreaterThanAndLessThanFilter_Succeeds(t test := testUtils.TestCase{ Description: "Simple query with logical compound filter (and) on inline int array", Actions: []any{ + testUtils.SchemaUpdate{ + Schema: `type Users { + Name: String + FavoriteNumbers: [Int!] + }`, + }, testUtils.CreateDoc{ Doc: `{ "Name": "Bob", @@ -106,5 +112,5 @@ func TestQuerySimple_WithInlineIntArray_GreaterThanAndLessThanFilter_Succeeds(t }, } - executeTestCase(t, test) + testUtils.ExecuteTestCase(t, test) } diff --git a/tests/integration/query/simple/with_filter/with_ge_datetime_test.go b/tests/integration/query/simple/with_filter/with_ge_datetime_test.go index 8c2344dc33..4ad799d0b0 100644 --- a/tests/integration/query/simple/with_filter/with_ge_datetime_test.go +++ b/tests/integration/query/simple/with_filter/with_ge_datetime_test.go @@ -150,10 +150,10 @@ func TestQuerySimpleWithDateTimeGEFilterBlockWithNilValue(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "Bob", }, { - "Name": "Bob", + "Name": "John", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ge_float_test.go b/tests/integration/query/simple/with_filter/with_ge_float_test.go index c933f12480..9ea5559972 100644 --- a/tests/integration/query/simple/with_filter/with_ge_float_test.go +++ b/tests/integration/query/simple/with_filter/with_ge_float_test.go @@ -148,10 +148,10 @@ func TestQuerySimpleWithHeightMGEFilterBlockWithNilValue(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Bob", + "Name": "John", }, { - "Name": "John", + "Name": "Bob", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ge_int_test.go b/tests/integration/query/simple/with_filter/with_ge_int_test.go index 073766aa6c..1c2b629960 100644 --- a/tests/integration/query/simple/with_filter/with_ge_int_test.go +++ b/tests/integration/query/simple/with_filter/with_ge_int_test.go @@ -112,10 +112,10 @@ func TestQuerySimpleWithIntGEFilterBlockWithNilValue(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "Bob", }, { - "Name": "Bob", + "Name": "John", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_gt_float_test.go b/tests/integration/query/simple/with_filter/with_gt_float_test.go index 73c1f151d3..a362223488 100644 --- a/tests/integration/query/simple/with_filter/with_gt_float_test.go +++ b/tests/integration/query/simple/with_filter/with_gt_float_test.go @@ -100,10 +100,10 @@ func TestQuerySimpleWithFloatGreaterThanFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Bob", + "Name": "John", }, { - "Name": "John", + "Name": "Bob", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_in_test.go b/tests/integration/query/simple/with_filter/with_in_test.go index 4af16b55f9..5afca0c170 100644 --- a/tests/integration/query/simple/with_filter/with_in_test.go +++ b/tests/integration/query/simple/with_filter/with_in_test.go @@ -53,14 +53,14 @@ func TestQuerySimpleWithIntInFilter(t *testing.T) { }`, Results: map[string]any{ "Users": []map[string]any{ - { - "Name": "Alice", - "Age": int64(19), - }, { "Name": "Carlo", "Age": int64(55), }, + { + "Name": "Alice", + "Age": int64(19), + }, }, }, }, @@ -164,16 +164,16 @@ func TestQuerySimpleWithIntInFilterWithNullValue(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Alice", - "Age": int64(19), + "Name": "Fred", + "Age": nil, }, { "Name": "Carlo", "Age": int64(55), }, { - "Name": "Fred", - "Age": nil, + "Name": "Alice", + "Age": int64(19), }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ne_bool_test.go b/tests/integration/query/simple/with_filter/with_ne_bool_test.go index 6f916333e9..d1acd27ad2 100644 --- a/tests/integration/query/simple/with_filter/with_ne_bool_test.go +++ b/tests/integration/query/simple/with_filter/with_ne_bool_test.go @@ -90,10 +90,10 @@ func TestQuerySimpleWithBoolNotEqualsNilFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Fred", + "Name": "John", }, { - "Name": "John", + "Name": "Fred", }, }, }, @@ -134,10 +134,10 @@ func TestQuerySimpleWithBoolNotEqualsFalseFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Bob", + "Name": "John", }, { - "Name": "John", + "Name": "Bob", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ne_datetime_test.go b/tests/integration/query/simple/with_filter/with_ne_datetime_test.go index f119c20ae9..ecc40d3969 100644 --- a/tests/integration/query/simple/with_filter/with_ne_datetime_test.go +++ b/tests/integration/query/simple/with_filter/with_ne_datetime_test.go @@ -87,10 +87,10 @@ func TestQuerySimpleWithDateTimeNotEqualsNilFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "Bob", }, { - "Name": "Bob", + "Name": "John", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_ne_float_test.go b/tests/integration/query/simple/with_filter/with_ne_float_test.go index c5835009a7..58b2985013 100644 --- a/tests/integration/query/simple/with_filter/with_ne_float_test.go +++ b/tests/integration/query/simple/with_filter/with_ne_float_test.go @@ -82,10 +82,10 @@ func TestQuerySimpleWithFloatNotEqualsNilFilterBlock(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Bob", + "Name": "John", }, { - "Name": "John", + "Name": "Bob", }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_not_test.go b/tests/integration/query/simple/with_filter/with_not_test.go index 23446a5618..15071e9c14 100644 --- a/tests/integration/query/simple/with_filter/with_not_test.go +++ b/tests/integration/query/simple/with_filter/with_not_test.go @@ -57,14 +57,14 @@ func TestQuerySimple_WithNotEqualToXFilter_NoError(t *testing.T) { "Name": "John", "Age": int64(21), }, - { - "Name": "Alice", - "Age": int64(19), - }, { "Name": "Bob", "Age": int64(32), }, + { + "Name": "Alice", + "Age": int64(19), + }, }, }, }, @@ -270,10 +270,6 @@ func TestQuerySimple_WithNotEqualToXAndNotYFilter_NoError(t *testing.T) { "Name": "John", "Age": int64(21), }, - { - "Name": "Alice", - "Age": int64(19), - }, { "Name": "Bob", "Age": int64(32), @@ -282,6 +278,10 @@ func TestQuerySimple_WithNotEqualToXAndNotYFilter_NoError(t *testing.T) { "Name": "Carlo", "Age": int64(55), }, + { + "Name": "Alice", + "Age": int64(19), + }, }, }, }, diff --git a/tests/integration/query/simple/with_filter/with_or_test.go b/tests/integration/query/simple/with_filter/with_or_test.go index 947e410577..e208693049 100644 --- a/tests/integration/query/simple/with_filter/with_or_test.go +++ b/tests/integration/query/simple/with_filter/with_or_test.go @@ -53,14 +53,14 @@ func TestQuerySimpleWithIntEqualToXOrYFilter(t *testing.T) { }`, Results: map[string]any{ "Users": []map[string]any{ - { - "Name": "Alice", - "Age": int64(19), - }, { "Name": "Carlo", "Age": int64(55), }, + { + "Name": "Alice", + "Age": int64(19), + }, }, }, }, @@ -74,6 +74,12 @@ func TestQuerySimple_WithInlineIntArray_EqualToXOrYFilter_Succeeds(t *testing.T) test := testUtils.TestCase{ Description: "Simple query with logical compound filter (or) on inline int array", Actions: []any{ + testUtils.SchemaUpdate{ + Schema: `type Users { + Name: String + FavoriteNumbers: [Int!] + }`, + }, testUtils.CreateDoc{ Doc: `{ "Name": "Bob", @@ -98,10 +104,10 @@ func TestQuerySimple_WithInlineIntArray_EqualToXOrYFilter_Succeeds(t *testing.T) Results: map[string]any{ "Users": []map[string]any{ { - "Name": "Bob", + "Name": "Alice", }, { - "Name": "Alice", + "Name": "Bob", }, }, }, @@ -109,5 +115,5 @@ func TestQuerySimple_WithInlineIntArray_EqualToXOrYFilter_Succeeds(t *testing.T) }, } - executeTestCase(t, test) + testUtils.ExecuteTestCase(t, test) }