diff --git a/server/metadata/tenant.go b/server/metadata/tenant.go index c21fe18a0..52abf1930 100644 --- a/server/metadata/tenant.go +++ b/server/metadata/tenant.go @@ -294,6 +294,7 @@ func (m *TenantManager) RefreshNamespaceAccounts(ctx context.Context) error { tenant.Lock() tenantMeta := tenant.namespace.Metadata() tenantMeta.Accounts = metadata.Accounts + tenant.namespace.SetMetadata(tenantMeta) tenant.Unlock() } } diff --git a/server/services/v1/database/base_runner.go b/server/services/v1/database/base_runner.go index 5cbab19ac..d57cbce2c 100644 --- a/server/services/v1/database/base_runner.go +++ b/server/services/v1/database/base_runner.go @@ -188,6 +188,10 @@ func (*BaseQueryRunner) mutateAndValidatePayload(ctx context.Context, coll *sche } if request.NeedSchemaValidation(ctx) { + if mutator.ofType() == updateMutator { + // there may be dot notation in the field + deserializedDoc = util.UnFlatMap(deserializedDoc) + } if err = coll.Validate(deserializedDoc); err != nil { // schema validation failed return doc, err diff --git a/server/services/v1/database/mutator.go b/server/services/v1/database/mutator.go index 2ad2d7525..5d6a7c503 100644 --- a/server/services/v1/database/mutator.go +++ b/server/services/v1/database/mutator.go @@ -21,11 +21,17 @@ import ( "github.com/tigrisdata/tigris/server/services/v1/common" ) +const ( + insertMutator = "insert_mutator" + updateMutator = "update_mutator" +) + type mutator interface { isMutated() bool stringToInt64(doc map[string]any) error setDefaultsInIncomingPayload(doc map[string]any) error setDefaultsInExistingPayload(doc map[string]any) error + ofType() string } type baseMutator struct { @@ -75,6 +81,8 @@ func (mutator *insertPayloadMutator) setDefaults(doc map[string]any, field *sche } } +func (*insertPayloadMutator) ofType() string { return insertMutator } + type updatePayloadMutator struct { *baseMutator @@ -115,6 +123,8 @@ func (mutator *updatePayloadMutator) setDefaults(doc map[string]any, field *sche } } +func (*updatePayloadMutator) ofType() string { return updateMutator } + func (p *baseMutator) isMutated() bool { return p.mutated } diff --git a/test/v1/server/document_test.go b/test/v1/server/document_test.go index f5403610f..db2fda00f 100644 --- a/test/v1/server/document_test.go +++ b/test/v1/server/document_test.go @@ -2879,6 +2879,127 @@ func TestUpdate_Object(t *testing.T) { }}) } +func TestUpdate_ObjectDotNotation(t *testing.T) { + db, _ := setupTests(t) + defer cleanupTests(t, db) + + collection := "test_update_collection" + schema := Map{ + "schema": Map{ + "title": collection, + "properties": Map{ + "a": Map{ + "type": "integer", + }, + "b": Map{ + "type": "string", + }, + "c": Map{ + "type": "object", + "properties": Map{ + "f1": Map{ + "type": "string", + }, + "f2": Map{ + "type": "string", + }, + }, + }, + "d": Map{ + "type": "object", + "properties": Map{}, + }, + }, + "primary_key": []any{"a"}, + }, + } + createCollection(t, db, collection, schema).Status(200) + + inputDocument := []Doc{ + { + "a": 1, + "b": "1", + "c": Doc{"f1": "A", "f2": "B"}, + "d": Doc{"f1": "A", "f2": "B"}, + }, + } + + insertDocuments(t, db, collection, inputDocument, false). + Status(http.StatusOK) + + updateByFilter(t, + db, + collection, + Map{ + "filter": Map{ + "b": "1", + }, + }, + Map{ + "fields": Map{ + "$set": Map{ + "c.f1": "updated_A", + "d.f1": "updated_A", + }, + }, + }, + nil).Status(http.StatusOK). + JSON(). + Object(). + ValueEqual("modified_count", 1). + Path("$.metadata").Object() + + readAndValidate(t, + db, + collection, + Map{ + "b": "1", + }, + nil, + []Doc{{ + "a": 1, + "b": "1", + "c": Doc{"f1": "updated_A", "f2": "B"}, + "d": Doc{"f1": "updated_A", "f2": "B"}, + }}) + + updateByFilter(t, + db, + collection, + Map{ + "filter": Map{ + "b": "1", + }, + }, + Map{ + "fields": Map{ + "$set": Map{ + "c.f2": "updated_B", + "d.f2": "updated_B", + }, + }, + }, + nil).Status(http.StatusOK). + JSON(). + Object(). + ValueEqual("modified_count", 1). + Path("$.metadata").Object() + + readAndValidate(t, + db, + collection, + Map{ + "b": "1", + }, + nil, + []Doc{{ + "a": 1, + "b": "1", + "c": Doc{"f1": "updated_A", "f2": "updated_B"}, + "d": Doc{"f1": "updated_A", "f2": "updated_B"}, + }}) +} + func TestDelete_BadRequest(t *testing.T) { db, coll := setupTests(t) defer cleanupTests(t, db)