@@ -826,6 +826,8 @@ export class PolicyUtil extends QueryUtils {
826
826
/**
827
827
* Given a model and a unique filter, checks the operation is allowed by policies and field validations.
828
828
* Rejects with an error if not allowed.
829
+ *
830
+ * This method is only called by mutation operations.
829
831
*/
830
832
async checkPolicyForUnique (
831
833
model : string ,
@@ -1365,32 +1367,68 @@ export class PolicyUtil extends QueryUtils {
1365
1367
excludePasswordFields : boolean = true ,
1366
1368
kind : 'create' | 'update' | undefined = undefined
1367
1369
) {
1370
+ if ( ! this . zodSchemas ) {
1371
+ return undefined ;
1372
+ }
1373
+
1368
1374
if ( ! this . hasFieldValidation ( model ) ) {
1369
1375
return undefined ;
1370
1376
}
1377
+
1371
1378
const schemaKey = `${ upperCaseFirst ( model ) } ${ kind ? 'Prisma' + upperCaseFirst ( kind ) : '' } Schema` ;
1372
- let result = this . zodSchemas ?. models ?. [ schemaKey ] as ZodObject < any > | undefined ;
1373
-
1374
- if ( result && excludePasswordFields ) {
1375
- // fields with `@password` attribute changes at runtime, so we cannot directly use the generated
1376
- // zod schema to validate it, instead, the validation happens when checking the input of "create"
1377
- // and "update" operations
1378
- const modelFields = this . modelMeta . models [ lowerCaseFirst ( model ) ] ?. fields ;
1379
- if ( modelFields ) {
1380
- for ( const [ key , field ] of Object . entries ( modelFields ) ) {
1381
- if ( field . attributes ?. some ( ( attr ) => attr . name === '@password' ) ) {
1382
- // override `@password` field schema with a string schema
1383
- let pwFieldSchema : ZodSchema = z . string ( ) ;
1384
- if ( field . isOptional ) {
1385
- pwFieldSchema = pwFieldSchema . nullish ( ) ;
1379
+
1380
+ if ( excludePasswordFields ) {
1381
+ // The `excludePasswordFields` mode is to handle the issue the fields marked with `@password` change at runtime,
1382
+ // so they can only be fully validated when processing the input of "create" and "update" operations.
1383
+ //
1384
+ // When excluding them, we need to override them with plain string schemas. However, since the scheme is not always
1385
+ // an `ZodObject` (this happens when there's `@@validate` refinement), we need to fetch the `ZodObject` schema before
1386
+ // the refinement is applied, override the `@password` fields and then re-apply the refinement.
1387
+
1388
+ let schema : ZodObject < any > | undefined ;
1389
+
1390
+ const overridePasswordFields = ( schema : z . ZodObject < any > ) => {
1391
+ let result = schema ;
1392
+ const modelFields = this . modelMeta . models [ lowerCaseFirst ( model ) ] ?. fields ;
1393
+ if ( modelFields ) {
1394
+ for ( const [ key , field ] of Object . entries ( modelFields ) ) {
1395
+ if ( field . attributes ?. some ( ( attr ) => attr . name === '@password' ) ) {
1396
+ // override `@password` field schema with a string schema
1397
+ let pwFieldSchema : ZodSchema = z . string ( ) ;
1398
+ if ( field . isOptional ) {
1399
+ pwFieldSchema = pwFieldSchema . nullish ( ) ;
1400
+ }
1401
+ result = result . merge ( z . object ( { [ key ] : pwFieldSchema } ) ) ;
1386
1402
}
1387
- result = result ?. merge ( z . object ( { [ key ] : pwFieldSchema } ) ) ;
1388
1403
}
1389
1404
}
1405
+ return result ;
1406
+ } ;
1407
+
1408
+ // get the schema without refinement: `[Model]WithoutRefineSchema`
1409
+ const withoutRefineSchemaKey = `${ upperCaseFirst ( model ) } ${
1410
+ kind ? 'Prisma' + upperCaseFirst ( kind ) : ''
1411
+ } WithoutRefineSchema`;
1412
+ schema = this . zodSchemas . models [ withoutRefineSchemaKey ] as ZodObject < any > | undefined ;
1413
+
1414
+ if ( schema ) {
1415
+ // the schema has refinement, need to call refine function after schema merge
1416
+ schema = overridePasswordFields ( schema ) ;
1417
+ // refine function: `refine[Model]`
1418
+ const refineFuncKey = `refine${ upperCaseFirst ( model ) } ` ;
1419
+ const refineFunc = this . zodSchemas . models [ refineFuncKey ] as unknown as (
1420
+ schema : ZodObject < any >
1421
+ ) => ZodSchema ;
1422
+ return typeof refineFunc === 'function' ? refineFunc ( schema ) : schema ;
1423
+ } else {
1424
+ // otherwise, directly override the `@password` fields
1425
+ schema = this . zodSchemas . models [ schemaKey ] as ZodObject < any > | undefined ;
1426
+ return schema ? overridePasswordFields ( schema ) : undefined ;
1390
1427
}
1428
+ } else {
1429
+ // simply return the schema
1430
+ return this . zodSchemas . models [ schemaKey ] ;
1391
1431
}
1392
-
1393
- return result ;
1394
1432
}
1395
1433
1396
1434
/**
0 commit comments