diff --git a/packages/orm/src/client/crud/operations/update.ts b/packages/orm/src/client/crud/operations/update.ts index 805eb2a8..477f03f5 100644 --- a/packages/orm/src/client/crud/operations/update.ts +++ b/packages/orm/src/client/crud/operations/update.ts @@ -43,7 +43,8 @@ export class UpdateOperationHandler extends BaseOperat if (needReadBack) { // updated can be undefined if there's nothing to update, in that case we'll use the original // filter to read back the entity - const readFilter = updateResult ?? args.where; + // note that we trim filter to id fields only, just in case underlying executor returns more fields + const readFilter = updateResult ? getIdValues(this.schema, this.model, updateResult) : args.where; let readBackResult: any = undefined; readBackResult = await this.readUnique(tx, this.model, { select: args.select, diff --git a/tests/e2e/orm/policy/crud/update.test.ts b/tests/e2e/orm/policy/crud/update.test.ts index 7f060c88..95b17306 100644 --- a/tests/e2e/orm/policy/crud/update.test.ts +++ b/tests/e2e/orm/policy/crud/update.test.ts @@ -1,5 +1,5 @@ -import { describe, expect, it } from 'vitest'; import { createPolicyTestClient } from '@zenstackhq/testtools'; +import { describe, expect, it } from 'vitest'; describe('Update policy tests', () => { describe('Scalar condition tests', () => { diff --git a/tests/regression/test/issue-586.test.ts b/tests/regression/test/issue-586.test.ts new file mode 100644 index 00000000..0c124472 --- /dev/null +++ b/tests/regression/test/issue-586.test.ts @@ -0,0 +1,87 @@ +import { createPolicyTestClient } from '@zenstackhq/testtools'; +import { describe, expect, it } from 'vitest'; + +describe('Regression for issue #586', () => { + it('does not throw cannot-read-back for json array update with extra mutation plugin', async () => { + const schema = ` + + type AuthInfo { + aProperty Boolean + + @@auth + } + + type Foo { + bar String + baz Int + + @@allow("all", auth().aProperty) + } + + model JsonArrayRoot { + id String @id @default(cuid()) + + fields JsonArrayField[] + + @@allow("all", auth().aProperty) + } + + model JsonArrayField { + id String @id @default(cuid()) + data Foo[] @json + rootId String + + root JsonArrayRoot @relation(fields: [rootId], references: [id]) + + @@allow("all", auth().aProperty) + } + `; + + const db = await createPolicyTestClient(schema, { + provider: 'postgresql', + usePrismaPush: true, + plugins: [ + { + id: 'foo', + name: 'foo', + description: 'foo', + onEntityMutation: { + afterEntityMutation: async () => Promise.resolve(), + beforeEntityMutation: async () => Promise.resolve(), + runAfterMutationWithinTransaction: true, + }, + }, + ], + }); + + try { + const authed = db.$setAuth({ aProperty: true }); + + const root = await authed.jsonArrayRoot.create({ data: {} }); + + const created = await authed.jsonArrayField.create({ + data: { + data: [], + rootId: root.id, + }, + }); + + const updateData = [ + { bar: 'hello', baz: 1 }, + { bar: 'world', baz: 2 }, + ]; + + await expect( + authed.jsonArrayField.update({ + where: { id: created.id }, + data: { + data: updateData, + rootId: root.id, + }, + }), + ).resolves.toMatchObject({ data: updateData }); + } finally { + await db.$disconnect?.(); + } + }); +});