Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@ export class PolicyUtil extends QueryUtils {
}
}

if (schema) {
if (schema && !this.options.validation?.inputOnlyValidationForUpdate) {
// TODO: push down schema check to the database
this.validateZodSchema(model, undefined, result, true, (err) => {
throw this.deniedByPolicy(
Expand Down
22 changes: 22 additions & 0 deletions packages/runtime/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ export type EnhancementOptions = {
* The encryption options for using the `encrypted` enhancement.
*/
encryption?: SimpleEncryption | CustomEncryption;

/**
* Options for data validation.
*/
validation?: ValidationOptions;
};

/**
Expand Down Expand Up @@ -209,3 +214,20 @@ export type CustomEncryption = {
*/
decrypt: (model: string, field: FieldInfo, cipher: string) => Promise<string>;
};

/**
* Options for data validation.
*/
export type ValidationOptions = {
/**
* Whether to validate "update" operations based only on the input data. By default, ZenStack
* validates the entity after a update operation completes (inside a transaction), and rejects
* the operation if validation fails. This implies the entire entity needs to satisfy the
* validation rules, even for fields that are not part of the update input data.
*
* You can use this option to toggle the behavior to only validate the input data.
*
* Default is `false`.
*/
inputOnlyValidationForUpdate?: boolean;
};
42 changes: 42 additions & 0 deletions tests/regression/tests/issue-2025.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { loadSchema } from '@zenstackhq/testtools';

describe('issue 2025', () => {
it('regression', async () => {
const { enhanceRaw, prisma } = await loadSchema(
`
model User {
id String @id @default(cuid())
email String @unique @email
termsAndConditions Int?
@@allow('all', true)
}
`
);

const user = await prisma.user.create({
data: {
email: 'xyz', // invalid email
},
});

const db = enhanceRaw(prisma, undefined, { validation: { inputOnlyValidationForUpdate: true } });
await expect(
db.user.update({
where: { id: user.id },
data: {
termsAndConditions: 1,
},
})
).toResolveTruthy();

const db1 = enhanceRaw(prisma);
await expect(
db1.user.update({
where: { id: user.id },
data: {
termsAndConditions: 1,
},
})
).toBeRejectedByPolicy();
});
});
Loading