diff --git a/composer.lock b/composer.lock index bc7ac3269b..47a32cf774 100644 --- a/composer.lock +++ b/composer.lock @@ -4679,16 +4679,16 @@ }, { "name": "utopia-php/platform", - "version": "0.7.12", + "version": "0.7.13", "source": { "type": "git", "url": "https://github.com/utopia-php/platform.git", - "reference": "04255de21db75e90b170040f4d1b457ba721e7a5" + "reference": "77a863a920122e2c6a6bc6ee5548d366a3f4c6c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/platform/zipball/04255de21db75e90b170040f4d1b457ba721e7a5", - "reference": "04255de21db75e90b170040f4d1b457ba721e7a5", + "url": "https://api.github.com/repos/utopia-php/platform/zipball/77a863a920122e2c6a6bc6ee5548d366a3f4c6c7", + "reference": "77a863a920122e2c6a6bc6ee5548d366a3f4c6c7", "shasum": "" }, "require": { @@ -4701,6 +4701,7 @@ }, "require-dev": { "laravel/pint": "1.*", + "phpstan/phpstan": "2.*", "phpunit/phpunit": "9.*" }, "type": "library", @@ -4723,9 +4724,9 @@ ], "support": { "issues": "https://github.com/utopia-php/platform/issues", - "source": "https://github.com/utopia-php/platform/tree/0.7.12" + "source": "https://github.com/utopia-php/platform/tree/0.7.13" }, - "time": "2025-09-05T15:53:12+00:00" + "time": "2025-12-08T10:02:40+00:00" }, { "name": "utopia-php/pools", diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php index 9fb438d577..812bae16e2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php @@ -108,8 +108,10 @@ class Create extends Action throw new Exception($this->getLimitException(), 'Index limit exceeded'); } - // Convert Document array to array of attribute metadata - $oldAttributes = \array_map(fn ($a) => $a->getArrayCopy(), $collection->getAttribute('attributes')); + $oldAttributes = \array_map( + fn ($a) => $a->getArrayCopy(), + $collection->getAttribute('attributes') + ); $oldAttributes[] = [ 'key' => '$id', @@ -120,7 +122,6 @@ class Create extends Action 'default' => null, 'size' => Database::LENGTH_KEY ]; - $oldAttributes[] = [ 'key' => '$createdAt', 'type' => Database::VAR_DATETIME, @@ -131,7 +132,6 @@ class Create extends Action 'default' => null, 'size' => 0 ]; - $oldAttributes[] = [ 'key' => '$updatedAt', 'type' => Database::VAR_DATETIME, @@ -145,7 +145,6 @@ class Create extends Action $contextType = $this->getParentContext(); foreach ($attributes as $i => $attribute) { - // find attribute metadata in collection document $attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key')); if ($attributeIndex === false) { @@ -160,7 +159,6 @@ class Create extends Action throw new Exception($this->getParentInvalidTypeException(), "Cannot create an index for a relationship $contextType: " . $oldAttributes[$attributeIndex]['key']); } - // Ensure attribute is available if ($attributeStatus !== 'available') { $contextType = ucfirst($contextType); throw new Exception($this->getParentNotAvailableException(), "$contextType not available: " . $oldAttributes[$attributeIndex]['key']); @@ -171,8 +169,8 @@ class Create extends Action } if ($attributeArray === true) { - $lengths[$i] = Database::MAX_ARRAY_INDEX_LENGTH; - $orders[$i] = null; + // Because of a bug in MySQL, we cannot create indexes on array attributes for now, otherwise queries break. + throw new Exception(Exception::INDEX_INVALID, 'Creating indexes on array attributes is not currently supported.'); } } diff --git a/tests/e2e/Services/Databases/Legacy/DatabasesBase.php b/tests/e2e/Services/Databases/Legacy/DatabasesBase.php index 409668dc46..12981ff262 100644 --- a/tests/e2e/Services/Databases/Legacy/DatabasesBase.php +++ b/tests/e2e/Services/Databases/Legacy/DatabasesBase.php @@ -1352,7 +1352,7 @@ trait DatabasesBase ]); $this->assertEquals(400, $fulltextArray['headers']['status-code']); - $this->assertEquals('"Fulltext" index is forbidden on array attributes', $fulltextArray['body']['message']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $fulltextArray['body']['message']); $actorsArray = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -1364,7 +1364,8 @@ trait DatabasesBase 'attributes' => ['actors'], ]); - $this->assertEquals(202, $actorsArray['headers']['status-code']); + $this->assertEquals(400, $actorsArray['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $actorsArray['body']['message']); $twoLevelsArray = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -1377,7 +1378,8 @@ trait DatabasesBase 'orders' => ['DESC', 'DESC'], ]); - $this->assertEquals(202, $twoLevelsArray['headers']['status-code']); + $this->assertEquals(400, $twoLevelsArray['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $twoLevelsArray['body']['message']); $unknown = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -1403,7 +1405,8 @@ trait DatabasesBase 'orders' => ['DESC'], // Check order is removed in API ]); - $this->assertEquals(202, $index1['headers']['status-code']); + $this->assertEquals(400, $index1['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $index1['body']['message']); $index2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -1415,7 +1418,8 @@ trait DatabasesBase 'attributes' => ['integers'], // array attribute ]); - $this->assertEquals(202, $index2['headers']['status-code']); + $this->assertEquals(400, $index2['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $index2['body']['message']); /** * Create Indexes by worker @@ -1429,7 +1433,7 @@ trait DatabasesBase ]), []); $this->assertIsArray($movies['body']['indexes']); - $this->assertCount(8, $movies['body']['indexes']); + $this->assertCount(4, $movies['body']['indexes']); $this->assertEquals($titleIndex['body']['key'], $movies['body']['indexes'][0]['key']); $this->assertEquals($releaseYearIndex['body']['key'], $movies['body']['indexes'][1]['key']); $this->assertEquals($releaseWithDate1['body']['key'], $movies['body']['indexes'][2]['key']); @@ -1483,8 +1487,7 @@ trait DatabasesBase $this->assertEquals('lengthTestIndex', $index['body']['key']); $this->assertEquals([128, 200], $index['body']['lengths']); - // Test case for lengths array overriding - // set a length for an array attribute, it should get overriden with Database::MAX_ARRAY_INDEX_LENGTH + // Test case for array attribute index (should be blocked) $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -1495,14 +1498,8 @@ trait DatabasesBase 'attributes' => ['actors'], 'lengths' => [120] ]); - $this->assertEquals(202, $create['headers']['status-code']); - - $index = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$collectionId}/indexes/lengthOverrideTestIndex", [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]); - $this->assertEquals([Database::MAX_ARRAY_INDEX_LENGTH], $index['body']['lengths']); + $this->assertEquals(400, $create['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $create['body']['message']); // Test case for count of lengths greater than attributes (should throw 400) $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ diff --git a/tests/e2e/Services/Databases/TablesDB/DatabasesBase.php b/tests/e2e/Services/Databases/TablesDB/DatabasesBase.php index f7739567c8..f2df01ebb0 100644 --- a/tests/e2e/Services/Databases/TablesDB/DatabasesBase.php +++ b/tests/e2e/Services/Databases/TablesDB/DatabasesBase.php @@ -1334,7 +1334,7 @@ trait DatabasesBase ]); $this->assertEquals(400, $fulltextArray['headers']['status-code']); - $this->assertEquals('"Fulltext" index is forbidden on array attributes', $fulltextArray['body']['message']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $fulltextArray['body']['message']); $actorsArray = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -1346,7 +1346,8 @@ trait DatabasesBase 'columns' => ['actors'], ]); - $this->assertEquals(202, $actorsArray['headers']['status-code']); + $this->assertEquals(400, $actorsArray['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $actorsArray['body']['message']); $twoLevelsArray = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -1359,7 +1360,8 @@ trait DatabasesBase 'orders' => ['DESC', 'DESC'], ]); - $this->assertEquals(202, $twoLevelsArray['headers']['status-code']); + $this->assertEquals(400, $twoLevelsArray['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $twoLevelsArray['body']['message']); $unknown = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -1385,7 +1387,8 @@ trait DatabasesBase 'orders' => ['DESC'], // Check order is removed in API ]); - $this->assertEquals(202, $index1['headers']['status-code']); + $this->assertEquals(400, $index1['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $index1['body']['message']); $index2 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $data['moviesId'] . '/indexes', array_merge([ 'content-type' => 'application/json', @@ -1397,7 +1400,8 @@ trait DatabasesBase 'columns' => ['integers'], // array column ]); - $this->assertEquals(202, $index2['headers']['status-code']); + $this->assertEquals(400, $index2['headers']['status-code']); + $this->assertEquals('Creating indexes on array attributes is not currently supported.', $index2['body']['message']); /** * Create Indexes by worker @@ -1411,7 +1415,7 @@ trait DatabasesBase ]), []); $this->assertIsArray($movies['body']['indexes']); - $this->assertCount(8, $movies['body']['indexes']); + $this->assertCount(4, $movies['body']['indexes']); $this->assertEquals($titleIndex['body']['key'], $movies['body']['indexes'][0]['key']); $this->assertEquals($releaseYearIndex['body']['key'], $movies['body']['indexes'][1]['key']); $this->assertEquals($releaseWithDate1['body']['key'], $movies['body']['indexes'][2]['key']);