@@ -826,6 +826,8 @@ export class PolicyUtil extends QueryUtils {
826826 /**
827827 * Given a model and a unique filter, checks the operation is allowed by policies and field validations.
828828 * Rejects with an error if not allowed.
829+ *
830+ * This method is only called by mutation operations.
829831 */
830832 async checkPolicyForUnique (
831833 model : string ,
@@ -1365,32 +1367,68 @@ export class PolicyUtil extends QueryUtils {
13651367 excludePasswordFields : boolean = true ,
13661368 kind : 'create' | 'update' | undefined = undefined
13671369 ) {
1370+ if ( ! this . zodSchemas ) {
1371+ return undefined ;
1372+ }
1373+
13681374 if ( ! this . hasFieldValidation ( model ) ) {
13691375 return undefined ;
13701376 }
1377+
13711378 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 } ) ) ;
13861402 }
1387- result = result ?. merge ( z . object ( { [ key ] : pwFieldSchema } ) ) ;
13881403 }
13891404 }
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 ;
13901427 }
1428+ } else {
1429+ // simply return the schema
1430+ return this . zodSchemas . models [ schemaKey ] ;
13911431 }
1392-
1393- return result ;
13941432 }
13951433
13961434 /**
0 commit comments