From ade2cfe1665afa26ad53b471ab2a372b3a0650a6 Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Thu, 27 Nov 2025 10:51:40 +0800 Subject: [PATCH 1/2] feat(orm): add settings to disallow query-time omit override --- packages/orm/src/client/client-impl.ts | 7 ++++++ packages/orm/src/client/contract.ts | 11 +++++++++ .../orm/src/client/crud/validator/index.ts | 12 +++++++++- packages/orm/src/client/options.ts | 23 ++++++++++++------- tests/e2e/orm/client-api/omit.test.ts | 19 +++++++++++++++ .../orm/validation/custom-validation.test.ts | 6 +++-- 6 files changed, 67 insertions(+), 11 deletions(-) diff --git a/packages/orm/src/client/client-impl.ts b/packages/orm/src/client/client-impl.ts index 1b472b55..8e2c8382 100644 --- a/packages/orm/src/client/client-impl.ts +++ b/packages/orm/src/client/client-impl.ts @@ -299,6 +299,13 @@ export class ClientImpl { return this.auth; } + $setOptions>(options: Options): ClientContract { + return new ClientImpl(this.schema, options as ClientOptions, this) as unknown as ClientContract< + SchemaDef, + Options + >; + } + $setInputValidation(enable: boolean) { const newOptions: ClientOptions = { ...this.options, diff --git a/packages/orm/src/client/contract.ts b/packages/orm/src/client/contract.ts index a4a8b46e..d5fe86ad 100644 --- a/packages/orm/src/client/contract.ts +++ b/packages/orm/src/client/contract.ts @@ -114,9 +114,20 @@ export type ClientContract | undefined): ClientContract; + /** + * Returns a new client with new options applied. + * @example + * ``` + * const dbNoValidation = db.$setOptions({ ...db.$options, validateInput: false }); + * ``` + */ + $setOptions>(options: Options): ClientContract; + /** * Returns a new client enabling/disabling input validations expressed with attributes like * `@email`, `@regex`, `@@validate`, etc. + * + * @deprecated Use `$setOptions` instead. */ $setInputValidation(enable: boolean): ClientContract; diff --git a/packages/orm/src/client/crud/validator/index.ts b/packages/orm/src/client/crud/validator/index.ts index ee8bd17a..30032224 100644 --- a/packages/orm/src/client/crud/validator/index.ts +++ b/packages/orm/src/client/crud/validator/index.ts @@ -61,6 +61,10 @@ export class InputValidator { return this.client.$schema; } + private get options() { + return this.client.$options; + } + private get extraValidationsEnabled() { return this.client.$options.validateInput !== false; } @@ -783,7 +787,13 @@ export class InputValidator { for (const field of Object.keys(modelDef.fields)) { const fieldDef = requireField(this.schema, model, field); if (!fieldDef.relation) { - fields[field] = z.boolean().optional(); + if (this.options.allowQueryTimeOmitOverride !== false) { + // if override is allowed, use boolean + fields[field] = z.boolean().optional(); + } else { + // otherwise only allow true + fields[field] = z.literal(true).optional(); + } } } return z.strictObject(fields); diff --git a/packages/orm/src/client/options.ts b/packages/orm/src/client/options.ts index a3feea03..21606371 100644 --- a/packages/orm/src/client/options.ts +++ b/packages/orm/src/client/options.ts @@ -78,19 +78,26 @@ export type ClientOptions = { * `@@validate`, etc. Defaults to `true`. */ validateInput?: boolean; -} & { + /** * Options for omitting fields in ORM query results. */ omit?: OmitOptions; + + /** + * Whether to allow overriding omit settings at query time. Defaults to `true`. When set to + * `false`, an `omit` clause that set field to `false` (not omitting) will trigger a validation + * error. + */ + allowQueryTimeOmitOverride?: boolean; } & (HasComputedFields extends true - ? { - /** - * Computed field definitions. - */ - computedFields: ComputedFieldsOptions; - } - : {}) & + ? { + /** + * Computed field definitions. + */ + computedFields: ComputedFieldsOptions; + } + : {}) & (HasProcedures extends true ? { /** diff --git a/tests/e2e/orm/client-api/omit.test.ts b/tests/e2e/orm/client-api/omit.test.ts index f200a0c5..7cabe4d8 100644 --- a/tests/e2e/orm/client-api/omit.test.ts +++ b/tests/e2e/orm/client-api/omit.test.ts @@ -140,4 +140,23 @@ describe('Field omission tests', () => { const read1 = await db.sub.findFirstOrThrow({ omit: { content: false } }); expect(read1.content).toBe('Foo'); }); + + it('respects query-level omit override settings', async () => { + const base = await createTestClient(schema); + const db = base.$setOptions({ ...base.$options, allowQueryTimeOmitOverride: false }); + await expect( + db.user.create({ + data: { id: 1, name: 'User1', password: 'abc' }, + omit: { password: false }, + }), + ).toBeRejectedByValidation(); + + await db.user.create({ data: { id: 1, name: 'User1', password: 'abc' } }); + await expect(db.user.findFirstOrThrow({ omit: { password: false } })).toBeRejectedByValidation(); + + // allow set omit as true + const user = await db.user.findFirstOrThrow({ omit: { name: true } }); + // @ts-expect-error + expect(user.name).toBeUndefined(); + }); }); diff --git a/tests/e2e/orm/validation/custom-validation.test.ts b/tests/e2e/orm/validation/custom-validation.test.ts index 955121b0..56558108 100644 --- a/tests/e2e/orm/validation/custom-validation.test.ts +++ b/tests/e2e/orm/validation/custom-validation.test.ts @@ -143,8 +143,10 @@ describe('Custom validation tests', () => { }), ).toBeRejectedByValidation(); + const dbNoValidation = db.$setOptions({ ...db.$options, validateInput: false }); + await expect( - db.$setInputValidation(false).user.create({ + dbNoValidation.user.create({ data: { id: 1, email: 'xyz', @@ -153,7 +155,7 @@ describe('Custom validation tests', () => { ).toResolveTruthy(); await expect( - db.$setInputValidation(false).user.update({ + dbNoValidation.user.update({ where: { id: 1 }, data: { email: 'a@b.com', From e54dfdf7716bfff9dfdc00412fd36d68c382daca Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Thu, 27 Nov 2025 10:55:24 +0800 Subject: [PATCH 2/2] Update packages/orm/src/client/options.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/orm/src/client/options.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/orm/src/client/options.ts b/packages/orm/src/client/options.ts index 21606371..ed2f9512 100644 --- a/packages/orm/src/client/options.ts +++ b/packages/orm/src/client/options.ts @@ -86,7 +86,7 @@ export type ClientOptions = { /** * Whether to allow overriding omit settings at query time. Defaults to `true`. When set to - * `false`, an `omit` clause that set field to `false` (not omitting) will trigger a validation + * `false`, an `omit` clause that sets field to `false` (not omitting) will trigger a validation * error. */ allowQueryTimeOmitOverride?: boolean;