From cc801b53eba969f1da4274ab4c81160d3b26327a Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Tue, 28 Nov 2023 11:44:00 -0800 Subject: [PATCH 01/16] add bytes scalar definition --- client/descriptions.go | 3 +- request/graphql/schema/collection.go | 3 ++ request/graphql/schema/descriptions.go | 20 ++++---- request/graphql/schema/manager.go | 3 ++ request/graphql/schema/types/scalars.go | 61 +++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 request/graphql/schema/types/scalars.go diff --git a/client/descriptions.go b/client/descriptions.go index f9a262e438..8fb54d8792 100644 --- a/client/descriptions.go +++ b/client/descriptions.go @@ -166,7 +166,7 @@ const ( FieldKind_DATETIME FieldKind = 10 FieldKind_STRING FieldKind = 11 FieldKind_STRING_ARRAY FieldKind = 12 - _ FieldKind = 13 // safe to repurpose (was never used) + FieldKind_BYTES FieldKind = 13 _ FieldKind = 14 // safe to repurpose (was never used) _ FieldKind = 15 // safe to repurpose (was never used) @@ -204,6 +204,7 @@ var FieldKindStringToEnumMapping = map[string]FieldKind{ "String": FieldKind_STRING, "[String]": FieldKind_NILLABLE_STRING_ARRAY, "[String!]": FieldKind_STRING_ARRAY, + "Bytes": FieldKind_BYTES, } // RelationType describes the type of relation between two types. diff --git a/request/graphql/schema/collection.go b/request/graphql/schema/collection.go index 15a6283acb..41b5b54f74 100644 --- a/request/graphql/schema/collection.go +++ b/request/graphql/schema/collection.go @@ -331,6 +331,7 @@ func astTypeToKind(t ast.Type) (client.FieldKind, error) { typeFloat string = "Float" typeDateTime string = "DateTime" typeString string = "String" + typeBytes string = "Bytes" ) switch astTypeVal := t.(type) { @@ -379,6 +380,8 @@ func astTypeToKind(t ast.Type) (client.FieldKind, error) { return client.FieldKind_DATETIME, nil case typeString: return client.FieldKind_STRING, nil + case typeBytes: + return client.FieldKind_BYTES, nil default: return client.FieldKind_FOREIGN_OBJECT, nil } diff --git a/request/graphql/schema/descriptions.go b/request/graphql/schema/descriptions.go index 1aabee729e..f195f67cdf 100644 --- a/request/graphql/schema/descriptions.go +++ b/request/graphql/schema/descriptions.go @@ -14,6 +14,7 @@ import ( gql "github.com/sourcenetwork/graphql-go" "github.com/sourcenetwork/defradb/client" + schemaTypes "github.com/sourcenetwork/defradb/request/graphql/schema/types" ) var ( @@ -23,14 +24,15 @@ var ( //nolint:unused gqlTypeToFieldKindReference = map[gql.Type]client.FieldKind{ - gql.ID: client.FieldKind_DocKey, - gql.Boolean: client.FieldKind_BOOL, - gql.Int: client.FieldKind_INT, - gql.Float: client.FieldKind_FLOAT, - gql.DateTime: client.FieldKind_DATETIME, - gql.String: client.FieldKind_STRING, - &gql.Object{}: client.FieldKind_FOREIGN_OBJECT, - &gql.List{}: client.FieldKind_FOREIGN_OBJECT_ARRAY, + gql.ID: client.FieldKind_DocKey, + gql.Boolean: client.FieldKind_BOOL, + gql.Int: client.FieldKind_INT, + gql.Float: client.FieldKind_FLOAT, + gql.DateTime: client.FieldKind_DATETIME, + gql.String: client.FieldKind_STRING, + &gql.Object{}: client.FieldKind_FOREIGN_OBJECT, + &gql.List{}: client.FieldKind_FOREIGN_OBJECT_ARRAY, + schemaTypes.BytesScalarType: client.FieldKind_BYTES, // More custom ones to come // - JSON // - ByteArray @@ -52,6 +54,7 @@ var ( client.FieldKind_STRING: gql.String, client.FieldKind_STRING_ARRAY: gql.NewList(gql.NewNonNull(gql.String)), client.FieldKind_NILLABLE_STRING_ARRAY: gql.NewList(gql.String), + client.FieldKind_BYTES: schemaTypes.BytesScalarType, } // This map is fine to use @@ -70,6 +73,7 @@ var ( client.FieldKind_STRING: client.LWW_REGISTER, client.FieldKind_STRING_ARRAY: client.LWW_REGISTER, client.FieldKind_NILLABLE_STRING_ARRAY: client.LWW_REGISTER, + client.FieldKind_BYTES: client.LWW_REGISTER, client.FieldKind_FOREIGN_OBJECT: client.NONE_CRDT, client.FieldKind_FOREIGN_OBJECT_ARRAY: client.NONE_CRDT, } diff --git a/request/graphql/schema/manager.go b/request/graphql/schema/manager.go index 0f96ec2a29..e9296a0322 100644 --- a/request/graphql/schema/manager.go +++ b/request/graphql/schema/manager.go @@ -141,6 +141,9 @@ func defaultTypes() []gql.Type { gql.Int, gql.String, + // Custom Scalar types + schemaTypes.BytesScalarType, + // Base Query types // Sort/Order enum diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go new file mode 100644 index 0000000000..4664dcc5f4 --- /dev/null +++ b/request/graphql/schema/types/scalars.go @@ -0,0 +1,61 @@ +// Copyright 2023 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 types + +import ( + "encoding/hex" + + "github.com/sourcenetwork/graphql-go" + "github.com/sourcenetwork/graphql-go/language/ast" +) + +var BytesScalarType = graphql.NewScalar(graphql.ScalarConfig{ + Name: "Bytes", + Description: "The `Bytes` scalar type represents an array of bytes.", + Serialize: func(value any) any { + switch value := value.(type) { + case []byte: + return hex.EncodeToString(value) + default: + return nil + } + }, + ParseValue: func(value any) any { + switch value := value.(type) { + case string: + data, err := hex.DecodeString(value) + if err != nil { + return nil + } + return data + case *string: + data, err := hex.DecodeString(*value) + if err != nil { + return nil + } + return data + default: + return nil + } + }, + ParseLiteral: func(valueAST ast.Value) any { + switch valueAST := valueAST.(type) { + case *ast.StringValue: + data, err := hex.DecodeString(valueAST.Value) + if err != nil { + return nil + } + return data + default: + return nil + } + }, +}) From d4ebf91a2796410016291814f546a7df11b683a3 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Tue, 28 Nov 2023 11:44:12 -0800 Subject: [PATCH 02/16] add bytes scalar tests --- .../mutation/update/field_kinds/bytes_test.go | 60 +++++++++++++++++++ tests/integration/schema/simple_test.go | 46 ++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 tests/integration/mutation/update/field_kinds/bytes_test.go diff --git a/tests/integration/mutation/update/field_kinds/bytes_test.go b/tests/integration/mutation/update/field_kinds/bytes_test.go new file mode 100644 index 0000000000..d74db363c8 --- /dev/null +++ b/tests/integration/mutation/update/field_kinds/bytes_test.go @@ -0,0 +1,60 @@ +// Copyright 2023 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 field_kinds + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestMutationUpdate_WithBytesField(t *testing.T) { + test := testUtils.TestCase{ + Description: "Simple update of bytes field", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + data: Bytes + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John", + "data": "00FE" + }`, + }, + testUtils.UpdateDoc{ + Doc: `{ + "data": "00FF" + }`, + }, + testUtils.Request{ + Request: ` + query { + Users { + data + } + } + `, + Results: []map[string]any{ + { + "data": "00FF", + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/schema/simple_test.go b/tests/integration/schema/simple_test.go index 6bcb2a1dec..306e0614e5 100644 --- a/tests/integration/schema/simple_test.go +++ b/tests/integration/schema/simple_test.go @@ -271,3 +271,49 @@ func TestSchemaSimpleErrorsGivenNonNullManyRelationField(t *testing.T) { testUtils.ExecuteTestCase(t, test) } + +func TestSchemaSimpleCreatesSchemaGivenTypeWithBytesField(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + data: Bytes + } + `, + }, + testUtils.IntrospectionRequest{ + Request: ` + query { + __type (name: "Users") { + name + fields { + name + type { + name + kind + } + } + } + } + `, + ExpectedData: map[string]any{ + "__type": map[string]any{ + "name": "Users", + "fields": DefaultFields.Append( + Field{ + "name": "data", + "type": map[string]any{ + "kind": "SCALAR", + "name": "Bytes", + }, + }, + ).Tidy(), + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} From 70bf6c3b992684fa013dfd66950e1e6bdfe5e3eb Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Tue, 28 Nov 2023 12:00:19 -0800 Subject: [PATCH 03/16] remove invalid field type 13 test --- .../updates/add/field/kind/invalid_test.go | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/tests/integration/schema/updates/add/field/kind/invalid_test.go b/tests/integration/schema/updates/add/field/kind/invalid_test.go index 5e578e5307..98f026ecc2 100644 --- a/tests/integration/schema/updates/add/field/kind/invalid_test.go +++ b/tests/integration/schema/updates/add/field/kind/invalid_test.go @@ -64,30 +64,6 @@ func TestSchemaUpdatesAddFieldKind9(t *testing.T) { testUtils.ExecuteTestCase(t, test) } -func TestSchemaUpdatesAddFieldKind13(t *testing.T) { - test := testUtils.TestCase{ - Description: "Test schema update, add field with kind deprecated (13)", - Actions: []any{ - testUtils.SchemaUpdate{ - Schema: ` - type Users { - name: String - } - `, - }, - testUtils.SchemaPatch{ - Patch: ` - [ - { "op": "add", "path": "/Users/Fields/-", "value": {"Name": "foo", "Kind": 13} } - ] - `, - ExpectedError: "no type found for given name. Type: 13", - }, - }, - } - testUtils.ExecuteTestCase(t, test) -} - func TestSchemaUpdatesAddFieldKind14(t *testing.T) { test := testUtils.TestCase{ Description: "Test schema update, add field with kind deprecated (14)", From 92dce71c63798e56ce2110e8f0ee21826fcd9518 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Tue, 28 Nov 2023 13:57:19 -0800 Subject: [PATCH 04/16] add missing field definition to validateFieldSchema --- db/collection_update.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/collection_update.go b/db/collection_update.go index c68902db44..1ca6983676 100644 --- a/db/collection_update.go +++ b/db/collection_update.go @@ -470,6 +470,9 @@ func validateFieldSchema(val *fastjson.Value, field client.FieldDescription) (an case client.FieldKind_FOREIGN_OBJECT, client.FieldKind_FOREIGN_OBJECT_ARRAY: return nil, NewErrFieldOrAliasToFieldNotExist(field.Name) + + case client.FieldKind_BYTES: + return getString(val) } return nil, client.NewErrUnhandledType("FieldKind", field.Kind) From d03da826e82644e598dd271e87c25dad001b9675 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Wed, 29 Nov 2023 09:43:59 -0800 Subject: [PATCH 05/16] add comment to type descriptions --- request/graphql/schema/descriptions.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/request/graphql/schema/descriptions.go b/request/graphql/schema/descriptions.go index f195f67cdf..edb55adbfe 100644 --- a/request/graphql/schema/descriptions.go +++ b/request/graphql/schema/descriptions.go @@ -24,18 +24,18 @@ var ( //nolint:unused gqlTypeToFieldKindReference = map[gql.Type]client.FieldKind{ - gql.ID: client.FieldKind_DocKey, - gql.Boolean: client.FieldKind_BOOL, - gql.Int: client.FieldKind_INT, - gql.Float: client.FieldKind_FLOAT, - gql.DateTime: client.FieldKind_DATETIME, - gql.String: client.FieldKind_STRING, - &gql.Object{}: client.FieldKind_FOREIGN_OBJECT, - &gql.List{}: client.FieldKind_FOREIGN_OBJECT_ARRAY, + gql.ID: client.FieldKind_DocKey, + gql.Boolean: client.FieldKind_BOOL, + gql.Int: client.FieldKind_INT, + gql.Float: client.FieldKind_FLOAT, + gql.DateTime: client.FieldKind_DATETIME, + gql.String: client.FieldKind_STRING, + &gql.Object{}: client.FieldKind_FOREIGN_OBJECT, + &gql.List{}: client.FieldKind_FOREIGN_OBJECT_ARRAY, + // Custom scalars schemaTypes.BytesScalarType: client.FieldKind_BYTES, // More custom ones to come // - JSON - // - ByteArray // - Counters } From 212dfec8c25519fc2c234918385bd35cc85f681e Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Wed, 29 Nov 2023 10:16:02 -0800 Subject: [PATCH 06/16] add scalar unit tests --- request/graphql/schema/types/scalars.go | 2 + request/graphql/schema/types/scalars_test.go | 82 ++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 request/graphql/schema/types/scalars_test.go diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index 4664dcc5f4..b38e39f9b3 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -24,6 +24,8 @@ var BytesScalarType = graphql.NewScalar(graphql.ScalarConfig{ switch value := value.(type) { case []byte: return hex.EncodeToString(value) + case *[]byte: + return hex.EncodeToString(*value) default: return nil } diff --git a/request/graphql/schema/types/scalars_test.go b/request/graphql/schema/types/scalars_test.go new file mode 100644 index 0000000000..2805cddd71 --- /dev/null +++ b/request/graphql/schema/types/scalars_test.go @@ -0,0 +1,82 @@ +// Copyright 2023 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 types + +import ( + "testing" + + "github.com/sourcenetwork/graphql-go/language/ast" + "github.com/stretchr/testify/assert" +) + +func TestBytesScalarTypeSerialize(t *testing.T) { + input := []byte{0, 255} + output := "00ff" + + cases := []struct { + input any + expect any + }{ + {input, output}, + {&input, output}, + {nil, nil}, + {0, nil}, + {false, nil}, + } + for _, c := range cases { + result := BytesScalarType.Serialize(c.input) + assert.Equal(t, c.expect, result) + } +} + +func TestBytesScalarTypeParseValue(t *testing.T) { + input := "00ff" + output := []byte{0, 255} + invalid := "invalid" + + cases := []struct { + input any + expect any + }{ + {input, output}, + {&input, output}, + {invalid, nil}, + {&invalid, nil}, + {nil, nil}, + {0, nil}, + {false, nil}, + } + for _, c := range cases { + result := BytesScalarType.ParseValue(c.input) + assert.Equal(t, c.expect, result) + } +} + +func TestBytesScalarTypeParseLiteral(t *testing.T) { + cases := []struct { + input ast.Value + expect any + }{ + {&ast.StringValue{Value: "00ff"}, []byte{0, 255}}, + {&ast.StringValue{Value: "invalid"}, nil}, + {&ast.IntValue{}, nil}, + {&ast.BooleanValue{}, nil}, + {&ast.NullValue{}, nil}, + {&ast.EnumValue{}, nil}, + {&ast.FloatValue{}, nil}, + {&ast.ListValue{}, nil}, + {&ast.ObjectValue{}, nil}, + } + for _, c := range cases { + result := BytesScalarType.ParseLiteral(c.input) + assert.Equal(t, c.expect, result) + } +} From da25d3cffd18f8f47a40f617f997ff93c5462f22 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Fri, 1 Dec 2023 10:02:48 -0800 Subject: [PATCH 07/16] rename bytes type to blob --- client/descriptions.go | 4 ++-- db/collection_update.go | 2 +- db/index.go | 2 ++ request/graphql/schema/collection.go | 6 +++--- request/graphql/schema/descriptions.go | 6 +++--- request/graphql/schema/manager.go | 2 +- request/graphql/schema/types/scalars.go | 6 +++--- request/graphql/schema/types/scalars_test.go | 12 ++++++------ .../mutation/update/field_kinds/bytes_test.go | 6 +++--- tests/integration/schema/simple_test.go | 6 +++--- 10 files changed, 27 insertions(+), 25 deletions(-) diff --git a/client/descriptions.go b/client/descriptions.go index 8fb54d8792..6ef29cebaa 100644 --- a/client/descriptions.go +++ b/client/descriptions.go @@ -166,7 +166,7 @@ const ( FieldKind_DATETIME FieldKind = 10 FieldKind_STRING FieldKind = 11 FieldKind_STRING_ARRAY FieldKind = 12 - FieldKind_BYTES FieldKind = 13 + FieldKind_BLOB FieldKind = 13 _ FieldKind = 14 // safe to repurpose (was never used) _ FieldKind = 15 // safe to repurpose (was never used) @@ -204,7 +204,7 @@ var FieldKindStringToEnumMapping = map[string]FieldKind{ "String": FieldKind_STRING, "[String]": FieldKind_NILLABLE_STRING_ARRAY, "[String!]": FieldKind_STRING_ARRAY, - "Bytes": FieldKind_BYTES, + "Blob": FieldKind_BLOB, } // RelationType describes the type of relation between two types. diff --git a/db/collection_update.go b/db/collection_update.go index 1ca6983676..e6dbc4617a 100644 --- a/db/collection_update.go +++ b/db/collection_update.go @@ -471,7 +471,7 @@ func validateFieldSchema(val *fastjson.Value, field client.FieldDescription) (an case client.FieldKind_FOREIGN_OBJECT, client.FieldKind_FOREIGN_OBJECT_ARRAY: return nil, NewErrFieldOrAliasToFieldNotExist(field.Name) - case client.FieldKind_BYTES: + case client.FieldKind_BLOB: return getString(val) } diff --git a/db/index.go b/db/index.go index ce9e55f519..4bd62f6ae3 100644 --- a/db/index.go +++ b/db/index.go @@ -51,6 +51,8 @@ func getValidateIndexFieldFunc(kind client.FieldKind) func(any) bool { return canConvertIndexFieldValue[float64] case client.FieldKind_BOOL: return canConvertIndexFieldValue[bool] + case client.FieldKind_BLOB: + return canConvertIndexFieldValue[string] case client.FieldKind_DATETIME: return func(val any) bool { timeStrVal, ok := val.(string) diff --git a/request/graphql/schema/collection.go b/request/graphql/schema/collection.go index 41b5b54f74..ed77a9d614 100644 --- a/request/graphql/schema/collection.go +++ b/request/graphql/schema/collection.go @@ -331,7 +331,7 @@ func astTypeToKind(t ast.Type) (client.FieldKind, error) { typeFloat string = "Float" typeDateTime string = "DateTime" typeString string = "String" - typeBytes string = "Bytes" + typeBlob string = "Blob" ) switch astTypeVal := t.(type) { @@ -380,8 +380,8 @@ func astTypeToKind(t ast.Type) (client.FieldKind, error) { return client.FieldKind_DATETIME, nil case typeString: return client.FieldKind_STRING, nil - case typeBytes: - return client.FieldKind_BYTES, nil + case typeBlob: + return client.FieldKind_BLOB, nil default: return client.FieldKind_FOREIGN_OBJECT, nil } diff --git a/request/graphql/schema/descriptions.go b/request/graphql/schema/descriptions.go index edb55adbfe..f267ae8ed0 100644 --- a/request/graphql/schema/descriptions.go +++ b/request/graphql/schema/descriptions.go @@ -33,7 +33,7 @@ var ( &gql.Object{}: client.FieldKind_FOREIGN_OBJECT, &gql.List{}: client.FieldKind_FOREIGN_OBJECT_ARRAY, // Custom scalars - schemaTypes.BytesScalarType: client.FieldKind_BYTES, + schemaTypes.BlobScalarType: client.FieldKind_BLOB, // More custom ones to come // - JSON // - Counters @@ -54,7 +54,7 @@ var ( client.FieldKind_STRING: gql.String, client.FieldKind_STRING_ARRAY: gql.NewList(gql.NewNonNull(gql.String)), client.FieldKind_NILLABLE_STRING_ARRAY: gql.NewList(gql.String), - client.FieldKind_BYTES: schemaTypes.BytesScalarType, + client.FieldKind_BLOB: schemaTypes.BlobScalarType, } // This map is fine to use @@ -73,7 +73,7 @@ var ( client.FieldKind_STRING: client.LWW_REGISTER, client.FieldKind_STRING_ARRAY: client.LWW_REGISTER, client.FieldKind_NILLABLE_STRING_ARRAY: client.LWW_REGISTER, - client.FieldKind_BYTES: client.LWW_REGISTER, + client.FieldKind_BLOB: client.LWW_REGISTER, client.FieldKind_FOREIGN_OBJECT: client.NONE_CRDT, client.FieldKind_FOREIGN_OBJECT_ARRAY: client.NONE_CRDT, } diff --git a/request/graphql/schema/manager.go b/request/graphql/schema/manager.go index e9296a0322..f44b770fcb 100644 --- a/request/graphql/schema/manager.go +++ b/request/graphql/schema/manager.go @@ -142,7 +142,7 @@ func defaultTypes() []gql.Type { gql.String, // Custom Scalar types - schemaTypes.BytesScalarType, + schemaTypes.BlobScalarType, // Base Query types diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index b38e39f9b3..3bed22fdf0 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -17,9 +17,9 @@ import ( "github.com/sourcenetwork/graphql-go/language/ast" ) -var BytesScalarType = graphql.NewScalar(graphql.ScalarConfig{ - Name: "Bytes", - Description: "The `Bytes` scalar type represents an array of bytes.", +var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ + Name: "Blob", + Description: "The `Blob` scalar type represents a binary large object.", Serialize: func(value any) any { switch value := value.(type) { case []byte: diff --git a/request/graphql/schema/types/scalars_test.go b/request/graphql/schema/types/scalars_test.go index 2805cddd71..43a9c6a737 100644 --- a/request/graphql/schema/types/scalars_test.go +++ b/request/graphql/schema/types/scalars_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestBytesScalarTypeSerialize(t *testing.T) { +func TestBlobScalarTypeSerialize(t *testing.T) { input := []byte{0, 255} output := "00ff" @@ -32,12 +32,12 @@ func TestBytesScalarTypeSerialize(t *testing.T) { {false, nil}, } for _, c := range cases { - result := BytesScalarType.Serialize(c.input) + result := BlobScalarType.Serialize(c.input) assert.Equal(t, c.expect, result) } } -func TestBytesScalarTypeParseValue(t *testing.T) { +func TestBlobScalarTypeParseValue(t *testing.T) { input := "00ff" output := []byte{0, 255} invalid := "invalid" @@ -55,12 +55,12 @@ func TestBytesScalarTypeParseValue(t *testing.T) { {false, nil}, } for _, c := range cases { - result := BytesScalarType.ParseValue(c.input) + result := BlobScalarType.ParseValue(c.input) assert.Equal(t, c.expect, result) } } -func TestBytesScalarTypeParseLiteral(t *testing.T) { +func TestBlobScalarTypeParseLiteral(t *testing.T) { cases := []struct { input ast.Value expect any @@ -76,7 +76,7 @@ func TestBytesScalarTypeParseLiteral(t *testing.T) { {&ast.ObjectValue{}, nil}, } for _, c := range cases { - result := BytesScalarType.ParseLiteral(c.input) + result := BlobScalarType.ParseLiteral(c.input) assert.Equal(t, c.expect, result) } } diff --git a/tests/integration/mutation/update/field_kinds/bytes_test.go b/tests/integration/mutation/update/field_kinds/bytes_test.go index d74db363c8..4445c45bba 100644 --- a/tests/integration/mutation/update/field_kinds/bytes_test.go +++ b/tests/integration/mutation/update/field_kinds/bytes_test.go @@ -16,15 +16,15 @@ import ( testUtils "github.com/sourcenetwork/defradb/tests/integration" ) -func TestMutationUpdate_WithBytesField(t *testing.T) { +func TestMutationUpdate_WithBlobField(t *testing.T) { test := testUtils.TestCase{ - Description: "Simple update of bytes field", + Description: "Simple update of blob field", Actions: []any{ testUtils.SchemaUpdate{ Schema: ` type Users { name: String - data: Bytes + data: Blob } `, }, diff --git a/tests/integration/schema/simple_test.go b/tests/integration/schema/simple_test.go index 306e0614e5..9fa0eb021a 100644 --- a/tests/integration/schema/simple_test.go +++ b/tests/integration/schema/simple_test.go @@ -272,13 +272,13 @@ func TestSchemaSimpleErrorsGivenNonNullManyRelationField(t *testing.T) { testUtils.ExecuteTestCase(t, test) } -func TestSchemaSimpleCreatesSchemaGivenTypeWithBytesField(t *testing.T) { +func TestSchemaSimpleCreatesSchemaGivenTypeWithBlobField(t *testing.T) { test := testUtils.TestCase{ Actions: []any{ testUtils.SchemaUpdate{ Schema: ` type Users { - data: Bytes + data: Blob } `, }, @@ -305,7 +305,7 @@ func TestSchemaSimpleCreatesSchemaGivenTypeWithBytesField(t *testing.T) { "name": "data", "type": map[string]any{ "kind": "SCALAR", - "name": "Bytes", + "name": "Blob", }, }, ).Tidy(), From cf090ae8298b73ad05460a5927f085dc30e21ed0 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Fri, 1 Dec 2023 10:19:31 -0800 Subject: [PATCH 08/16] add comments to scalar functions and tests --- request/graphql/schema/types/scalars.go | 10 ++++++++++ request/graphql/schema/types/scalars_test.go | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index 3bed22fdf0..3a2e129cb5 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -27,6 +27,7 @@ var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ case *[]byte: return hex.EncodeToString(*value) default: + // return nil if the value cannot be serialized return nil } }, @@ -41,6 +42,10 @@ var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ case *string: data, err := hex.DecodeString(*value) if err != nil { + // the error cannot be handled due to + // the design of graphql-go scalars + // + // return nil if the value cannot be parsed return nil } return data @@ -53,10 +58,15 @@ var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ case *ast.StringValue: data, err := hex.DecodeString(valueAST.Value) if err != nil { + // the error cannot be handled due to + // the design of graphql-go scalars + // + // return nil if the value cannot be parsed return nil } return data default: + // return nil if the value cannot be parsed return nil } }, diff --git a/request/graphql/schema/types/scalars_test.go b/request/graphql/schema/types/scalars_test.go index 43a9c6a737..4b37ff9cfc 100644 --- a/request/graphql/schema/types/scalars_test.go +++ b/request/graphql/schema/types/scalars_test.go @@ -40,7 +40,8 @@ func TestBlobScalarTypeSerialize(t *testing.T) { func TestBlobScalarTypeParseValue(t *testing.T) { input := "00ff" output := []byte{0, 255} - invalid := "invalid" + // invalid string containing non-hex characters + invalid := "!@#$%^&*" cases := []struct { input any @@ -66,7 +67,7 @@ func TestBlobScalarTypeParseLiteral(t *testing.T) { expect any }{ {&ast.StringValue{Value: "00ff"}, []byte{0, 255}}, - {&ast.StringValue{Value: "invalid"}, nil}, + {&ast.StringValue{Value: "!@#$%^&*"}, nil}, {&ast.IntValue{}, nil}, {&ast.BooleanValue{}, nil}, {&ast.NullValue{}, nil}, From 9cb51fc90b18902b1fe211529178e1959d46bea9 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Fri, 1 Dec 2023 10:34:18 -0800 Subject: [PATCH 09/16] add scalar func documentation --- request/graphql/schema/types/scalars.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index 3a2e129cb5..ddea1570ed 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -20,6 +20,7 @@ import ( var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ Name: "Blob", Description: "The `Blob` scalar type represents a binary large object.", + // Serialize converts the value to the serialized hex representation Serialize: func(value any) any { switch value := value.(type) { case []byte: @@ -31,6 +32,7 @@ var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ return nil } }, + // ParseValue converts the serialized value to the []byte representation ParseValue: func(value any) any { switch value := value.(type) { case string: @@ -53,6 +55,7 @@ var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ return nil } }, + // ParseLiteral converts the ast value to the []byte representation ParseLiteral: func(valueAST ast.Value) any { switch valueAST := valueAST.(type) { case *ast.StringValue: From d67c1beccc5dc380b6a6b0cc0251a26d3b0a2e2e Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Fri, 1 Dec 2023 10:45:51 -0800 Subject: [PATCH 10/16] add schema patch test --- .../{bytes_test.go => blob_test.go} | 0 .../updates/add/field/kind/blob_test.go | 137 ++++++++++++++++++ 2 files changed, 137 insertions(+) rename tests/integration/mutation/update/field_kinds/{bytes_test.go => blob_test.go} (100%) create mode 100644 tests/integration/schema/updates/add/field/kind/blob_test.go diff --git a/tests/integration/mutation/update/field_kinds/bytes_test.go b/tests/integration/mutation/update/field_kinds/blob_test.go similarity index 100% rename from tests/integration/mutation/update/field_kinds/bytes_test.go rename to tests/integration/mutation/update/field_kinds/blob_test.go diff --git a/tests/integration/schema/updates/add/field/kind/blob_test.go b/tests/integration/schema/updates/add/field/kind/blob_test.go new file mode 100644 index 0000000000..badbdc56fe --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/blob_test.go @@ -0,0 +1,137 @@ +// Copyright 2023 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 kind + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesAddFieldKindBlob(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind blob (13)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Fields/-", "value": {"Name": "foo", "Kind": 13} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + name + foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestSchemaUpdatesAddFieldKindBlobWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind blob (13) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Fields/-", "value": {"Name": "foo", "Kind": 13} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "name": "John", + "foo": "00ff" + }`, + }, + testUtils.Request{ + Request: `query { + Users { + name + foo + } + }`, + Results: []map[string]any{ + { + "name": "John", + "foo": "00ff", + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} + +func TestSchemaUpdatesAddFieldKindBlobSubstitutionWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind blob substitution with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Fields/-", "value": {"Name": "foo", "Kind": "Blob"} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "name": "John", + "foo": "00ff" + }`, + }, + testUtils.Request{ + Request: `query { + Users { + name + foo + } + }`, + Results: []map[string]any{ + { + "name": "John", + "foo": "00ff", + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, test) +} From a5405185b64c32ffc1a1c7f7db12600e8f0375d8 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Mon, 4 Dec 2023 10:32:56 -0800 Subject: [PATCH 11/16] add coerceBlob function --- request/graphql/schema/types/scalars.go | 73 +++++++++----------- request/graphql/schema/types/scalars_test.go | 28 ++++---- 2 files changed, 47 insertions(+), 54 deletions(-) diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index ddea1570ed..561d21024e 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -12,62 +12,51 @@ package types import ( "encoding/hex" + "regexp" "github.com/sourcenetwork/graphql-go" "github.com/sourcenetwork/graphql-go/language/ast" ) +// blobPattern is a regex for validating blob hex strings +var blobPattern = regexp.MustCompile("[0-9a-fA-F]+") + +// coerceBlob converts the given value into a valid hex string. +// If the value cannot be converted nil is returned. +func coerceBlob(value any) any { + switch value := value.(type) { + case []byte: + return hex.EncodeToString(value) + + case *[]byte: + return coerceBlob(*value) + + case string: + if !blobPattern.MatchString(value) { + return nil + } + return value + + case *string: + return coerceBlob(*value) + + default: + return nil + } +} + var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ Name: "Blob", Description: "The `Blob` scalar type represents a binary large object.", // Serialize converts the value to the serialized hex representation - Serialize: func(value any) any { - switch value := value.(type) { - case []byte: - return hex.EncodeToString(value) - case *[]byte: - return hex.EncodeToString(*value) - default: - // return nil if the value cannot be serialized - return nil - } - }, + Serialize: coerceBlob, // ParseValue converts the serialized value to the []byte representation - ParseValue: func(value any) any { - switch value := value.(type) { - case string: - data, err := hex.DecodeString(value) - if err != nil { - return nil - } - return data - case *string: - data, err := hex.DecodeString(*value) - if err != nil { - // the error cannot be handled due to - // the design of graphql-go scalars - // - // return nil if the value cannot be parsed - return nil - } - return data - default: - return nil - } - }, + ParseValue: coerceBlob, // ParseLiteral converts the ast value to the []byte representation ParseLiteral: func(valueAST ast.Value) any { switch valueAST := valueAST.(type) { case *ast.StringValue: - data, err := hex.DecodeString(valueAST.Value) - if err != nil { - // the error cannot be handled due to - // the design of graphql-go scalars - // - // return nil if the value cannot be parsed - return nil - } - return data + return coerceBlob(valueAST.Value) default: // return nil if the value cannot be parsed return nil diff --git a/request/graphql/schema/types/scalars_test.go b/request/graphql/schema/types/scalars_test.go index 4b37ff9cfc..372e4e8b88 100644 --- a/request/graphql/schema/types/scalars_test.go +++ b/request/graphql/schema/types/scalars_test.go @@ -18,15 +18,17 @@ import ( ) func TestBlobScalarTypeSerialize(t *testing.T) { - input := []byte{0, 255} - output := "00ff" + stringInput := "00ff" + bytesInput := []byte{0, 255} cases := []struct { input any expect any }{ - {input, output}, - {&input, output}, + {stringInput, "00ff"}, + {&stringInput, "00ff"}, + {bytesInput, "00ff"}, + {&bytesInput, "00ff"}, {nil, nil}, {0, nil}, {false, nil}, @@ -38,19 +40,21 @@ func TestBlobScalarTypeSerialize(t *testing.T) { } func TestBlobScalarTypeParseValue(t *testing.T) { - input := "00ff" - output := []byte{0, 255} + stringInput := "00ff" + bytesInput := []byte{0, 255} // invalid string containing non-hex characters - invalid := "!@#$%^&*" + invalidHexString := "!@#$%^&*" cases := []struct { input any expect any }{ - {input, output}, - {&input, output}, - {invalid, nil}, - {&invalid, nil}, + {stringInput, "00ff"}, + {&stringInput, "00ff"}, + {bytesInput, "00ff"}, + {&bytesInput, "00ff"}, + {invalidHexString, nil}, + {&invalidHexString, nil}, {nil, nil}, {0, nil}, {false, nil}, @@ -66,7 +70,7 @@ func TestBlobScalarTypeParseLiteral(t *testing.T) { input ast.Value expect any }{ - {&ast.StringValue{Value: "00ff"}, []byte{0, 255}}, + {&ast.StringValue{Value: "00ff"}, "00ff"}, {&ast.StringValue{Value: "!@#$%^&*"}, nil}, {&ast.IntValue{}, nil}, {&ast.BooleanValue{}, nil}, From 95c453d97a002c26335a3de9d2f49a45e8322e1d Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Mon, 4 Dec 2023 10:43:49 -0800 Subject: [PATCH 12/16] update docs --- request/graphql/schema/types/scalars.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index 561d21024e..7132d3d3e6 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -48,11 +48,11 @@ func coerceBlob(value any) any { var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ Name: "Blob", Description: "The `Blob` scalar type represents a binary large object.", - // Serialize converts the value to the serialized hex representation + // Serialize converts the value to a hex string Serialize: coerceBlob, - // ParseValue converts the serialized value to the []byte representation + // ParseValue converts the value to a hex string ParseValue: coerceBlob, - // ParseLiteral converts the ast value to the []byte representation + // ParseLiteral converts the ast value a hex string ParseLiteral: func(valueAST ast.Value) any { switch valueAST := valueAST.(type) { case *ast.StringValue: From 389ffef2dc39cdee8999add84a628c09dfb03a50 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Mon, 4 Dec 2023 10:45:41 -0800 Subject: [PATCH 13/16] fix blob regex --- request/graphql/schema/types/scalars.go | 2 +- request/graphql/schema/types/scalars_test.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index 7132d3d3e6..49d5055199 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -19,7 +19,7 @@ import ( ) // blobPattern is a regex for validating blob hex strings -var blobPattern = regexp.MustCompile("[0-9a-fA-F]+") +var blobPattern = regexp.MustCompile("^[0-9a-fA-F]+$") // coerceBlob converts the given value into a valid hex string. // If the value cannot be converted nil is returned. diff --git a/request/graphql/schema/types/scalars_test.go b/request/graphql/schema/types/scalars_test.go index 372e4e8b88..5126f2e6a2 100644 --- a/request/graphql/schema/types/scalars_test.go +++ b/request/graphql/schema/types/scalars_test.go @@ -71,7 +71,8 @@ func TestBlobScalarTypeParseLiteral(t *testing.T) { expect any }{ {&ast.StringValue{Value: "00ff"}, "00ff"}, - {&ast.StringValue{Value: "!@#$%^&*"}, nil}, + {&ast.StringValue{Value: "00!@#$%^&*"}, nil}, + {&ast.StringValue{Value: "!@#$%^&*00"}, nil}, {&ast.IntValue{}, nil}, {&ast.BooleanValue{}, nil}, {&ast.NullValue{}, nil}, From 1aa1a26a64fbfe40dae95a186bf94d9123de3f05 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Wed, 6 Dec 2023 09:21:19 -0800 Subject: [PATCH 14/16] add index test --- client/descriptions.go | 2 ++ db/index.go | 9 ++++++++- db/indexed_docs_test.go | 2 ++ request/graphql/schema/types/scalars.go | 6 +++--- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/client/descriptions.go b/client/descriptions.go index 6ef29cebaa..96f68108b4 100644 --- a/client/descriptions.go +++ b/client/descriptions.go @@ -146,6 +146,8 @@ func (f FieldKind) String() string { return "[String]" case FieldKind_STRING_ARRAY: return "[String!]" + case FieldKind_BLOB: + return "Blob" default: return fmt.Sprint(uint8(f)) } diff --git a/db/index.go b/db/index.go index 4bd62f6ae3..5d43bddb21 100644 --- a/db/index.go +++ b/db/index.go @@ -18,6 +18,7 @@ import ( "github.com/sourcenetwork/defradb/core" "github.com/sourcenetwork/defradb/datastore" "github.com/sourcenetwork/defradb/errors" + "github.com/sourcenetwork/defradb/request/graphql/schema/types" ) // CollectionIndex is an interface for collection indexes @@ -52,7 +53,13 @@ func getValidateIndexFieldFunc(kind client.FieldKind) func(any) bool { case client.FieldKind_BOOL: return canConvertIndexFieldValue[bool] case client.FieldKind_BLOB: - return canConvertIndexFieldValue[string] + return func(val any) bool { + blobStrVal, ok := val.(string) + if !ok { + return false + } + return types.BlobPattern.MatchString(blobStrVal) + } case client.FieldKind_DATETIME: return func(val any) bool { timeStrVal, ok := val.(string) diff --git a/db/indexed_docs_test.go b/db/indexed_docs_test.go index f1f8d6270f..56d7026e1e 100644 --- a/db/indexed_docs_test.go +++ b/db/indexed_docs_test.go @@ -421,6 +421,7 @@ func TestNonUnique_StoringIndexedFieldValueOfDifferentTypes(t *testing.T) { {Name: "invalid bool", FieldKind: client.FieldKind_BOOL, FieldVal: "invalid", ShouldFail: true}, {Name: "invalid datetime", FieldKind: client.FieldKind_DATETIME, FieldVal: nowStr[1:], ShouldFail: true}, {Name: "invalid datetime type", FieldKind: client.FieldKind_DATETIME, FieldVal: 1, ShouldFail: true}, + {Name: "invalid blob type", FieldKind: client.FieldKind_BLOB, FieldVal: "invalid", ShouldFail: true}, {Name: "valid int", FieldKind: client.FieldKind_INT, FieldVal: 12}, {Name: "valid float", FieldKind: client.FieldKind_FLOAT, FieldVal: 36.654}, @@ -428,6 +429,7 @@ func TestNonUnique_StoringIndexedFieldValueOfDifferentTypes(t *testing.T) { {Name: "valid bool false", FieldKind: client.FieldKind_BOOL, FieldVal: false}, {Name: "valid datetime string", FieldKind: client.FieldKind_DATETIME, FieldVal: nowStr}, {Name: "valid empty string", FieldKind: client.FieldKind_STRING, FieldVal: ""}, + {Name: "valid blob type", FieldKind: client.FieldKind_BLOB, FieldVal: "00ff"}, } for i, tc := range testCase { diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index 49d5055199..c1a1bc4d3b 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -18,8 +18,8 @@ import ( "github.com/sourcenetwork/graphql-go/language/ast" ) -// blobPattern is a regex for validating blob hex strings -var blobPattern = regexp.MustCompile("^[0-9a-fA-F]+$") +// BlobPattern is a regex for validating blob hex strings +var BlobPattern = regexp.MustCompile("^[0-9a-fA-F]+$") // coerceBlob converts the given value into a valid hex string. // If the value cannot be converted nil is returned. @@ -32,7 +32,7 @@ func coerceBlob(value any) any { return coerceBlob(*value) case string: - if !blobPattern.MatchString(value) { + if !BlobPattern.MatchString(value) { return nil } return value From 8089b49924d1c5e75e9dc91d7a794b302fd1a4a1 Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Wed, 6 Dec 2023 09:21:52 -0800 Subject: [PATCH 15/16] fix typo --- request/graphql/schema/types/scalars.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/request/graphql/schema/types/scalars.go b/request/graphql/schema/types/scalars.go index c1a1bc4d3b..a0e9dca369 100644 --- a/request/graphql/schema/types/scalars.go +++ b/request/graphql/schema/types/scalars.go @@ -52,7 +52,7 @@ var BlobScalarType = graphql.NewScalar(graphql.ScalarConfig{ Serialize: coerceBlob, // ParseValue converts the value to a hex string ParseValue: coerceBlob, - // ParseLiteral converts the ast value a hex string + // ParseLiteral converts the ast value to a hex string ParseLiteral: func(valueAST ast.Value) any { switch valueAST := valueAST.(type) { case *ast.StringValue: From 438894bc3ca3dcbd809d68ad964a58544c30447f Mon Sep 17 00:00:00 2001 From: Keenan Nemetz Date: Wed, 6 Dec 2023 09:53:50 -0800 Subject: [PATCH 16/16] improve index blob test --- db/indexed_docs_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/db/indexed_docs_test.go b/db/indexed_docs_test.go index 56d7026e1e..bb569bdc6c 100644 --- a/db/indexed_docs_test.go +++ b/db/indexed_docs_test.go @@ -421,7 +421,8 @@ func TestNonUnique_StoringIndexedFieldValueOfDifferentTypes(t *testing.T) { {Name: "invalid bool", FieldKind: client.FieldKind_BOOL, FieldVal: "invalid", ShouldFail: true}, {Name: "invalid datetime", FieldKind: client.FieldKind_DATETIME, FieldVal: nowStr[1:], ShouldFail: true}, {Name: "invalid datetime type", FieldKind: client.FieldKind_DATETIME, FieldVal: 1, ShouldFail: true}, - {Name: "invalid blob type", FieldKind: client.FieldKind_BLOB, FieldVal: "invalid", ShouldFail: true}, + {Name: "invalid blob", FieldKind: client.FieldKind_BLOB, FieldVal: "invalid", ShouldFail: true}, + {Name: "invalid blob type", FieldKind: client.FieldKind_BLOB, FieldVal: 1, ShouldFail: true}, {Name: "valid int", FieldKind: client.FieldKind_INT, FieldVal: 12}, {Name: "valid float", FieldKind: client.FieldKind_FLOAT, FieldVal: 36.654},