diff --git a/src/Database/Database.php b/src/Database/Database.php index c90d68c6b..3f1771809 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -2995,7 +2995,14 @@ private function updateDocumentRelationships(Document $collection, Document $old switch ($relationType) { case Database::RELATION_ONE_TO_ONE: if (!$twoWay) { - if ($value instanceof Document) { + if (\is_string($value)) { + $related = $this->getDocument($relatedCollection->getId(), $value); + if ($related->isEmpty()) { + // If no such document exists in related collection + // For one-one we need to update the related key to null if no relation exists + $document->setAttribute($key, null); + } + } elseif ($value instanceof Document) { $relationId = $this->relateDocuments( $collection, $relatedCollection, @@ -3015,7 +3022,12 @@ private function updateDocumentRelationships(Document $collection, Document $old switch (\gettype($value)) { case 'string': $related = $this->skipRelationships(fn () => $this->getDocument($relatedCollection->getId(), $value)); - + if ($related->isEmpty()) { + // If no such document exists in related collection + // For one-one we need to update the related key to null if no relation exists + $document->setAttribute($key, null); + break; + } if ( $oldValue?->getId() !== $value && $this->skipRelationships(fn () => $this->findOne($relatedCollection->getId(), [ @@ -3133,6 +3145,10 @@ private function updateDocumentRelationships(Document $collection, Document $old $this->getDocument($relatedCollection->getId(), $relation) ); + if ($related->isEmpty()) { + continue; + } + $this->skipRelationships(fn () => $this->updateDocument( $relatedCollection->getId(), $related->getId(), @@ -3166,6 +3182,12 @@ private function updateDocumentRelationships(Document $collection, Document $old } if (\is_string($value)) { + $related = $this->getDocument($relatedCollection->getId(), $value); + if ($related->isEmpty()) { + // If no such document exists in related collection + // For many-one we need to update the related key to null if no relation exists + $document->setAttribute($key, null); + } $this->deleteCachedDocument($relatedCollection->getId(), $value); } elseif ($value instanceof Document) { $related = $this->getDocument($relatedCollection->getId(), $value->getId()); @@ -3233,7 +3255,7 @@ private function updateDocumentRelationships(Document $collection, Document $old foreach ($value as $relation) { if (\is_string($relation)) { - if (\in_array($relation, $oldIds)) { + if (\in_array($relation, $oldIds) || $this->getDocument($relatedCollection->getId(), $relation)->isEmpty()) { continue; } } elseif ($relation instanceof Document) { diff --git a/tests/Database/Base.php b/tests/Database/Base.php index 8a83b39ba..1b3d5ee77 100644 --- a/tests/Database/Base.php +++ b/tests/Database/Base.php @@ -4095,6 +4095,23 @@ public function testOneToOneOneWayRelationship(): void ], ])); + // Update a document with non existing related document. It should not get added to the list. + static::getDatabase()->updateDocument( + 'person', + 'person1', + $person1->setAttribute('library', 'no-library') + ); + + $person1Document = static::getDatabase()->getDocument('person', 'person1'); + // Assert document does not contain non existing relation document. + $this->assertEquals(null, $person1Document->getAttribute('library')); + + static::getDatabase()->updateDocument( + 'person', + 'person1', + $person1->setAttribute('library', 'library1') + ); + // Update through create $library10 = static::getDatabase()->createDocument('library', new Document([ '$id' => 'library10', @@ -4510,6 +4527,13 @@ public function testOneToOneTwoWayRelationship(): void $country1 = static::getDatabase()->getDocument('country', 'country1'); $this->assertEquals('London', $country1->getAttribute('city')->getAttribute('name')); + // Update a document with non existing related document. It should not get added to the list. + static::getDatabase()->updateDocument('country', 'country1', $doc->setAttribute('city', 'no-city')); + + $country1Document = static::getDatabase()->getDocument('country', 'country1'); + // Assert document does not contain non existing relation document. + $this->assertEquals(null, $country1Document->getAttribute('city')); + static::getDatabase()->updateDocument('country', 'country1', $doc->setAttribute('city', 'city1')); try { static::getDatabase()->deleteDocument('country', 'country1'); $this->fail('Failed to throw exception'); @@ -5135,6 +5159,13 @@ public function testOneToManyOneWayRelationship(): void ], ])); + // Update a document with non existing related document. It should not get added to the list. + static::getDatabase()->updateDocument('artist', 'artist1', $artist1->setAttribute('albums', ['album1', 'no-album'])); + + $artist1Document = static::getDatabase()->getDocument('artist', 'artist1'); + // Assert document does not contain non existing relation document. + $this->assertEquals(1, \count($artist1Document->getAttribute('albums'))); + // Create document with relationship with related ID static::getDatabase()->createDocument('album', new Document([ '$id' => 'album2', @@ -5513,6 +5544,14 @@ public function testOneToManyTwoWayRelationship(): void ], ], ])); + + // Update a document with non existing related document. It should not get added to the list. + static::getDatabase()->updateDocument('customer', 'customer1', $customer1->setAttribute('accounts', ['account1','no-account'])); + + $customer1Document = static::getDatabase()->getDocument('customer', 'customer1'); + // Assert document does not contain non existing relation document. + $this->assertEquals(1, \count($customer1Document->getAttribute('accounts'))); + // Create document with relationship with related ID $account2 = static::getDatabase()->createDocument('account', new Document([ '$id' => 'account2', @@ -5954,6 +5993,15 @@ public function testManyToOneOneWayRelationship(): void ], ])); + // Update a document with non existing related document. It should not get added to the list. + static::getDatabase()->updateDocument('review', 'review1', $review1->setAttribute('movie', 'no-movie')); + + $review1Document = static::getDatabase()->getDocument('review', 'review1'); + // Assert document does not contain non existing relation document. + $this->assertEquals(null, $review1Document->getAttribute('movie')); + + static::getDatabase()->updateDocument('review', 'review1', $review1->setAttribute('movie', 'movie1')); + // Create document with relationship to existing document by ID $review10 = static::getDatabase()->createDocument('review', new Document([ '$id' => 'review10', @@ -6281,6 +6329,15 @@ public function testManyToOneTwoWayRelationship(): void ], ])); + // Update a document with non existing related document. It should not get added to the list. + static::getDatabase()->updateDocument('product', 'product1', $product1->setAttribute('store', 'no-store')); + + $product1Document = static::getDatabase()->getDocument('product', 'product1'); + // Assert document does not contain non existing relation document. + $this->assertEquals(null, $product1Document->getAttribute('store')); + + static::getDatabase()->updateDocument('product', 'product1', $product1->setAttribute('store', 'store1')); + // Create document with relationship with related ID static::getDatabase()->createDocument('store', new Document([ '$id' => 'store2', @@ -6741,6 +6798,13 @@ public function testManyToManyOneWayRelationship(): void ] ])); + // Update a document with non existing related document. It should not get added to the list. + static::getDatabase()->updateDocument('playlist', 'playlist1', $playlist1->setAttribute('songs', ['song1','no-song'])); + + $playlist1Document = static::getDatabase()->getDocument('playlist', 'playlist1'); + // Assert document does not contain non existing relation document. + $this->assertEquals(1, \count($playlist1Document->getAttribute('songs'))); + $documents = static::getDatabase()->find('playlist', [ Query::select(['name']), Query::limit(1) @@ -7032,6 +7096,13 @@ public function testManyToManyTwoWayRelationship(): void ], ])); + // Update a document with non existing related document. It should not get added to the list. + static::getDatabase()->updateDocument('students', 'student1', $student1->setAttribute('classes', ['class1', 'no-class'])); + + $student1Document = static::getDatabase()->getDocument('students', 'student1'); + // Assert document does not contain non existing relation document. + $this->assertEquals(1, \count($student1Document->getAttribute('classes'))); + // Create document with relationship with related ID static::getDatabase()->createDocument('classes', new Document([ '$id' => 'class2',