diff --git a/CHANGES.md b/CHANGES.md index 21501b1bd5..5ab6e586cf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +# Version 1.3.2 + +## Bugs +- Fixed auto-setting custom ID on nested documents [#5363](https://github.com/appwrite/appwrite/pull/5363) + # Version 1.3.1 ## Bugs diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index b309b74894..5146c945ea 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2743,8 +2743,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') if (empty($related)) { continue; } - if (!\is_array($related)) { - $related = [$related]; + + $isList = \is_array($related) && \array_values($related) === $related; + + if ($isList) { + $relations = $related; + } else { + $relations = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); @@ -2752,7 +2757,15 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); - foreach ($related as $relation) { + foreach ($relations as &$relation) { + if ( + \is_array($related) + && \array_values($related) !== $related + && !isset($relation['$id']) + ) { + $relation['$id'] = ID::unique(); + $relation = new Document($relation); + } if ($relation instanceof Document) { $current = Authorization::skip( fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId()) @@ -2761,7 +2774,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') if ($current->isEmpty()) { $type = Database::PERMISSION_CREATE; - if (!isset($relation['$id']) || $relation['$id'] === 'unique()') { + if (isset($relation['$id']) && $relation['$id'] === 'unique()') { $relation['$id'] = ID::unique(); } } else { @@ -2774,6 +2787,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $checkPermissions($relatedCollection, $relation, $type); } } + + if ($isList) { + $document->setAttribute($relationship->getAttribute('key'), \array_values($relations)); + } else { + $document->setAttribute($relationship->getAttribute('key'), \reset($relations)); + } } }; @@ -3321,8 +3340,13 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum if (empty($related)) { continue; } - if (!\is_array($related)) { - $related = [$related]; + + $isList = \is_array($related) && \array_values($related) === $related; + + if ($isList) { + $relations = $related; + } else { + $relations = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); @@ -3330,7 +3354,15 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); - foreach ($related as $relation) { + foreach ($related as &$relation) { + if ( + \is_array($relation) + && \array_values($relation) !== $relation + && !isset($relation['$id']) + ) { + $relation['$id'] = ID::unique(); + $relation = new Document($relation); + } if ($relation instanceof Document) { $oldDocument = Authorization::skip(fn() => $dbForProject->getDocument( 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), @@ -3340,7 +3372,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum if ($oldDocument->isEmpty()) { $type = Database::PERMISSION_CREATE; - if (!isset($relation['$id']) || $relation['$id'] === 'unique()') { + if (isset($relation['$id']) && $relation['$id'] === 'unique()') { $relation['$id'] = ID::unique(); } } else { @@ -3353,6 +3385,12 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $checkPermissions($relatedCollection, $relation, $oldDocument, $type); } } + + if ($isList) { + $document->setAttribute($relationship->getAttribute('key'), \array_values($relations)); + } else { + $document->setAttribute($relationship->getAttribute('key'), \reset($relations)); + } } }; diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 42f83ea046..a2cb48cf93 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -3339,6 +3339,26 @@ trait DatabasesBase $this->assertEquals('Library 1', $person1['body']['library']['libraryName']); + // Create without nested ID + $person2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documentId' => ID::unique(), + 'data' => [ + 'library' => [ + 'libraryName' => 'Library 2', + ], + ], + 'permissions' => [ + Permission::read(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])), + Permission::delete(Role::user($this->getUser()['$id'])), + ] + ]); + + $this->assertEquals('Library 2', $person2['body']['library']['libraryName']); + // Ensure IDs were set and internal IDs removed $this->assertEquals($databaseId, $person1['body']['$databaseId']); $this->assertEquals($databaseId, $person1['body']['library']['$databaseId']); @@ -3901,7 +3921,7 @@ trait DatabasesBase ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, count($response['body']['documents'])); + $this->assertEquals(2, count($response['body']['documents'])); $this->assertEquals(null, $response['body']['documents'][0]['fullName']); $this->assertArrayNotHasKey("libraries", $response['body']['documents'][0]); }