diff --git a/client/db.go b/client/db.go index ea32ec3f6f..e10af66d0b 100644 --- a/client/db.go +++ b/client/db.go @@ -21,6 +21,7 @@ import ( type DB interface { AddSchema(context.Context, string) error + PatchSchema(context.Context, string) error CreateCollection(context.Context, CollectionDescription) (Collection, error) CreateCollectionTxn(context.Context, datastore.Txn, CollectionDescription) (Collection, error) diff --git a/db/collection.go b/db/collection.go index e5296dfb32..35cdd65857 100644 --- a/db/collection.go +++ b/db/collection.go @@ -199,6 +199,59 @@ func (db *db) CreateCollectionTxn( return col, nil } +func (db *db) UpdateCollection( //todo - add to DB interface? Could be unsafe atm. Move validation into here? + ctx context.Context, + txn datastore.Txn, + desc client.CollectionDescription, +) (client.Collection, error) { + for i, field := range desc.Schema.Fields { + if field.ID == client.FieldID(0) { + // This is not wonderful and will probably break when we add the ability + // to delete fields. Location is also not great + field.ID = client.FieldID(i) + desc.Schema.Fields[i] = field + } + } + + globalSchemaBuf, err := json.Marshal(desc.Schema) + if err != nil { + return nil, err + } + + buf, err := json.Marshal(desc) + if err != nil { + return nil, err + } + + cid, err := core.NewSHA256CidV1(globalSchemaBuf) + if err != nil { + return nil, err + } + schemaVersionID := cid.String() + + collectionSchemaVersionKey := core.NewCollectionSchemaVersionKey(schemaVersionID) + // Whilst the schemaVersionKey is global, the data persisted at the key's location + // is local to the node (the global only elements are not useful beyond key generation). + err = txn.Systemstore().Put(ctx, collectionSchemaVersionKey.ToDS(), buf) + if err != nil { + return nil, err + } + + collectionSchemaKey := core.NewCollectionSchemaKey(desc.Schema.SchemaID) + err = txn.Systemstore().Put(ctx, collectionSchemaKey.ToDS(), []byte(schemaVersionID)) + if err != nil { + return nil, err + } + + collectionKey := core.NewCollectionKey(desc.Name) + err = txn.Systemstore().Put(ctx, collectionKey.ToDS(), []byte(schemaVersionID)) + if err != nil { + return nil, err + } + + return db.GetCollectionByNameTxn(ctx, txn, desc.Name) +} + // getCollectionByVersionId returns the [*collection] at the given [schemaVersionId] version. // // Will return an error if the given key is empty, or not found. diff --git a/db/schema.go b/db/schema.go index 0a9c49a570..eec85f74c4 100644 --- a/db/schema.go +++ b/db/schema.go @@ -12,9 +12,13 @@ package db import ( "context" + "encoding/json" + "strings" + jsonpatch "github.com/evanphx/json-patch" "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/datastore" + "github.com/sourcenetwork/defradb/errors" ) // AddSchema takes the provided schema in SDL format, and applies it to the database, @@ -86,3 +90,119 @@ func (db *db) getCollectionDescriptions(ctx context.Context, txn datastore.Txn) return descriptions, nil } + +func (db *db) PatchSchema(ctx context.Context, patchString string) error { + txn, err := db.NewTxn(ctx, false) + if err != nil { + return err + } + defer txn.Discard(ctx) + + collectionsByName, err := db.getCollectionsByName(ctx, txn) + if err != nil { + return err + } + + err = validateSchemaPatch(collectionsByName, patchString) + if err != nil { + return err + } + + patch, err := jsonpatch.DecodePatch([]byte(patchString)) + if err != nil { + return err + } + + existingDescriptionJson, err := json.Marshal(collectionsByName) + if err != nil { + return err + } + + newDescriptionJson, err := patch.Apply(existingDescriptionJson) + if err != nil { + return err + } + + var newDescriptionsByName map[string]client.CollectionDescription + err = json.Unmarshal([]byte(newDescriptionJson), &newDescriptionsByName) + if err != nil { + return err + } + + newDescriptions := []client.CollectionDescription{} + for _, desc := range newDescriptionsByName { + newDescriptions = append(newDescriptions, desc) + } + + err = db.parser.SetSchema(ctx, txn, newDescriptions) + if err != nil { + return err + } + + for _, desc := range newDescriptions { + if _, err := db.UpdateCollection(ctx, txn, desc); err != nil { //todo - test transactional, validation in here required! Can skip in PatchSchema + return err + } + } + + return txn.Commit(ctx) +} + +func (db *db) getCollectionsByName(ctx context.Context, txn datastore.Txn) (map[string]client.CollectionDescription, error) { + collections, err := db.GetAllCollectionsTxn(ctx, txn) + if err != nil { + return nil, err + } + + collectionsByName := map[string]client.CollectionDescription{} + for _, collection := range collections { + collectionsByName[collection.Name()] = collection.Description() + } + + return collectionsByName, nil +} + +func validateSchemaPatch(collectionsByName map[string]client.CollectionDescription, patchString string) error { + var patch []schemaPatchItem + err := json.Unmarshal([]byte(patchString), &patch) + if err != nil { + return err + } + + for _, patchItem := range patch { + switch patchItem.Op { + case "add": + // no-op, operation is supported + + default: + return errors.New("op not supported", errors.NewKV("op", patchItem.Op)) + } + + path := strings.TrimPrefix(patchItem.Path, "/") + pathItems := strings.Split(path, "/") + + if len(pathItems) != 4 { + return errors.New("path not supported", errors.NewKV("path", patchItem.Path)) + } + + if _, isCollectionName := collectionsByName[pathItems[0]]; !isCollectionName { + return errors.New("unknown collection", errors.NewKV("name", pathItems[0])) + } + + if pathItems[1] != "Schema" { + return errors.New("path not supported", errors.NewKV("path", patchItem.Path)) + } + + if pathItems[2] != "Fields" { + return errors.New("path not supported", errors.NewKV("path", patchItem.Path)) + } + } + + return nil +} + +type schemaPatchItem struct { + Op string + Path string + Value client.FieldDescription +} diff --git a/go.mod b/go.mod index c894a40f82..46d8539bb5 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.19 require ( github.com/bxcodec/faker v2.0.1+incompatible github.com/dgraph-io/badger/v3 v3.2103.4 + github.com/evanphx/json-patch v0.5.2 github.com/fxamacker/cbor/v2 v2.4.0 github.com/go-chi/chi/v5 v5.0.7 github.com/go-chi/cors v1.2.1 diff --git a/go.sum b/go.sum index d8714a67c5..060592af08 100644 --- a/go.sum +++ b/go.sum @@ -202,6 +202,8 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= diff --git a/tests/integration/schema/updates/add/field/create_test.go b/tests/integration/schema/updates/add/field/create_test.go new file mode 100644 index 0000000000..17018d34e5 --- /dev/null +++ b/tests/integration/schema/updates/add/field/create_test.go @@ -0,0 +1,119 @@ +// 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 + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesAddFieldWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John" + }`, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Email", "Kind": 11} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + _key + Name + Email + } + }`, + Results: []map[string]any{ + { + "_key": "bae-43deba43-f2bc-59f4-9056-fef661b22832", + "Name": "John", + "Email": nil, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldWithCreateAfterSchemaUpdate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with create after schema update", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John" + }`, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Email", "Kind": 11} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "Shahzad", + "Email": "sqlizded@yahoo.ca" + }`, + }, + testUtils.Request{ + Request: `query { + Users { + _key + Name + Email + } + }`, + Results: []map[string]any{ + { + "_key": "bae-43deba43-f2bc-59f4-9056-fef661b22832", + "Name": "John", + "Email": nil, + }, + { + "_key": "bae-68926881-2eed-519b-b4eb-883b4a6624a6", + "Name": "Shahzad", + "Email": "sqlizded@yahoo.ca", + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/create_update_test.go b/tests/integration/schema/updates/add/field/create_update_test.go new file mode 100644 index 0000000000..7c0aee2ea9 --- /dev/null +++ b/tests/integration/schema/updates/add/field/create_update_test.go @@ -0,0 +1,67 @@ +// 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 + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesAddFieldWithCreateWithUpdateAfterSchemaUpdate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with update after schema update", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John" + }`, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Email", "Kind": 11} } + ] + `, + }, + testUtils.UpdateDoc{ + CollectionID: 0, + DocID: 0, + Doc: `{ + "Email": "ih8oraclelicensing@netscape.net" + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Email + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Email": "ih8oraclelicensing@netscape.net", + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/bool_array_test.go b/tests/integration/schema/updates/add/field/kind/bool_array_test.go new file mode 100644 index 0000000000..4bad3433a4 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/bool_array_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindBoolArray(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind bool array (3)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 3} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindBoolArrayWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind bool array (3) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 3} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": [true, false, true] + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": []bool{true, false, true}, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/bool_test.go b/tests/integration/schema/updates/add/field/kind/bool_test.go new file mode 100644 index 0000000000..8649145ae3 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/bool_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindBool(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind bool (2)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 2} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindBoolWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind bool (2) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 2} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": true + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": true, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/datetime_test.go b/tests/integration/schema/updates/add/field/kind/datetime_test.go new file mode 100644 index 0000000000..9a4cbc9479 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/datetime_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindDateTime(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind datetime (10)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 10} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindDateTimeWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind datetime (10) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 4} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": "2017-07-23T03:46:56.647Z" + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": "2017-07-23T03:46:56.647Z", + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/deprecated_test.go b/tests/integration/schema/updates/add/field/kind/deprecated_test.go new file mode 100644 index 0000000000..9130f81934 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/deprecated_test.go @@ -0,0 +1,89 @@ +// 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 TestSchemaUpdatesAddFieldKind8(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind deprecated (8)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 8} } + ] + `, + ExpectedError: "no type found for given name. Type: 8", + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKind9(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind deprecated (9)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 9} } + ] + `, + ExpectedError: "no type found for given name. Type: 9", + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, 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/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 13} } + ] + `, + ExpectedError: "no type found for given name. Type: 13", + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/dockey_test.go b/tests/integration/schema/updates/add/field/kind/dockey_test.go new file mode 100644 index 0000000000..ac4c3b06ab --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/dockey_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindDocKey(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind DocKey (1)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 1} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindDocKeyWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind DocKey (1) and create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 1} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": "nhgfdsfd" + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": "nhgfdsfd", + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/float_array_test.go b/tests/integration/schema/updates/add/field/kind/float_array_test.go new file mode 100644 index 0000000000..d71164efe7 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/float_array_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindFloatArray(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind float array (7)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 7} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindFloatArrayWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind float array (7) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 7} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": [3.1, -8.1, 0] + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": []float64{3.1, -8.1, 0}, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/float_test.go b/tests/integration/schema/updates/add/field/kind/float_test.go new file mode 100644 index 0000000000..ed231c2f11 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/float_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindFloat(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind float (6)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 6} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindFloatWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind float (6) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 6} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": 3 + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": float64(3), + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/int_array_test.go b/tests/integration/schema/updates/add/field/kind/int_array_test.go new file mode 100644 index 0000000000..78b1db1d7f --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/int_array_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindIntArray(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind int array (5)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 5} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindIntArrayWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind int array (5) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 5} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": [3, 5, 8] + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": []int64{3, 5, 8}, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/int_test.go b/tests/integration/schema/updates/add/field/kind/int_test.go new file mode 100644 index 0000000000..e499139070 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/int_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindInt(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind int (4)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 4} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindIntWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind int (4) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 4} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": 3 + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": uint64(3), + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/none_test.go b/tests/integration/schema/updates/add/field/kind/none_test.go new file mode 100644 index 0000000000..9959fc2031 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/none_test.go @@ -0,0 +1,41 @@ +// 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 TestSchemaUpdatesAddFieldKindNone(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind none (0)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 0} } + ] + `, + ExpectedError: "no type found for given name. Type: 0", + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/string_array_test.go b/tests/integration/schema/updates/add/field/kind/string_array_test.go new file mode 100644 index 0000000000..25300095f6 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/string_array_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindStringArray(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind string array (12)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 12} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindStringArrayWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind string array (12) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 12} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": ["bar", "pub", "inn", "out", "hokey", "cokey", "pepsi", "beer", "bar", "pub", "..."] + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": []string{"bar", "pub", "inn", "out", "hokey", "cokey", "pepsi", "beer", "bar", "pub", "..."}, + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/kind/string_test.go b/tests/integration/schema/updates/add/field/kind/string_test.go new file mode 100644 index 0000000000..4bba3d64a5 --- /dev/null +++ b/tests/integration/schema/updates/add/field/kind/string_test.go @@ -0,0 +1,93 @@ +// 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 TestSchemaUpdatesAddFieldKindString(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind string (11)", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 11} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldKindStringWithCreate(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field with kind string (11) with create", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Foo", "Kind": 11} } + ] + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "Name": "John", + "Foo": "bar" + }`, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Foo + } + }`, + Results: []map[string]any{ + { + "Name": "John", + "Foo": "bar", + }, + }, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/field/simple_test.go b/tests/integration/schema/updates/add/field/simple_test.go new file mode 100644 index 0000000000..5f2fe95db7 --- /dev/null +++ b/tests/integration/schema/updates/add/field/simple_test.go @@ -0,0 +1,181 @@ +// 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 + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +// todo: make sure other ops are blocked and error! Add schema tests (gql introspection stuff) + +func TestSchemaUpdatesAddFieldSimple(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Email", "Kind": 11} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Email + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldSimpleErrorsAddingToUnknownCollection(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add to unknown collection fails", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Authors/Schema/Fields/-", "value": {"Name": "Email", "Kind": 11} } + ] + `, + ExpectedError: "unknown collection. name: Authors", + }, + testUtils.Request{ + Request: `query { + Users { + Name + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldMultipleInPatch(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add multiple fields in single patch", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Email", "Kind": 11} }, + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "City", "Kind": 11} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Email + City + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldMultiplePatches(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add multiple patches", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "Email", "Kind": 11} } + ] + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Name": "City", "Kind": 11} } + ] + `, + }, + testUtils.Request{ + Request: `query { + Users { + Name + Email + City + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddFieldSimpleWithoutName(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add field without name", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Fields/-", "value": {"Kind": 11} } + ] + `, + ExpectedError: "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"\" does not.", + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/add/simple_test.go b/tests/integration/schema/updates/add/simple_test.go new file mode 100644 index 0000000000..d269846492 --- /dev/null +++ b/tests/integration/schema/updates/add/simple_test.go @@ -0,0 +1,177 @@ +// 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 + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesAddSimpleErrorsAddingSchema(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add schema fails", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/-", "value": {"Name": "Books"} } + ] + `, + ExpectedError: "path not supported", + }, + testUtils.Request{ + Request: `query { + Users { + Name + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddSimpleErrorsAddingCollectionProp(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add collection property fails", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/-", "value": {"Name": "Books"} } + ] + `, + ExpectedError: "path not supported", + }, + testUtils.Request{ + Request: `query { + Users { + Name + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddSimpleErrorsAddingSchemaProp(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add schema property fails", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/-", "value": {"Foo": "Bar"} } + ] + `, + ExpectedError: "path not supported", + }, + testUtils.Request{ + Request: `query { + Users { + Name + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddSimpleErrorsAddingUnsupportedCollectionProp(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add to unsupported collection prop", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Foo/Fields/-", "value": {"Name": "Email", "Kind": 11} } + ] + `, + ExpectedError: "path not supported", + }, + testUtils.Request{ + Request: `query { + Users { + Name + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} + +func TestSchemaUpdatesAddSimpleErrorsAddingUnsupportedSchemaProp(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, add to unsupported schema prop", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "add", "path": "/Users/Schema/Foo/-", "value": {"Name": "Email", "Kind": 11} } + ] + `, + ExpectedError: "path not supported", + }, + testUtils.Request{ + Request: `query { + Users { + Name + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/copy/simple_test.go b/tests/integration/schema/updates/copy/simple_test.go new file mode 100644 index 0000000000..a470f49a61 --- /dev/null +++ b/tests/integration/schema/updates/copy/simple_test.go @@ -0,0 +1,51 @@ +// 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 copy + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesCopyErrors(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, copy field", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + Email: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "copy", "from": "/Users/Schema/Fields/Email", "path": "/Users/Schema/Fields/OldEmail" } + ] + `, + ExpectedError: "op not supported. op: copy", + }, + testUtils.Request{ + Request: `query { + Users { + Name + Email + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/move/simple_test.go b/tests/integration/schema/updates/move/simple_test.go new file mode 100644 index 0000000000..bb572d46d2 --- /dev/null +++ b/tests/integration/schema/updates/move/simple_test.go @@ -0,0 +1,51 @@ +// 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 move + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesMoveErrors(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, move field", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + Email: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "move", "from": "/Users/Schema/Fields/Email", "path": "/Users/Schema/Fields/NewEmail" } + ] + `, + ExpectedError: "op not supported. op: move", + }, + testUtils.Request{ + Request: `query { + Users { + Name + Email + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/remove/simple_test.go b/tests/integration/schema/updates/remove/simple_test.go new file mode 100644 index 0000000000..cb6c6ba0d0 --- /dev/null +++ b/tests/integration/schema/updates/remove/simple_test.go @@ -0,0 +1,51 @@ +// 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 remove + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesRemoveErrors(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, remove field", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + Email: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "remove", "path": "/Users/Schema/Fields/Email" } + ] + `, + ExpectedError: "op not supported. op: remove", + }, + testUtils.Request{ + Request: `query { + Users { + Name + Email + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/replace/simple_test.go b/tests/integration/schema/updates/replace/simple_test.go new file mode 100644 index 0000000000..a4fe217348 --- /dev/null +++ b/tests/integration/schema/updates/replace/simple_test.go @@ -0,0 +1,51 @@ +// 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 replace + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesReplaceErrors(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, replace field", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + Email: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "replace", "path": "/Users/Schema/Fields/Email", "value": {"Name": "Fax", "Kind": 11} } + ] + `, + ExpectedError: "op not supported. op: replace", + }, + testUtils.Request{ + Request: `query { + Users { + Name + Email + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/schema/updates/test/simple_test.go b/tests/integration/schema/updates/test/simple_test.go new file mode 100644 index 0000000000..71e1904e4b --- /dev/null +++ b/tests/integration/schema/updates/test/simple_test.go @@ -0,0 +1,49 @@ +// 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 test + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestSchemaUpdatesTestErrors(t *testing.T) { + test := testUtils.TestCase{ + Description: "Test schema update, test field", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + Name: String + } + `, + }, + testUtils.SchemaPatch{ + Patch: ` + [ + { "op": "test", "path": "/Users/Schema/Fields/Name", "value": {"Name": "Name", "Kind": 11} } + ] + `, + ExpectedError: "op not supported. op: test", + }, + testUtils.Request{ + Request: `query { + Users { + Name + } + }`, + Results: []map[string]any{}, + }, + }, + } + testUtils.ExecuteTestCase(t, []string{"Users"}, test) +} diff --git a/tests/integration/test_case.go b/tests/integration/test_case.go index 74970b6ee4..e209f5b230 100644 --- a/tests/integration/test_case.go +++ b/tests/integration/test_case.go @@ -40,6 +40,11 @@ type SchemaUpdate struct { ExpectedError string } +type SchemaPatch struct { + Patch string + ExpectedError string +} + // CreateDoc will attempt to create the given document in the given collection // using the collection api. type CreateDoc struct { diff --git a/tests/integration/utils2.go b/tests/integration/utils2.go index 61842156ac..9396014031 100644 --- a/tests/integration/utils2.go +++ b/tests/integration/utils2.go @@ -327,6 +327,11 @@ func executeTestCase( // If the schema was updated we need to refresh the collection definitions. collections = getCollections(ctx, t, dbi.db, collectionNames) + case SchemaPatch: + patchSchema(ctx, t, dbi.db, testCase, action) + // If the schema was updated we need to refresh the collection definitions. + collections = getCollections(ctx, t, dbi.db, collectionNames) + case CreateDoc: documents = createDoc(ctx, t, testCase, collections, documents, action) @@ -478,6 +483,19 @@ func updateSchema( assertExpectedErrorRaised(t, testCase.Description, action.ExpectedError, expectedErrorRaised) } +func patchSchema( + ctx context.Context, + t *testing.T, + db client.DB, + testCase TestCase, + action SchemaPatch, +) { + err := db.PatchSchema(ctx, action.Patch) + expectedErrorRaised := AssertError(t, testCase.Description, err, action.ExpectedError) + + assertExpectedErrorRaised(t, testCase.Description, action.ExpectedError, expectedErrorRaised) +} + // createDoc creates a document using the collection api and caches it in the // given documents slice. func createDoc(