@@ -523,29 +523,16 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
523523        let  createResult  =  await  Promise . all ( 
524524            enumerate ( args . data ) . map ( async  ( item )  =>  { 
525525                if  ( args . skipDuplicates )  { 
526-                     // check unique constraint conflicts 
527-                     // we can't rely on try/catch/ignore constraint violation error: https://github.com/prisma/prisma/issues/20496 
528-                     // TODO: for simple cases we should be able to translate it to an `upsert` with empty `update` payload 
529- 
530-                     // for each unique constraint, check if the input item has all fields set, and if so, check if 
531-                     // an entity already exists, and ignore accordingly 
532-                     const  uniqueConstraints  =  this . utils . getUniqueConstraints ( model ) ; 
533-                     for  ( const  constraint  of  Object . values ( uniqueConstraints ) )  { 
534-                         if  ( constraint . fields . every ( ( f )  =>  item [ f ]  !==  undefined ) )  { 
535-                             const  uniqueFilter  =  constraint . fields . reduce ( ( acc ,  f )  =>  ( {  ...acc ,  [ f ] : item [ f ]  } ) ,  { } ) ; 
536-                             const  existing  =  await  this . utils . checkExistence ( db ,  model ,  uniqueFilter ) ; 
537-                             if  ( existing )  { 
538-                                 if  ( this . shouldLogQuery )  { 
539-                                     this . logger . info ( `[policy] skipping duplicate ${ formatObject ( item ) }  ) ; 
540-                                 } 
541-                                 return  undefined ; 
542-                             } 
526+                     if  ( await  this . hasDuplicatedUniqueConstraint ( model ,  item ,  db ) )  { 
527+                         if  ( this . shouldLogQuery )  { 
528+                             this . logger . info ( `[policy] \`createMany\` skipping duplicate ${ formatObject ( item ) }  ) ; 
543529                        } 
530+                         return  undefined ; 
544531                    } 
545532                } 
546533
547534                if  ( this . shouldLogQuery )  { 
548-                     this . logger . info ( `[policy] \`create\` ${ model } ${ formatObject ( item ) }  ) ; 
535+                     this . logger . info ( `[policy] \`create\` for \`createMany\`  ${ model } ${ formatObject ( item ) }  ) ; 
549536                } 
550537                return  await  db [ model ] . create ( {  select : this . utils . makeIdSelection ( model ) ,  data : item  } ) ; 
551538            } ) 
@@ -564,6 +551,26 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
564551        } ; 
565552    } 
566553
554+     private  async  hasDuplicatedUniqueConstraint ( model : string ,  createData : any ,  db : Record < string ,  DbOperations > )  { 
555+         // check unique constraint conflicts 
556+         // we can't rely on try/catch/ignore constraint violation error: https://github.com/prisma/prisma/issues/20496 
557+         // TODO: for simple cases we should be able to translate it to an `upsert` with empty `update` payload 
558+ 
559+         // for each unique constraint, check if the input item has all fields set, and if so, check if 
560+         // an entity already exists, and ignore accordingly 
561+         const  uniqueConstraints  =  this . utils . getUniqueConstraints ( model ) ; 
562+         for  ( const  constraint  of  Object . values ( uniqueConstraints ) )  { 
563+             if  ( constraint . fields . every ( ( f )  =>  createData [ f ]  !==  undefined ) )  { 
564+                 const  uniqueFilter  =  constraint . fields . reduce ( ( acc ,  f )  =>  ( {  ...acc ,  [ f ] : createData [ f ]  } ) ,  { } ) ; 
565+                 const  existing  =  await  this . utils . checkExistence ( db ,  model ,  uniqueFilter ) ; 
566+                 if  ( existing )  { 
567+                     return  true ; 
568+                 } 
569+             } 
570+         } 
571+         return  false ; 
572+     } 
573+ 
567574    //#endregion 
568575
569576    //#region Update & Upsert 
@@ -707,17 +714,22 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
707714            postWriteChecks . push ( ...checks ) ; 
708715        } ; 
709716
710-         const  _createMany  =  async  ( model : string ,  args : any ,  context : NestedWriteVisitorContext )  =>  { 
711-             if  ( context . field ?. backLink )  { 
712-                 // handles the connection to upstream entity 
713-                 const  reversedQuery  =  this . utils . buildReversedQuery ( context ) ; 
714-                 for  ( const  item  of  enumerate ( args . data ) )  { 
715-                     Object . assign ( item ,  reversedQuery ) ; 
717+         const  _createMany  =  async  ( 
718+             model : string , 
719+             args : {  data : any ;  skipDuplicates ?: boolean  } , 
720+             context : NestedWriteVisitorContext 
721+         )  =>  { 
722+             for  ( const  item  of  enumerate ( args . data ) )  { 
723+                 if  ( args . skipDuplicates )  { 
724+                     if  ( await  this . hasDuplicatedUniqueConstraint ( model ,  item ,  db ) )  { 
725+                         if  ( this . shouldLogQuery )  { 
726+                             this . logger . info ( `[policy] \`createMany\` skipping duplicate ${ formatObject ( item ) }  ) ; 
727+                         } 
728+                         continue ; 
729+                     } 
716730                } 
731+                 await  _create ( model ,  item ,  context ) ; 
717732            } 
718-             // proceed with the create and collect post-create checks 
719-             const  {  postWriteChecks : checks  }  =  await  this . doCreateMany ( model ,  args ,  db ) ; 
720-             postWriteChecks . push ( ...checks ) ; 
721733        } ; 
722734
723735        const  _connectDisconnect  =  async  ( model : string ,  args : any ,  context : NestedWriteVisitorContext )  =>  { 
@@ -797,9 +809,6 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
797809            } , 
798810
799811            updateMany : async  ( model ,  args ,  context )  =>  { 
800-                 // injects auth guard into where clause 
801-                 this . utils . injectAuthGuard ( db ,  args ,  model ,  'update' ) ; 
802- 
803812                // prepare for post-update check 
804813                if  ( this . utils . hasAuthGuard ( model ,  'postUpdate' )  ||  this . utils . getZodSchema ( model ) )  { 
805814                    let  select  =  this . utils . makeIdSelection ( model ) ; 
@@ -809,10 +818,12 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
809818                    } 
810819                    const  reversedQuery  =  this . utils . buildReversedQuery ( context ) ; 
811820                    const  currentSetQuery  =  {  select,  where : reversedQuery  } ; 
812-                     this . utils . injectAuthGuard ( db ,  currentSetQuery ,  model ,  'read' ) ; 
821+                     this . utils . injectAuthGuardAsWhere ( db ,  currentSetQuery ,  model ,  'read' ) ; 
813822
814823                    if  ( this . shouldLogQuery )  { 
815-                         this . logger . info ( `[policy] \`findMany\` ${ model } ${ formatObject ( currentSetQuery ) }  ) ; 
824+                         this . logger . info ( 
825+                             `[policy] \`findMany\` for post update check ${ model } ${ formatObject ( currentSetQuery ) }  
826+                         ) ; 
816827                    } 
817828                    const  currentSet  =  await  db [ model ] . findMany ( currentSetQuery ) ; 
818829
@@ -825,6 +836,27 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
825836                        } ) ) 
826837                    ) ; 
827838                } 
839+ 
840+                 const  updateGuard  =  this . utils . getAuthGuard ( db ,  model ,  'update' ) ; 
841+                 if  ( this . utils . isTrue ( updateGuard )  ||  this . utils . isFalse ( updateGuard ) )  { 
842+                     // injects simple auth guard into where clause 
843+                     this . utils . injectAuthGuardAsWhere ( db ,  args ,  model ,  'update' ) ; 
844+                 }  else  { 
845+                     // we have to process `updateMany` separately because the guard may contain 
846+                     // filters using relation fields which are not allowed in nested `updateMany` 
847+                     const  reversedQuery  =  this . utils . buildReversedQuery ( context ) ; 
848+                     const  updateWhere  =  this . utils . and ( reversedQuery ,  updateGuard ) ; 
849+                     if  ( this . shouldLogQuery )  { 
850+                         this . logger . info ( 
851+                             `[policy] \`updateMany\` ${ model } ${ formatObject ( {  
852+                                 where : updateWhere ,  
853+                                 data : args . data ,  
854+                             } ) }  `
855+                         ) ; 
856+                     } 
857+                     await  db [ model ] . updateMany ( {  where : updateWhere ,  data : args . data  } ) ; 
858+                     delete  context . parent . updateMany ; 
859+                 } 
828860            } , 
829861
830862            create : async  ( model ,  args ,  context )  =>  { 
@@ -931,9 +963,21 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
931963            } , 
932964
933965            deleteMany : async  ( model ,  args ,  context )  =>  { 
934-                 // inject delete guard 
935966                const  guard  =  await  this . utils . getAuthGuard ( db ,  model ,  'delete' ) ; 
936-                 context . parent . deleteMany  =  this . utils . and ( args ,  guard ) ; 
967+                 if  ( this . utils . isTrue ( guard )  ||  this . utils . isFalse ( guard ) )  { 
968+                     // inject simple auth guard 
969+                     context . parent . deleteMany  =  this . utils . and ( args ,  guard ) ; 
970+                 }  else  { 
971+                     // we have to process `deleteMany` separately because the guard may contain 
972+                     // filters using relation fields which are not allowed in nested `deleteMany` 
973+                     const  reversedQuery  =  this . utils . buildReversedQuery ( context ) ; 
974+                     const  deleteWhere  =  this . utils . and ( reversedQuery ,  guard ) ; 
975+                     if  ( this . shouldLogQuery )  { 
976+                         this . logger . info ( `[policy] \`deleteMany\` ${ model } ${ formatObject ( {  where : deleteWhere  } ) }  ) ; 
977+                     } 
978+                     await  db [ model ] . deleteMany ( {  where : deleteWhere  } ) ; 
979+                     delete  context . parent . deleteMany ; 
980+                 } 
937981            } , 
938982        } ) ; 
939983
@@ -958,13 +1002,17 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
9581002        } 
9591003        for  ( const  k  of  Object . keys ( args ) )  { 
9601004            const  field  =  resolveField ( this . modelMeta ,  model ,  k ) ; 
961-             if  ( field ?. isId  ||  field ?. isForeignKey )  { 
1005+             if  ( this . isAutoIncrementIdField ( field )  ||  field ?. isForeignKey )  { 
9621006                return  true ; 
9631007            } 
9641008        } 
9651009        return  false ; 
9661010    } 
9671011
1012+     private  isAutoIncrementIdField ( field : FieldInfo )  { 
1013+         return  field . isId  &&  field . isAutoIncrement ; 
1014+     } 
1015+ 
9681016    async  updateMany ( args : any )  { 
9691017        if  ( ! args )  { 
9701018            throw  prismaClientValidationError ( this . prisma ,  'query argument is required' ) ; 
@@ -976,7 +1024,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
9761024        this . utils . tryReject ( this . prisma ,  this . model ,  'update' ) ; 
9771025
9781026        args  =  this . utils . clone ( args ) ; 
979-         this . utils . injectAuthGuard ( this . prisma ,  args ,  this . model ,  'update' ) ; 
1027+         this . utils . injectAuthGuardAsWhere ( this . prisma ,  args ,  this . model ,  'update' ) ; 
9801028
9811029        if  ( this . utils . hasAuthGuard ( this . model ,  'postUpdate' )  ||  this . utils . getZodSchema ( this . model ) )  { 
9821030            // use a transaction to do post-update checks 
@@ -989,7 +1037,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
9891037                    select  =  {  ...select ,  ...preValueSelect  } ; 
9901038                } 
9911039                const  currentSetQuery  =  {  select,  where : args . where  } ; 
992-                 this . utils . injectAuthGuard ( tx ,  currentSetQuery ,  this . model ,  'read' ) ; 
1040+                 this . utils . injectAuthGuardAsWhere ( tx ,  currentSetQuery ,  this . model ,  'read' ) ; 
9931041
9941042                if  ( this . shouldLogQuery )  { 
9951043                    this . logger . info ( `[policy] \`findMany\` ${ this . model } ${ formatObject ( currentSetQuery ) }  ) ; 
@@ -1118,7 +1166,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
11181166
11191167        // inject policy conditions 
11201168        args  =  args  ??  { } ; 
1121-         this . utils . injectAuthGuard ( this . prisma ,  args ,  this . model ,  'delete' ) ; 
1169+         this . utils . injectAuthGuardAsWhere ( this . prisma ,  args ,  this . model ,  'delete' ) ; 
11221170
11231171        // conduct the deletion 
11241172        if  ( this . shouldLogQuery )  { 
@@ -1139,7 +1187,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
11391187        args  =  this . utils . clone ( args ) ; 
11401188
11411189        // inject policy conditions 
1142-         this . utils . injectAuthGuard ( this . prisma ,  args ,  this . model ,  'read' ) ; 
1190+         this . utils . injectAuthGuardAsWhere ( this . prisma ,  args ,  this . model ,  'read' ) ; 
11431191
11441192        if  ( this . shouldLogQuery )  { 
11451193            this . logger . info ( `[policy] \`aggregate\` ${ this . model } ${ formatObject ( args ) }  ) ; 
@@ -1155,7 +1203,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
11551203        args  =  this . utils . clone ( args ) ; 
11561204
11571205        // inject policy conditions 
1158-         this . utils . injectAuthGuard ( this . prisma ,  args ,  this . model ,  'read' ) ; 
1206+         this . utils . injectAuthGuardAsWhere ( this . prisma ,  args ,  this . model ,  'read' ) ; 
11591207
11601208        if  ( this . shouldLogQuery )  { 
11611209            this . logger . info ( `[policy] \`groupBy\` ${ this . model } ${ formatObject ( args ) }  ) ; 
@@ -1166,7 +1214,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
11661214    async  count ( args : any )  { 
11671215        // inject policy conditions 
11681216        args  =  args  ? this . utils . clone ( args )  : { } ; 
1169-         this . utils . injectAuthGuard ( this . prisma ,  args ,  this . model ,  'read' ) ; 
1217+         this . utils . injectAuthGuardAsWhere ( this . prisma ,  args ,  this . model ,  'read' ) ; 
11701218
11711219        if  ( this . shouldLogQuery )  { 
11721220            this . logger . info ( `[policy] \`count\` ${ this . model } ${ formatObject ( args ) }  ) ; 
0 commit comments