added spatial index tests

This commit is contained in:
ArnabChatterjee20k
2025-08-26 20:54:55 +05:30
parent 3755d58d62
commit b28ec182d7
4 changed files with 223 additions and 5 deletions
@@ -71,7 +71,7 @@ class Create extends Action
->param('databaseId', '', new UID(), 'Database ID.')
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
->param('key', null, new Key(), 'Index Key.')
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE]), 'Index type.')
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL]), 'Index type.')
->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.')
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional: true)
@@ -190,11 +190,29 @@ class Create extends Action
'orders' => $orders,
]);
// Determine adapter capabilities. For TablesDB, be permissive to accept requests
// and let the background worker enforce engine-specific constraints.
$maxIndexLength = $dbForProject->getAdapter()->getMaxIndexLength();
$internalIndexesKeys = $dbForProject->getAdapter()->getInternalIndexesKeys();
$supportForIndexArray = $dbForProject->getAdapter()->getSupportForIndexArray();
$supportForSpatialAttributes = $dbForProject->getAdapter()->getSupportForSpatialAttributes();
$supportForSpatialIndexNull = $dbForProject->getAdapter()->getSupportForSpatialIndexNull();
$supportForSpatialIndexOrder = $dbForProject->getAdapter()->getSupportForSpatialIndexOrder();
if (!$this->isCollectionsAPI()) {
// Relax spatial constraints for TablesDB API
$supportForSpatialIndexNull = true;
$supportForSpatialIndexOrder = true;
}
$validator = new IndexValidator(
$collection->getAttribute('attributes'),
$dbForProject->getAdapter()->getMaxIndexLength(),
$dbForProject->getAdapter()->getInternalIndexesKeys(),
$dbForProject->getAdapter()->getSupportForIndexArray()
$maxIndexLength,
$internalIndexesKeys,
$supportForIndexArray,
$supportForSpatialAttributes,
$supportForSpatialIndexNull,
$supportForSpatialIndexOrder
);
if (!$validator->isValid($index)) {
@@ -58,7 +58,7 @@ class Create extends IndexCreate
->param('databaseId', '', new UID(), 'Database ID.')
->param('tableId', '', new UID(), 'Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/tablesdb#tablesDBCreate).')
->param('key', null, new Key(), 'Index Key.')
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE]), 'Index type.')
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL]), 'Index type.')
->param('columns', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of columns to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' columns are allowed, each 32 characters long.')
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional: true)
@@ -7261,4 +7261,104 @@ trait DatabasesBase
'x-appwrite-key' => $this->getProject()['apiKey']
]));
}
public function testSpatialIndex(): void
{
$database = $this->client->call(Client::METHOD_POST, '/databases', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
], [
'databaseId' => ID::unique(),
'name' => 'Spatial Index Test DB'
]);
$this->assertEquals(201, $database['headers']['status-code']);
$databaseId = $database['body']['$id'];
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'collectionId' => ID::unique(),
'name' => 'SpatialIdx',
'documentSecurity' => true,
'permissions' => [
Permission::create(Role::any()),
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
]);
$this->assertEquals(201, $collection['headers']['status-code']);
$collectionId = $collection['body']['$id'];
// Create spatial attributes: one required, one optional
$reqPoint = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/point', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'pRequired',
'required' => true,
]);
$this->assertEquals(202, $reqPoint['headers']['status-code']);
$optPoint = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/point', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'pOptional',
'required' => false,
]);
$this->assertEquals(202, $optPoint['headers']['status-code']);
// Ensure attributes are available
sleep(2);
// Create index on required spatial attribute (should succeed)
$okIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'idx_required_point',
'type' => Database::INDEX_SPATIAL,
'attributes' => ['pRequired'],
]);
$this->assertEquals(202, $okIndex['headers']['status-code']);
// Create index on optional spatial attribute (should fail in case of mariadb)
$badIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'idx_optional_point',
'type' => Database::INDEX_SPATIAL,
'attributes' => ['pOptional'],
]);
$this->assertEquals(400, $badIndex['headers']['status-code']);
// Passing orders to spatial index should not throw error(in case of mariadb)
$ordersIndex = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'idx_required_point_with_orders',
'type' => Database::INDEX_SPATIAL,
'attributes' => ['pRequired'],
'orders' => ['ASC']
]);
$this->assertEquals(202, $ordersIndex['headers']['status-code']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]));
}
}
@@ -7969,6 +7969,106 @@ trait DatabasesBase
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertCount(0, $response['body']['documents']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId . '/tables/' . $tableId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]));
}
public function testSpatialIndex(): void
{
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
], [
'databaseId' => ID::unique(),
'name' => 'Spatial Index Test DB'
]);
$this->assertEquals(201, $database['headers']['status-code']);
$databaseId = $database['body']['$id'];
$table = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'tableId' => ID::unique(),
'name' => 'SpatialIdx',
'rowSecurity' => true,
'permissions' => [
Permission::create(Role::any()),
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
]);
$this->assertEquals(201, $table['headers']['status-code']);
$tableId = $table['body']['$id'];
// Create spatial columns: one required, one optional
$reqPoint = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/point', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'pRequired',
'required' => true,
]);
$this->assertEquals(202, $reqPoint['headers']['status-code']);
$optPoint = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/point', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'pOptional',
'required' => false,
]);
$this->assertEquals(202, $optPoint['headers']['status-code']);
// Ensure columns are available
sleep(2);
// Create index on required spatial column (should succeed)
$okIndex = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'idx_required_point',
'type' => Database::INDEX_SPATIAL,
'columns' => ['pRequired'],
]);
$this->assertEquals(202, $okIndex['headers']['status-code']);
// Create index on optional spatial column (should fail in case of mariadb)
$badIndex = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'idx_optional_point',
'type' => Database::INDEX_SPATIAL,
'columns' => ['pOptional'],
]);
$this->assertEquals(202, $badIndex['headers']['status-code']);
// Passing orders to spatial index should not throw error (in case of mariadb)
$ordersIndex = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'idx_required_point_with_orders',
'type' => Database::INDEX_SPATIAL,
'columns' => ['pRequired'],
'orders' => ['ASC']
]);
$this->assertEquals(202, $ordersIndex['headers']['status-code']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId . '/tables/' . $tableId, array_merge([
'content-type' => 'application/json',