2727use Utopia \Database \Validator \Authorization ;
2828use Utopia \Database \Validator \Index as IndexValidator ;
2929use Utopia \Database \Validator \IndexDependency as IndexDependencyValidator ;
30- use Utopia \Database \Validator \Operator as OperatorValidator ;
3130use Utopia \Database \Validator \PartialStructure ;
3231use Utopia \Database \Validator \Permissions ;
3332use Utopia \Database \Validator \Queries \Document as DocumentValidator ;
@@ -4952,20 +4951,7 @@ public function updateDocument(string $collection, string $id, Document $documen
49524951 }
49534952 $ createdAt = $ document ->getCreatedAt ();
49544953
4955- // Extract operators from the document before merging
4956- $ documentArray = $ document ->getArrayCopy ();
4957- $ extracted = Operator::extractOperators ($ documentArray );
4958- $ operators = $ extracted ['operators ' ];
4959- $ updates = $ extracted ['updates ' ];
4960-
4961- $ operatorValidator = new OperatorValidator ($ collection , $ old );
4962- foreach ($ operators as $ attribute => $ operator ) {
4963- if (!$ operatorValidator ->isValid ($ operator )) {
4964- throw new StructureException ($ operatorValidator ->getDescription ());
4965- }
4966- }
4967-
4968- $ document = \array_merge ($ old ->getArrayCopy (), $ updates );
4954+ $ document = \array_merge ($ old ->getArrayCopy (), $ document ->getArrayCopy ());
49694955 $ document ['$collection ' ] = $ old ->getAttribute ('$collection ' ); // Make sure user doesn't switch collection ID
49704956 $ document ['$createdAt ' ] = ($ createdAt === null || !$ this ->preserveDates ) ? $ old ->getCreatedAt () : $ createdAt ;
49714957
@@ -4989,8 +4975,11 @@ public function updateDocument(string $collection, string $id, Document $documen
49894975 $ relationships [$ relationship ->getAttribute ('key ' )] = $ relationship ;
49904976 }
49914977
4992- if (!empty ($ operators )) {
4993- $ shouldUpdate = true ;
4978+ foreach ($ document as $ key => $ value ) {
4979+ if (Operator::isOperator ($ value )) {
4980+ $ shouldUpdate = true ;
4981+ break ;
4982+ }
49944983 }
49954984
49964985 // Compare if the document has any changes
@@ -5110,7 +5099,8 @@ public function updateDocument(string $collection, string $id, Document $documen
51105099 $ this ->adapter ->getIdAttributeType (),
51115100 $ this ->adapter ->getMinDateTime (),
51125101 $ this ->adapter ->getMaxDateTime (),
5113- $ this ->adapter ->getSupportForAttributes ()
5102+ $ this ->adapter ->getSupportForAttributes (),
5103+ $ old
51145104 );
51155105 if (!$ structureValidator ->isValid ($ document )) { // Make sure updated structure still apply collection rules (if any)
51165106 throw new StructureException ($ structureValidator ->getDescription ());
@@ -5120,22 +5110,24 @@ public function updateDocument(string $collection, string $id, Document $documen
51205110 $ document = $ this ->silent (fn () => $ this ->updateDocumentRelationships ($ collection , $ old , $ document ));
51215111 }
51225112
5123-
51245113 $ document = $ this ->adapter ->castingBefore ($ collection , $ document );
51255114
5126- // Re-add operators to document for adapter processing
5127- foreach ($ operators as $ key => $ operator ) {
5128- $ document ->setAttribute ($ key , $ operator );
5129- }
5130-
51315115 $ this ->adapter ->updateDocument ($ collection , $ id , $ document , $ skipPermissionsUpdate );
51325116
51335117 $ document = $ this ->adapter ->castingAfter ($ collection , $ document );
51345118
51355119 $ this ->purgeCachedDocument ($ collection ->getId (), $ id );
51365120
51375121 // If operators were used, refetch document to get computed values
5138- if (!empty ($ operators )) {
5122+ $ hasOperators = false ;
5123+ foreach ($ document ->getArrayCopy () as $ value ) {
5124+ if (Operator::isOperator ($ value )) {
5125+ $ hasOperators = true ;
5126+ break ;
5127+ }
5128+ }
5129+
5130+ if ($ hasOperators ) {
51395131 $ refetched = $ this ->refetchDocuments ($ collection , [$ document ]);
51405132 $ document = $ refetched [0 ];
51415133 }
@@ -5258,24 +5250,17 @@ public function updateDocuments(
52585250 applyDefaults: false
52595251 );
52605252
5261- // Separate operators from regular updates for validation
5262- $ extracted = Operator::extractOperators ($ updates ->getArrayCopy ());
5263- $ operators = $ extracted ['operators ' ];
5264- $ regularUpdates = $ extracted ['updates ' ];
5265-
5266- // Only validate regular updates, not operators
5267- if (!empty ($ regularUpdates )) {
5268- $ validator = new PartialStructure (
5269- $ collection ,
5270- $ this ->adapter ->getIdAttributeType (),
5271- $ this ->adapter ->getMinDateTime (),
5272- $ this ->adapter ->getMaxDateTime (),
5273- $ this ->adapter ->getSupportForAttributes ()
5274- );
5253+ $ validator = new PartialStructure (
5254+ $ collection ,
5255+ $ this ->adapter ->getIdAttributeType (),
5256+ $ this ->adapter ->getMinDateTime (),
5257+ $ this ->adapter ->getMaxDateTime (),
5258+ $ this ->adapter ->getSupportForAttributes (),
5259+ null // No old document available in bulk updates
5260+ );
52755261
5276- if (!$ validator ->isValid (new Document ($ regularUpdates ))) {
5277- throw new StructureException ($ validator ->getDescription ());
5278- }
5262+ if (!$ validator ->isValid ($ updates )) {
5263+ throw new StructureException ($ validator ->getDescription ());
52795264 }
52805265
52815266 $ originalLimit = $ limit ;
@@ -5311,17 +5296,8 @@ public function updateDocuments(
53115296 $ currentPermissions = $ updates ->getPermissions ();
53125297 sort ($ currentPermissions );
53135298
5314- $ this ->withTransaction (function () use ($ collection , $ updates , &$ batch , $ currentPermissions, $ operators ) {
5299+ $ this ->withTransaction (function () use ($ collection , $ updates , &$ batch , $ currentPermissions ) {
53155300 foreach ($ batch as $ index => $ document ) {
5316- if (!empty ($ operators )) {
5317- $ operatorValidator = new OperatorValidator ($ collection , $ document );
5318- foreach ($ operators as $ attribute => $ operator ) {
5319- if (!$ operatorValidator ->isValid ($ operator )) {
5320- throw new StructureException ($ operatorValidator ->getDescription ());
5321- }
5322- }
5323- }
5324-
53255301 $ skipPermissionsUpdate = true ;
53265302
53275303 if ($ updates ->offsetExists ('$permissions ' )) {
@@ -5369,7 +5345,15 @@ public function updateDocuments(
53695345
53705346 $ updates = $ this ->adapter ->castingBefore ($ collection , $ updates );
53715347
5372- if (!empty ($ operators )) {
5348+ $ hasOperators = false ;
5349+ foreach ($ updates ->getArrayCopy () as $ value ) {
5350+ if (Operator::isOperator ($ value )) {
5351+ $ hasOperators = true ;
5352+ break ;
5353+ }
5354+ }
5355+
5356+ if ($ hasOperators ) {
53735357 $ batch = $ this ->refetchDocuments ($ collection , $ batch );
53745358 }
53755359
@@ -6035,45 +6019,19 @@ public function upsertDocumentsWithIncrease(
60356019 }
60366020 }
60376021
6038- // Extract operators for validation
6039- $ documentArray = $ document ->getArrayCopy ();
6040- $ extracted = Operator::extractOperators ($ documentArray );
6041- $ operators = $ extracted ['operators ' ];
6042- $ regularUpdates = $ extracted ['updates ' ];
6043-
6044- $ operatorValidator = new OperatorValidator ($ collection , $ old ->isEmpty () ? null : $ old );
6045- foreach ($ operators as $ attribute => $ operator ) {
6046- if (!$ operatorValidator ->isValid ($ operator )) {
6047- throw new StructureException ($ operatorValidator ->getDescription ());
6048- }
6049- }
6050-
6051- // Create a temporary document with only regular updates for encoding and validation
6052- $ tempDocument = new Document ($ regularUpdates );
6053- $ tempDocument ->setAttribute ('$id ' , $ document ->getId ());
6054- $ tempDocument ->setAttribute ('$collection ' , $ document ->getAttribute ('$collection ' ));
6055- $ tempDocument ->setAttribute ('$createdAt ' , $ document ->getAttribute ('$createdAt ' ));
6056- $ tempDocument ->setAttribute ('$updatedAt ' , $ document ->getAttribute ('$updatedAt ' ));
6057- $ tempDocument ->setAttribute ('$permissions ' , $ document ->getAttribute ('$permissions ' ));
6058- if ($ this ->adapter ->getSharedTables ()) {
6059- $ tempDocument ->setAttribute ('$tenant ' , $ document ->getAttribute ('$tenant ' ));
6060- }
6061-
6062- $ encodedTemp = $ this ->encode ($ collection , $ tempDocument );
6063-
60646022 $ validator = new Structure (
60656023 $ collection ,
60666024 $ this ->adapter ->getIdAttributeType (),
60676025 $ this ->adapter ->getMinDateTime (),
60686026 $ this ->adapter ->getMaxDateTime (),
6069- $ this ->adapter ->getSupportForAttributes ()
6027+ $ this ->adapter ->getSupportForAttributes (),
6028+ $ old ->isEmpty () ? null : $ old
60706029 );
60716030
6072- if (!$ validator ->isValid ($ encodedTemp )) {
6031+ if (!$ validator ->isValid ($ document )) {
60736032 throw new StructureException ($ validator ->getDescription ());
60746033 }
60756034
6076- // Now encode the full document with operators for the adapter
60776035 $ document = $ this ->encode ($ collection , $ document );
60786036
60796037 if (!$ old ->isEmpty ()) {
0 commit comments