@@ -1462,17 +1462,8 @@ public function createAttribute(string $collection, string $id, string $type, in
14621462 throw new DatabaseException ("Attribute of type: $ type requires the following filters: " . implode (", " , $ requiredFilters ));
14631463 }
14641464
1465- if (
1466- $ this ->adapter ->getLimitForAttributes () > 0 &&
1467- $ this ->adapter ->getCountOfAttributes ($ collection ) >= $ this ->adapter ->getLimitForAttributes ()
1468- ) {
1469- throw new LimitException ('Column limit reached. Cannot create new attribute. ' );
1470- }
1471-
1472- if ($ format ) {
1473- if (!Structure::hasFormat ($ format , $ type )) {
1474- throw new DatabaseException ('Format (" ' . $ format . '") not available for this attribute type (" ' . $ type . '") ' );
1475- }
1465+ if ($ format && !Structure::hasFormat ($ format , $ type )) {
1466+ throw new DatabaseException ('Format (" ' . $ format . '") not available for this attribute type (" ' . $ type . '") ' );
14761467 }
14771468
14781469 $ attribute = new Document ([
@@ -1489,22 +1480,20 @@ public function createAttribute(string $collection, string $id, string $type, in
14891480 'filters ' => $ filters ,
14901481 ]);
14911482
1492- $ collection -> setAttribute ( ' attributes ' , $ attribute, Document:: SET_TYPE_APPEND );
1483+ $ this -> checkAttribute ( $ collection , $ attribute );
14931484
1494- if (
1495- $ this ->adapter ->getDocumentSizeLimit () > 0 &&
1496- $ this ->adapter ->getAttributeWidth ($ collection ) >= $ this ->adapter ->getDocumentSizeLimit ()
1497- ) {
1498- throw new LimitException ('Row width limit reached. Cannot create new attribute. ' );
1499- }
1485+ $ collection ->setAttribute (
1486+ 'attributes ' ,
1487+ $ attribute ,
1488+ Document::SET_TYPE_APPEND
1489+ );
15001490
15011491 switch ($ type ) {
15021492 case self ::VAR_STRING :
15031493 if ($ size > $ this ->adapter ->getLimitForString ()) {
15041494 throw new DatabaseException ('Max size allowed for string is: ' . number_format ($ this ->adapter ->getLimitForString ()));
15051495 }
15061496 break ;
1507-
15081497 case self ::VAR_INTEGER :
15091498 $ limit = ($ signed ) ? $ this ->adapter ->getLimitForInt () / 2 : $ this ->adapter ->getLimitForInt ();
15101499 if ($ size > $ limit ) {
@@ -2259,8 +2248,24 @@ public function createRelationship(
22592248 }
22602249
22612250 $ this ->silent (function () use ($ collection , $ relatedCollection , $ type , $ twoWay , $ id , $ twoWayKey ) {
2262- $ this ->updateDocument (self ::METADATA , $ collection ->getId (), $ collection );
2263- $ this ->updateDocument (self ::METADATA , $ relatedCollection ->getId (), $ relatedCollection );
2251+ try {
2252+ $ this ->withTransaction (function () use ($ collection , $ relatedCollection ) {
2253+ $ this ->updateDocument (self ::METADATA , $ collection ->getId (), $ collection );
2254+ $ this ->updateDocument (self ::METADATA , $ relatedCollection ->getId (), $ relatedCollection );
2255+ });
2256+ } catch (\Throwable $ e ) {
2257+ $ this ->adapter ->deleteRelationship (
2258+ $ collection ->getId (),
2259+ $ relatedCollection ->getId (),
2260+ $ type ,
2261+ $ twoWay ,
2262+ $ id ,
2263+ $ twoWayKey ,
2264+ Database::RELATION_SIDE_PARENT
2265+ );
2266+
2267+ throw new DatabaseException ('Failed to create relationship: ' . $ e ->getMessage ());
2268+ }
22642269
22652270 $ indexKey = '_index_ ' . $ id ;
22662271 $ twoWayIndexKey = '_index_ ' . $ twoWayKey ;
@@ -2328,13 +2333,13 @@ public function updateRelationship(
23282333 !\is_null ($ newKey )
23292334 && \in_array ($ newKey , \array_map (fn ($ attribute ) => $ attribute ['key ' ], $ attributes ))
23302335 ) {
2331- throw new DuplicateException ('Attribute already exists ' );
2336+ throw new DuplicateException ('Relationship already exists ' );
23322337 }
23332338
23342339 $ attributeIndex = array_search ($ id , array_map (fn ($ attribute ) => $ attribute ['$id ' ], $ attributes ));
23352340
23362341 if ($ attributeIndex === false ) {
2337- throw new NotFoundException ('Attribute not found ' );
2342+ throw new NotFoundException ('Relationship not found ' );
23382343 }
23392344
23402345 $ attribute = $ attributes [$ attributeIndex ];
@@ -2521,7 +2526,7 @@ public function deleteRelationship(string $collection, string $id): bool
25212526 }
25222527
25232528 if (\is_null ($ relationship )) {
2524- throw new NotFoundException ('Attribute not found ' );
2529+ throw new NotFoundException ('Relationship not found ' );
25252530 }
25262531
25272532 $ collection ->setAttribute ('attributes ' , \array_values ($ attributes ));
@@ -2545,8 +2550,14 @@ public function deleteRelationship(string $collection, string $id): bool
25452550 $ relatedCollection ->setAttribute ('attributes ' , \array_values ($ relatedAttributes ));
25462551
25472552 $ this ->silent (function () use ($ collection , $ relatedCollection , $ type , $ twoWay , $ id , $ twoWayKey , $ side ) {
2548- $ this ->updateDocument (self ::METADATA , $ collection ->getId (), $ collection );
2549- $ this ->updateDocument (self ::METADATA , $ relatedCollection ->getId (), $ relatedCollection );
2553+ try {
2554+ $ this ->withTransaction (function () use ($ collection , $ relatedCollection ) {
2555+ $ this ->updateDocument (self ::METADATA , $ collection ->getId (), $ collection );
2556+ $ this ->updateDocument (self ::METADATA , $ relatedCollection ->getId (), $ relatedCollection );
2557+ });
2558+ } catch (\Throwable $ e ) {
2559+ throw new DatabaseException ('Failed to delete relationship: ' . $ e ->getMessage ());
2560+ }
25502561
25512562 $ indexKey = '_index_ ' . $ id ;
25522563 $ twoWayIndexKey = '_index_ ' . $ twoWayKey ;
@@ -2992,35 +3003,9 @@ public function getDocument(string $collection, string $id, array $queries = [],
29923003 $ attribute ['type ' ] === Database::VAR_RELATIONSHIP
29933004 );
29943005
2995- $ hasTwoWayRelationship = false ;
2996- foreach ($ relationships as $ relationship ) {
2997- if ($ relationship ['options ' ]['twoWay ' ]) {
2998- $ hasTwoWayRelationship = true ;
2999- break ;
3000- }
3001- }
3002-
3003- /**
3004- * Bug with function purity in PHPStan means it thinks $this->map is always empty
3005- * @phpstan-ignore-next-line
3006- */
3007- foreach ($ this ->map as $ key => $ value ) {
3008- [$ k , $ v ] = \explode ('=> ' , $ key );
3009- $ ck = $ this ->cacheName . '-cache- ' . $ this ->getNamespace () . ': ' . $ this ->adapter ->getTenant () . ':map: ' . $ k ;
3010- $ cache = $ this ->cache ->load ($ ck , self ::TTL , $ ck );
3011- if (empty ($ cache )) {
3012- $ cache = [];
3013- }
3014- if (!\in_array ($ v , $ cache )) {
3015- $ cache [] = $ v ;
3016- $ this ->cache ->save ($ ck , $ cache , $ ck );
3017- }
3018- }
3019-
30203006 // Don't save to cache if it's part of a relationship
3021- if (! $ hasTwoWayRelationship && empty ($ relationships )) {
3007+ if (empty ($ relationships )) {
30223008 $ this ->cache ->save ($ documentCacheKey , $ document ->getArrayCopy (), $ documentCacheHash );
3023- // Add document reference to the collection key
30243009 $ this ->cache ->save ($ collectionCacheKey , 'empty ' , $ documentCacheKey );
30253010 }
30263011
@@ -3948,7 +3933,6 @@ public function updateDocument(string $collection, string $id, Document $documen
39483933
39493934 $ document = $ this ->decode ($ collection , $ document );
39503935
3951- $ this ->purgeRelatedDocuments ($ collection , $ id );
39523936 $ this ->purgeCachedDocument ($ collection ->getId (), $ id );
39533937 $ this ->trigger (self ::EVENT_DOCUMENT_UPDATE , $ document );
39543938
@@ -4103,7 +4087,6 @@ public function updateDocuments(string $collection, Document $updates, array $qu
41034087 }
41044088
41054089 foreach ($ documents as $ document ) {
4106- $ this ->purgeRelatedDocuments ($ collection , $ document ->getId ());
41074090 $ this ->purgeCachedDocument ($ collection ->getId (), $ document ->getId ());
41084091 }
41094092
@@ -4752,7 +4735,6 @@ public function deleteDocument(string $collection, string $id): bool
47524735 return $ this ->adapter ->deleteDocument ($ collection ->getId (), $ id );
47534736 });
47544737
4755- $ this ->purgeRelatedDocuments ($ collection , $ id );
47564738 $ this ->purgeCachedDocument ($ collection ->getId (), $ id );
47574739
47584740 $ this ->trigger (self ::EVENT_DOCUMENT_DELETE , $ document );
@@ -5246,7 +5228,6 @@ public function deleteDocuments(string $collection, array $queries = [], int $ba
52465228 throw new ConflictException ('Document was updated after the request timestamp ' );
52475229 }
52485230
5249- $ this ->purgeRelatedDocuments ($ collection , $ document ->getId ());
52505231 $ this ->purgeCachedDocument ($ collection ->getId (), $ document ->getId ());
52515232 }
52525233
@@ -5292,6 +5273,8 @@ public function purgeCachedCollection(string $collectionId): bool
52925273 $ this ->cache ->purge ($ documentKey );
52935274 }
52945275
5276+ $ this ->cache ->purge ($ collectionKey );
5277+
52955278 return true ;
52965279 }
52975280
@@ -5993,39 +5976,6 @@ public static function convertQueries(Document $collection, array $queries): arr
59935976 return $ queries ;
59945977 }
59955978
5996- /**
5997- * @param Document $collection
5998- * @param string $id
5999- * @return void
6000- * @throws DatabaseException
6001- */
6002- private function purgeRelatedDocuments (Document $ collection , string $ id ): void
6003- {
6004- if ($ collection ->getId () === self ::METADATA ) {
6005- return ;
6006- }
6007-
6008- $ relationships = \array_filter (
6009- $ collection ->getAttribute ('attributes ' , []),
6010- fn ($ attribute ) =>
6011- $ attribute ['type ' ] === Database::VAR_RELATIONSHIP
6012- );
6013-
6014- if (empty ($ relationships )) {
6015- return ;
6016- }
6017-
6018- $ key = $ this ->cacheName . '-cache- ' . $ this ->getNamespace () . ':map: ' . $ collection ->getId () . ': ' . $ id ;
6019- $ cache = $ this ->cache ->load ($ key , self ::TTL , $ key );
6020- if (!empty ($ cache )) {
6021- foreach ($ cache as $ v ) {
6022- list ($ collectionId , $ documentId ) = explode (': ' , $ v );
6023- $ this ->purgeCachedDocument ($ collectionId , $ documentId );
6024- }
6025- $ this ->cache ->purge ($ key );
6026- }
6027- }
6028-
60295979 /**
60305980 * @return array<array<string, mixed>>
60315981 */
0 commit comments