From 2e8c2ef805b032ed7b4ec77a209091d2f8dfecd2 Mon Sep 17 00:00:00 2001 From: Islam Aleiv Date: Tue, 16 Jul 2024 16:03:44 +0200 Subject: [PATCH 1/3] Enable filtering doc by fields of JSON and Blob types --- .../request/graphql/schema/descriptions.go | 4 +- internal/request/graphql/schema/manager.go | 8 +- internal/request/graphql/schema/types/base.go | 167 ++++++++++++++++++ .../request/graphql/schema/types/scalars.go | 8 +- .../graphql/schema/types/scalars_test.go | 12 +- .../simple/with_filter/with_eq_blob_test.go | 54 ++++++ .../simple/with_filter/with_eq_json_test.go | 55 ++++++ .../simple/with_filter/with_like_blob_test.go | 54 ++++++ .../simple/with_filter/with_like_json_test.go | 54 ++++++ .../simple/with_filter/with_nin_blob_test.go | 55 ++++++ .../simple/with_filter/with_nin_json_test.go | 55 ++++++ 11 files changed, 514 insertions(+), 12 deletions(-) create mode 100644 tests/integration/query/simple/with_filter/with_eq_blob_test.go create mode 100644 tests/integration/query/simple/with_filter/with_eq_json_test.go create mode 100644 tests/integration/query/simple/with_filter/with_like_blob_test.go create mode 100644 tests/integration/query/simple/with_filter/with_like_json_test.go create mode 100644 tests/integration/query/simple/with_filter/with_nin_blob_test.go create mode 100644 tests/integration/query/simple/with_filter/with_nin_json_test.go diff --git a/internal/request/graphql/schema/descriptions.go b/internal/request/graphql/schema/descriptions.go index 526e41470e..8fccff2fb0 100644 --- a/internal/request/graphql/schema/descriptions.go +++ b/internal/request/graphql/schema/descriptions.go @@ -33,8 +33,8 @@ var ( client.FieldKind_NILLABLE_STRING: gql.String, client.FieldKind_STRING_ARRAY: gql.NewList(gql.NewNonNull(gql.String)), client.FieldKind_NILLABLE_STRING_ARRAY: gql.NewList(gql.String), - client.FieldKind_NILLABLE_BLOB: schemaTypes.BlobScalarType(), - client.FieldKind_NILLABLE_JSON: schemaTypes.JSONScalarType(), + client.FieldKind_NILLABLE_BLOB: schemaTypes.BlobScalarType, + client.FieldKind_NILLABLE_JSON: schemaTypes.JSONScalarType, } defaultCRDTForFieldKind = map[client.FieldKind]client.CType{ diff --git a/internal/request/graphql/schema/manager.go b/internal/request/graphql/schema/manager.go index fee626b45c..7009ee2e3f 100644 --- a/internal/request/graphql/schema/manager.go +++ b/internal/request/graphql/schema/manager.go @@ -176,8 +176,8 @@ func defaultTypes( gql.String, // Custom Scalar types - schemaTypes.BlobScalarType(), - schemaTypes.JSONScalarType(), + schemaTypes.BlobScalarType, + schemaTypes.JSONScalarType, // Base Query types @@ -195,6 +195,10 @@ func defaultTypes( schemaTypes.NotNullIntOperatorBlock(), schemaTypes.StringOperatorBlock(), schemaTypes.NotNullstringOperatorBlock(), + schemaTypes.JSONOperatorBlock(), + schemaTypes.NotNullJSONOperatorBlock(), + schemaTypes.BlobOperatorBlock(), + schemaTypes.NotNullBlobOperatorBlock(), commitsOrderArg, commitLinkObject, diff --git a/internal/request/graphql/schema/types/base.go b/internal/request/graphql/schema/types/base.go index ca4c8f2372..bcfa00e477 100644 --- a/internal/request/graphql/schema/types/base.go +++ b/internal/request/graphql/schema/types/base.go @@ -360,6 +360,173 @@ func NotNullstringOperatorBlock() *gql.InputObject { }) } +// JSONOperatorBlock filter block for string types. +func JSONOperatorBlock() *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "JSONOperatorBlock", + Description: stringOperatorBlockDescription, + Fields: gql.InputObjectConfigFieldMap{ + "_eq": &gql.InputObjectFieldConfig{ + Description: eqOperatorDescription, + Type: JSONScalarType, + }, + "_ne": &gql.InputObjectFieldConfig{ + Description: neOperatorDescription, + Type: JSONScalarType, + }, + "_in": &gql.InputObjectFieldConfig{ + Description: inOperatorDescription, + Type: gql.NewList(JSONScalarType), + }, + "_nin": &gql.InputObjectFieldConfig{ + Description: ninOperatorDescription, + Type: gql.NewList(JSONScalarType), + }, + "_like": &gql.InputObjectFieldConfig{ + Description: likeStringOperatorDescription, + Type: gql.String, + }, + "_nlike": &gql.InputObjectFieldConfig{ + Description: nlikeStringOperatorDescription, + Type: gql.String, + }, + "_ilike": &gql.InputObjectFieldConfig{ + Description: ilikeStringOperatorDescription, + Type: gql.String, + }, + "_nilike": &gql.InputObjectFieldConfig{ + Description: nilikeStringOperatorDescription, + Type: gql.String, + }, + }, + }) +} + +// NotNullJSONOperatorBlock filter block for string! types. +func NotNullJSONOperatorBlock() *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "NotNullJSONOperatorBlock", + Description: notNullStringOperatorBlockDescription, + Fields: gql.InputObjectConfigFieldMap{ + "_eq": &gql.InputObjectFieldConfig{ + Description: eqOperatorDescription, + Type: JSONScalarType, + }, + "_ne": &gql.InputObjectFieldConfig{ + Description: neOperatorDescription, + Type: JSONScalarType, + }, + "_in": &gql.InputObjectFieldConfig{ + Description: inOperatorDescription, + Type: gql.NewList(gql.NewNonNull(JSONScalarType)), + }, + "_nin": &gql.InputObjectFieldConfig{ + Description: ninOperatorDescription, + Type: gql.NewList(gql.NewNonNull(JSONScalarType)), + }, + "_like": &gql.InputObjectFieldConfig{ + Description: likeStringOperatorDescription, + Type: gql.String, + }, + "_nlike": &gql.InputObjectFieldConfig{ + Description: nlikeStringOperatorDescription, + Type: gql.String, + }, + "_ilike": &gql.InputObjectFieldConfig{ + Description: ilikeStringOperatorDescription, + Type: gql.String, + }, + "_nilike": &gql.InputObjectFieldConfig{ + Description: nilikeStringOperatorDescription, + Type: gql.String, + }, + }, + }) +} + +func BlobOperatorBlock() *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "BlobOperatorBlock", + Description: stringOperatorBlockDescription, + Fields: gql.InputObjectConfigFieldMap{ + "_eq": &gql.InputObjectFieldConfig{ + Description: eqOperatorDescription, + Type: BlobScalarType, + }, + "_ne": &gql.InputObjectFieldConfig{ + Description: neOperatorDescription, + Type: BlobScalarType, + }, + "_in": &gql.InputObjectFieldConfig{ + Description: inOperatorDescription, + Type: gql.NewList(BlobScalarType), + }, + "_nin": &gql.InputObjectFieldConfig{ + Description: ninOperatorDescription, + Type: gql.NewList(BlobScalarType), + }, + "_like": &gql.InputObjectFieldConfig{ + Description: likeStringOperatorDescription, + Type: gql.String, + }, + "_nlike": &gql.InputObjectFieldConfig{ + Description: nlikeStringOperatorDescription, + Type: gql.String, + }, + "_ilike": &gql.InputObjectFieldConfig{ + Description: ilikeStringOperatorDescription, + Type: gql.String, + }, + "_nilike": &gql.InputObjectFieldConfig{ + Description: nilikeStringOperatorDescription, + Type: gql.String, + }, + }, + }) +} + +// NotNullJSONOperatorBlock filter block for string! types. +func NotNullBlobOperatorBlock() *gql.InputObject { + return gql.NewInputObject(gql.InputObjectConfig{ + Name: "NotNullBlobOperatorBlock", + Description: notNullStringOperatorBlockDescription, + Fields: gql.InputObjectConfigFieldMap{ + "_eq": &gql.InputObjectFieldConfig{ + Description: eqOperatorDescription, + Type: BlobScalarType, + }, + "_ne": &gql.InputObjectFieldConfig{ + Description: neOperatorDescription, + Type: BlobScalarType, + }, + "_in": &gql.InputObjectFieldConfig{ + Description: inOperatorDescription, + Type: gql.NewList(gql.NewNonNull(BlobScalarType)), + }, + "_nin": &gql.InputObjectFieldConfig{ + Description: ninOperatorDescription, + Type: gql.NewList(gql.NewNonNull(BlobScalarType)), + }, + "_like": &gql.InputObjectFieldConfig{ + Description: likeStringOperatorDescription, + Type: gql.String, + }, + "_nlike": &gql.InputObjectFieldConfig{ + Description: nlikeStringOperatorDescription, + Type: gql.String, + }, + "_ilike": &gql.InputObjectFieldConfig{ + Description: ilikeStringOperatorDescription, + Type: gql.String, + }, + "_nilike": &gql.InputObjectFieldConfig{ + Description: nilikeStringOperatorDescription, + Type: gql.String, + }, + }, + }) +} + // IdOperatorBlock filter block for ID types. func IdOperatorBlock() *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ diff --git a/internal/request/graphql/schema/types/scalars.go b/internal/request/graphql/schema/types/scalars.go index b86c744607..a57fe5ae67 100644 --- a/internal/request/graphql/schema/types/scalars.go +++ b/internal/request/graphql/schema/types/scalars.go @@ -46,7 +46,7 @@ func coerceBlob(value any) any { } } -func BlobScalarType() *graphql.Scalar { +func NewBlobScalarType() *graphql.Scalar { return graphql.NewScalar(graphql.ScalarConfig{ Name: "Blob", Description: "The `Blob` scalar type represents a binary large object.", @@ -67,6 +67,8 @@ func BlobScalarType() *graphql.Scalar { }) } +var BlobScalarType = NewBlobScalarType() + // coerceJSON converts the given value into a valid json string. // If the value cannot be converted nil is returned. func coerceJSON(value any) any { @@ -100,7 +102,7 @@ func coerceJSON(value any) any { } } -func JSONScalarType() *graphql.Scalar { +func NewJSONScalarType() *graphql.Scalar { return graphql.NewScalar(graphql.ScalarConfig{ Name: "JSON", Description: "The `JSON` scalar type represents a JSON string.", @@ -120,3 +122,5 @@ func JSONScalarType() *graphql.Scalar { }, }) } + +var JSONScalarType = NewJSONScalarType() diff --git a/internal/request/graphql/schema/types/scalars_test.go b/internal/request/graphql/schema/types/scalars_test.go index fba94ce67b..f7fe5ed4ec 100644 --- a/internal/request/graphql/schema/types/scalars_test.go +++ b/internal/request/graphql/schema/types/scalars_test.go @@ -34,7 +34,7 @@ func TestBlobScalarTypeSerialize(t *testing.T) { {false, nil}, } for _, c := range cases { - result := BlobScalarType().Serialize(c.input) + result := NewBlobScalarType().Serialize(c.input) assert.Equal(t, c.expect, result) } } @@ -60,7 +60,7 @@ func TestBlobScalarTypeParseValue(t *testing.T) { {false, nil}, } for _, c := range cases { - result := BlobScalarType().ParseValue(c.input) + result := NewBlobScalarType().ParseValue(c.input) assert.Equal(t, c.expect, result) } } @@ -82,7 +82,7 @@ func TestBlobScalarTypeParseLiteral(t *testing.T) { {&ast.ObjectValue{}, nil}, } for _, c := range cases { - result := BlobScalarType().ParseLiteral(c.input) + result := NewBlobScalarType().ParseLiteral(c.input) assert.Equal(t, c.expect, result) } } @@ -141,10 +141,10 @@ func TestJSONScalarTypeParseAndSerialize(t *testing.T) { {false, nil}, } for _, c := range cases { - parsed := JSONScalarType().ParseValue(c.input) + parsed := JSONScalarType.ParseValue(c.input) assert.Equal(t, c.expect, parsed) - serialized := JSONScalarType().Serialize(c.input) + serialized := JSONScalarType.Serialize(c.input) assert.Equal(t, c.expect, serialized) } } @@ -165,7 +165,7 @@ func TestJSONScalarTypeParseLiteral(t *testing.T) { {&ast.ObjectValue{}, nil}, } for _, c := range cases { - result := JSONScalarType().ParseLiteral(c.input) + result := JSONScalarType.ParseLiteral(c.input) assert.Equal(t, c.expect, result) } } diff --git a/tests/integration/query/simple/with_filter/with_eq_blob_test.go b/tests/integration/query/simple/with_filter/with_eq_blob_test.go new file mode 100644 index 0000000000..76a804f98a --- /dev/null +++ b/tests/integration/query/simple/with_filter/with_eq_blob_test.go @@ -0,0 +1,54 @@ +// 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 simple + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQuerySimple_WithEqOpOnBlobField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + data: Blob + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John", + "data": "00FF99AA" + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Andy", + "data": "FA02CC45" + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {data: {_eq: "00FF99AA"}}) { + name + } + }`, + Results: []map[string]any{{"name": "John"}}, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_filter/with_eq_json_test.go b/tests/integration/query/simple/with_filter/with_eq_json_test.go new file mode 100644 index 0000000000..d0d9e93369 --- /dev/null +++ b/tests/integration/query/simple/with_filter/with_eq_json_test.go @@ -0,0 +1,55 @@ +// 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 simple + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQuerySimple_WithEqOpOnJSONField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + custom: JSON + } + `, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": "{\"tree\": \"maple\", \"age\": 250}", + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": "{\"tree\": \"oak\", \"age\": 450}", + }, + }, + testUtils.Request{ + // the filtered-by JSON has no spaces, because this is now it's stored. + Request: `query { + Users(filter: {custom: {_eq: "{\"tree\":\"oak\",\"age\":450}"}}) { + name + } + }`, + Results: []map[string]any{{"name": "Andy"}}, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_filter/with_like_blob_test.go b/tests/integration/query/simple/with_filter/with_like_blob_test.go new file mode 100644 index 0000000000..bc51930f06 --- /dev/null +++ b/tests/integration/query/simple/with_filter/with_like_blob_test.go @@ -0,0 +1,54 @@ +// 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 simple + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQuerySimple_WithLikeOpOnBlobField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + data: Blob + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John", + "data": "00FF99AA" + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Andy", + "data": "FA02CC45" + }`, + }, + testUtils.Request{ + Request: `query { + Users(filter: {data: {_like: "%FF99%"}}) { + name + } + }`, + Results: []map[string]any{{"name": "John"}}, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_filter/with_like_json_test.go b/tests/integration/query/simple/with_filter/with_like_json_test.go new file mode 100644 index 0000000000..ed092dd502 --- /dev/null +++ b/tests/integration/query/simple/with_filter/with_like_json_test.go @@ -0,0 +1,54 @@ +// 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 simple + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQuerySimple_WithLikeOpOnJSONField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + custom: JSON + } + `, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": "{\"tree\": \"maple\", \"age\": 250}", + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": "{\"tree\": \"oak\", \"age\": 450}", + }, + }, + testUtils.Request{ + Request: `query { + Users(filter: {custom: {_like: "%oak%"}}) { + name + } + }`, + Results: []map[string]any{{"name": "Andy"}}, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_filter/with_nin_blob_test.go b/tests/integration/query/simple/with_filter/with_nin_blob_test.go new file mode 100644 index 0000000000..b2d70ace16 --- /dev/null +++ b/tests/integration/query/simple/with_filter/with_nin_blob_test.go @@ -0,0 +1,55 @@ +// 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 simple + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQuerySimple_WithInOpOnBlobField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + data: Blob + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John", + "data": "00FF99AA" + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Andy", + "data": "FA02CC45" + }`, + }, + testUtils.Request{ + // the filtered-by JSON has no spaces, because this is now it's stored. + Request: `query { + Users(filter: {data: {_in: ["00FF99AA"]}}) { + name + } + }`, + Results: []map[string]any{{"name": "John"}}, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_filter/with_nin_json_test.go b/tests/integration/query/simple/with_filter/with_nin_json_test.go new file mode 100644 index 0000000000..cb4fcdc7da --- /dev/null +++ b/tests/integration/query/simple/with_filter/with_nin_json_test.go @@ -0,0 +1,55 @@ +// 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 simple + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQuerySimple_WithInOpOnJSONField_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + custom: JSON + } + `, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "John", + "custom": "{\"tree\": \"maple\", \"age\": 250}", + }, + }, + testUtils.CreateDoc{ + DocMap: map[string]any{ + "name": "Andy", + "custom": "{\"tree\": \"oak\", \"age\": 450}", + }, + }, + testUtils.Request{ + // the filtered-by JSON has no spaces, because this is now it's stored. + Request: `query { + Users(filter: {custom: {_in: ["{\"tree\":\"oak\",\"age\":450}"]}}) { + name + } + }`, + Results: []map[string]any{{"name": "Andy"}}, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} From b33a3760cb001ec1fddf6711be5d75de38f99244 Mon Sep 17 00:00:00 2001 From: Islam Aleiv Date: Tue, 16 Jul 2024 16:10:01 +0200 Subject: [PATCH 2/3] Rename files --- .../with_filter/{with_nin_blob_test.go => with_in_blob_test.go} | 1 - .../with_filter/{with_nin_json_test.go => with_in_json_test.go} | 0 2 files changed, 1 deletion(-) rename tests/integration/query/simple/with_filter/{with_nin_blob_test.go => with_in_blob_test.go} (93%) rename tests/integration/query/simple/with_filter/{with_nin_json_test.go => with_in_json_test.go} (100%) diff --git a/tests/integration/query/simple/with_filter/with_nin_blob_test.go b/tests/integration/query/simple/with_filter/with_in_blob_test.go similarity index 93% rename from tests/integration/query/simple/with_filter/with_nin_blob_test.go rename to tests/integration/query/simple/with_filter/with_in_blob_test.go index b2d70ace16..a168a297ac 100644 --- a/tests/integration/query/simple/with_filter/with_nin_blob_test.go +++ b/tests/integration/query/simple/with_filter/with_in_blob_test.go @@ -40,7 +40,6 @@ func TestQuerySimple_WithInOpOnBlobField_ShouldFilter(t *testing.T) { }`, }, testUtils.Request{ - // the filtered-by JSON has no spaces, because this is now it's stored. Request: `query { Users(filter: {data: {_in: ["00FF99AA"]}}) { name diff --git a/tests/integration/query/simple/with_filter/with_nin_json_test.go b/tests/integration/query/simple/with_filter/with_in_json_test.go similarity index 100% rename from tests/integration/query/simple/with_filter/with_nin_json_test.go rename to tests/integration/query/simple/with_filter/with_in_json_test.go From 2e61ab047d49c00ade5851bb73eca5d11d483600 Mon Sep 17 00:00:00 2001 From: Islam Aleiv Date: Tue, 16 Jul 2024 22:29:45 +0200 Subject: [PATCH 3/3] Get rid of global gql scalar variables --- .../request/graphql/schema/descriptions.go | 4 +- internal/request/graphql/schema/manager.go | 15 ++++--- internal/request/graphql/schema/types/base.go | 40 +++++++++---------- .../request/graphql/schema/types/scalars.go | 8 +--- .../graphql/schema/types/scalars_test.go | 12 +++--- 5 files changed, 39 insertions(+), 40 deletions(-) diff --git a/internal/request/graphql/schema/descriptions.go b/internal/request/graphql/schema/descriptions.go index 8fccff2fb0..526e41470e 100644 --- a/internal/request/graphql/schema/descriptions.go +++ b/internal/request/graphql/schema/descriptions.go @@ -33,8 +33,8 @@ var ( client.FieldKind_NILLABLE_STRING: gql.String, client.FieldKind_STRING_ARRAY: gql.NewList(gql.NewNonNull(gql.String)), client.FieldKind_NILLABLE_STRING_ARRAY: gql.NewList(gql.String), - client.FieldKind_NILLABLE_BLOB: schemaTypes.BlobScalarType, - client.FieldKind_NILLABLE_JSON: schemaTypes.JSONScalarType, + client.FieldKind_NILLABLE_BLOB: schemaTypes.BlobScalarType(), + client.FieldKind_NILLABLE_JSON: schemaTypes.JSONScalarType(), } defaultCRDTForFieldKind = map[client.FieldKind]client.CType{ diff --git a/internal/request/graphql/schema/manager.go b/internal/request/graphql/schema/manager.go index 7009ee2e3f..d409fe96b5 100644 --- a/internal/request/graphql/schema/manager.go +++ b/internal/request/graphql/schema/manager.go @@ -166,6 +166,9 @@ func defaultTypes( crdtEnum *gql.Enum, explainEnum *gql.Enum, ) []gql.Type { + blobScalarType := schemaTypes.BlobScalarType() + jsonScalarType := schemaTypes.JSONScalarType() + return []gql.Type{ // Base Scalar types gql.Boolean, @@ -176,8 +179,8 @@ func defaultTypes( gql.String, // Custom Scalar types - schemaTypes.BlobScalarType, - schemaTypes.JSONScalarType, + blobScalarType, + jsonScalarType, // Base Query types @@ -195,10 +198,10 @@ func defaultTypes( schemaTypes.NotNullIntOperatorBlock(), schemaTypes.StringOperatorBlock(), schemaTypes.NotNullstringOperatorBlock(), - schemaTypes.JSONOperatorBlock(), - schemaTypes.NotNullJSONOperatorBlock(), - schemaTypes.BlobOperatorBlock(), - schemaTypes.NotNullBlobOperatorBlock(), + schemaTypes.JSONOperatorBlock(jsonScalarType), + schemaTypes.NotNullJSONOperatorBlock(jsonScalarType), + schemaTypes.BlobOperatorBlock(blobScalarType), + schemaTypes.NotNullBlobOperatorBlock(blobScalarType), commitsOrderArg, commitLinkObject, diff --git a/internal/request/graphql/schema/types/base.go b/internal/request/graphql/schema/types/base.go index bcfa00e477..fd49fbb45a 100644 --- a/internal/request/graphql/schema/types/base.go +++ b/internal/request/graphql/schema/types/base.go @@ -361,26 +361,26 @@ func NotNullstringOperatorBlock() *gql.InputObject { } // JSONOperatorBlock filter block for string types. -func JSONOperatorBlock() *gql.InputObject { +func JSONOperatorBlock(jsonScalarType *gql.Scalar) *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ Name: "JSONOperatorBlock", Description: stringOperatorBlockDescription, Fields: gql.InputObjectConfigFieldMap{ "_eq": &gql.InputObjectFieldConfig{ Description: eqOperatorDescription, - Type: JSONScalarType, + Type: jsonScalarType, }, "_ne": &gql.InputObjectFieldConfig{ Description: neOperatorDescription, - Type: JSONScalarType, + Type: jsonScalarType, }, "_in": &gql.InputObjectFieldConfig{ Description: inOperatorDescription, - Type: gql.NewList(JSONScalarType), + Type: gql.NewList(jsonScalarType), }, "_nin": &gql.InputObjectFieldConfig{ Description: ninOperatorDescription, - Type: gql.NewList(JSONScalarType), + Type: gql.NewList(jsonScalarType), }, "_like": &gql.InputObjectFieldConfig{ Description: likeStringOperatorDescription, @@ -403,26 +403,26 @@ func JSONOperatorBlock() *gql.InputObject { } // NotNullJSONOperatorBlock filter block for string! types. -func NotNullJSONOperatorBlock() *gql.InputObject { +func NotNullJSONOperatorBlock(jsonScalarType *gql.Scalar) *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ Name: "NotNullJSONOperatorBlock", Description: notNullStringOperatorBlockDescription, Fields: gql.InputObjectConfigFieldMap{ "_eq": &gql.InputObjectFieldConfig{ Description: eqOperatorDescription, - Type: JSONScalarType, + Type: jsonScalarType, }, "_ne": &gql.InputObjectFieldConfig{ Description: neOperatorDescription, - Type: JSONScalarType, + Type: jsonScalarType, }, "_in": &gql.InputObjectFieldConfig{ Description: inOperatorDescription, - Type: gql.NewList(gql.NewNonNull(JSONScalarType)), + Type: gql.NewList(gql.NewNonNull(jsonScalarType)), }, "_nin": &gql.InputObjectFieldConfig{ Description: ninOperatorDescription, - Type: gql.NewList(gql.NewNonNull(JSONScalarType)), + Type: gql.NewList(gql.NewNonNull(jsonScalarType)), }, "_like": &gql.InputObjectFieldConfig{ Description: likeStringOperatorDescription, @@ -444,26 +444,26 @@ func NotNullJSONOperatorBlock() *gql.InputObject { }) } -func BlobOperatorBlock() *gql.InputObject { +func BlobOperatorBlock(blobScalarType *gql.Scalar) *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ Name: "BlobOperatorBlock", Description: stringOperatorBlockDescription, Fields: gql.InputObjectConfigFieldMap{ "_eq": &gql.InputObjectFieldConfig{ Description: eqOperatorDescription, - Type: BlobScalarType, + Type: blobScalarType, }, "_ne": &gql.InputObjectFieldConfig{ Description: neOperatorDescription, - Type: BlobScalarType, + Type: blobScalarType, }, "_in": &gql.InputObjectFieldConfig{ Description: inOperatorDescription, - Type: gql.NewList(BlobScalarType), + Type: gql.NewList(blobScalarType), }, "_nin": &gql.InputObjectFieldConfig{ Description: ninOperatorDescription, - Type: gql.NewList(BlobScalarType), + Type: gql.NewList(blobScalarType), }, "_like": &gql.InputObjectFieldConfig{ Description: likeStringOperatorDescription, @@ -486,26 +486,26 @@ func BlobOperatorBlock() *gql.InputObject { } // NotNullJSONOperatorBlock filter block for string! types. -func NotNullBlobOperatorBlock() *gql.InputObject { +func NotNullBlobOperatorBlock(blobScalarType *gql.Scalar) *gql.InputObject { return gql.NewInputObject(gql.InputObjectConfig{ Name: "NotNullBlobOperatorBlock", Description: notNullStringOperatorBlockDescription, Fields: gql.InputObjectConfigFieldMap{ "_eq": &gql.InputObjectFieldConfig{ Description: eqOperatorDescription, - Type: BlobScalarType, + Type: blobScalarType, }, "_ne": &gql.InputObjectFieldConfig{ Description: neOperatorDescription, - Type: BlobScalarType, + Type: blobScalarType, }, "_in": &gql.InputObjectFieldConfig{ Description: inOperatorDescription, - Type: gql.NewList(gql.NewNonNull(BlobScalarType)), + Type: gql.NewList(gql.NewNonNull(blobScalarType)), }, "_nin": &gql.InputObjectFieldConfig{ Description: ninOperatorDescription, - Type: gql.NewList(gql.NewNonNull(BlobScalarType)), + Type: gql.NewList(gql.NewNonNull(blobScalarType)), }, "_like": &gql.InputObjectFieldConfig{ Description: likeStringOperatorDescription, diff --git a/internal/request/graphql/schema/types/scalars.go b/internal/request/graphql/schema/types/scalars.go index a57fe5ae67..b86c744607 100644 --- a/internal/request/graphql/schema/types/scalars.go +++ b/internal/request/graphql/schema/types/scalars.go @@ -46,7 +46,7 @@ func coerceBlob(value any) any { } } -func NewBlobScalarType() *graphql.Scalar { +func BlobScalarType() *graphql.Scalar { return graphql.NewScalar(graphql.ScalarConfig{ Name: "Blob", Description: "The `Blob` scalar type represents a binary large object.", @@ -67,8 +67,6 @@ func NewBlobScalarType() *graphql.Scalar { }) } -var BlobScalarType = NewBlobScalarType() - // coerceJSON converts the given value into a valid json string. // If the value cannot be converted nil is returned. func coerceJSON(value any) any { @@ -102,7 +100,7 @@ func coerceJSON(value any) any { } } -func NewJSONScalarType() *graphql.Scalar { +func JSONScalarType() *graphql.Scalar { return graphql.NewScalar(graphql.ScalarConfig{ Name: "JSON", Description: "The `JSON` scalar type represents a JSON string.", @@ -122,5 +120,3 @@ func NewJSONScalarType() *graphql.Scalar { }, }) } - -var JSONScalarType = NewJSONScalarType() diff --git a/internal/request/graphql/schema/types/scalars_test.go b/internal/request/graphql/schema/types/scalars_test.go index f7fe5ed4ec..fba94ce67b 100644 --- a/internal/request/graphql/schema/types/scalars_test.go +++ b/internal/request/graphql/schema/types/scalars_test.go @@ -34,7 +34,7 @@ func TestBlobScalarTypeSerialize(t *testing.T) { {false, nil}, } for _, c := range cases { - result := NewBlobScalarType().Serialize(c.input) + result := BlobScalarType().Serialize(c.input) assert.Equal(t, c.expect, result) } } @@ -60,7 +60,7 @@ func TestBlobScalarTypeParseValue(t *testing.T) { {false, nil}, } for _, c := range cases { - result := NewBlobScalarType().ParseValue(c.input) + result := BlobScalarType().ParseValue(c.input) assert.Equal(t, c.expect, result) } } @@ -82,7 +82,7 @@ func TestBlobScalarTypeParseLiteral(t *testing.T) { {&ast.ObjectValue{}, nil}, } for _, c := range cases { - result := NewBlobScalarType().ParseLiteral(c.input) + result := BlobScalarType().ParseLiteral(c.input) assert.Equal(t, c.expect, result) } } @@ -141,10 +141,10 @@ func TestJSONScalarTypeParseAndSerialize(t *testing.T) { {false, nil}, } for _, c := range cases { - parsed := JSONScalarType.ParseValue(c.input) + parsed := JSONScalarType().ParseValue(c.input) assert.Equal(t, c.expect, parsed) - serialized := JSONScalarType.Serialize(c.input) + serialized := JSONScalarType().Serialize(c.input) assert.Equal(t, c.expect, serialized) } } @@ -165,7 +165,7 @@ func TestJSONScalarTypeParseLiteral(t *testing.T) { {&ast.ObjectValue{}, nil}, } for _, c := range cases { - result := JSONScalarType.ParseLiteral(c.input) + result := JSONScalarType().ParseLiteral(c.input) assert.Equal(t, c.expect, result) } }