Compare commits

...
3 changed files with 180 additions and 2 deletions
@@ -80,7 +80,7 @@ class Create extends Action
->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->param('documentSecurity', false, new Boolean(true), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->param('enabled', true, new Boolean(), 'Is collection enabled? When set to \'disabled\', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.', true)
->param('attributes', [], new ArrayList(new JSON(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attribute definitions to create. Each attribute should contain: key (string), type (string: string, integer, float, boolean, datetime), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options.', true)
->param('attributes', [], new ArrayList(new JSON(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attribute definitions to create. Each attribute should contain: key (string), type (string: string, integer, float, boolean, datetime, point, linestring, polygon), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options.', true)
->param('indexes', [], new ArrayList(new JSON(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index definitions to create. Each index should contain: key (string), type (string: key, fulltext, unique, spatial), attributes (array of attribute keys), orders (array of ASC/DESC, optional), and lengths (array of integers, optional).', true)
->inject('response')
->inject('dbForProject')
@@ -62,7 +62,7 @@ class Create extends CollectionCreate
->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->param('rowSecurity', false, new Boolean(true), 'Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a row. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
->param('enabled', true, new Boolean(), 'Is table enabled? When set to \'disabled\', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled.', true)
->param('columns', [], new ArrayList(new JSON(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of column definitions to create. Each column should contain: key (string), type (string: string, integer, float, boolean, datetime, relationship), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options.', true)
->param('columns', [], new ArrayList(new JSON(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of column definitions to create. Each column should contain: key (string), type (string: string, integer, float, boolean, datetime, relationship, point, linestring, polygon), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options.', true)
->param('indexes', [], new ArrayList(new JSON(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index definitions to create. Each index should contain: key (string), type (string: key, fulltext, unique, spatial), attributes (array of column keys), orders (array of ASC/DESC, optional), and lengths (array of integers, optional).', true)
->inject('response')
->inject('dbForProject')
@@ -6957,6 +6957,184 @@ class DatabasesCustomServerTest extends Scope
]));
}
public function testCreateCollectionWithSpatialAttributesAndIndexes(): void
{
// Create database
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'databaseId' => ID::unique(),
'name' => 'Test Spatial Multi Create',
]);
$this->assertEquals(201, $database['headers']['status-code']);
$databaseId = $database['body']['$id'];
// Test: Create collection with spatial attributes and indexes in one call
$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::custom('locations'),
'name' => 'Locations',
'permissions' => [
Permission::read(Role::any()),
Permission::create(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'documentSecurity' => true,
'attributes' => [
[
'key' => 'name',
'type' => Database::VAR_STRING,
'size' => 256,
'required' => true,
],
[
'key' => 'point',
'type' => Database::VAR_POINT,
'required' => true,
],
[
'key' => 'route',
'type' => Database::VAR_LINESTRING,
'required' => false,
],
[
'key' => 'area',
'type' => Database::VAR_POLYGON,
'required' => false,
],
],
'indexes' => [
[
'key' => 'idx_name',
'type' => Database::INDEX_KEY,
'attributes' => ['name'],
],
[
'key' => 'idx_point',
'type' => Database::INDEX_SPATIAL,
'attributes' => ['point'],
],
],
]);
$this->assertEquals(201, $collection['headers']['status-code']);
$this->assertEquals('Locations', $collection['body']['name']);
$this->assertEquals('locations', $collection['body']['$id']);
// Wait for attributes to be available
sleep(2);
// Verify attributes were created and are available
$attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/locations/attributes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]));
$this->assertEquals(200, $attributes['headers']['status-code']);
$this->assertEquals(4, $attributes['body']['total']);
$attrByKey = [];
foreach ($attributes['body']['attributes'] as $attr) {
$attrByKey[$attr['key']] = $attr;
}
$this->assertEquals('available', $attrByKey['name']['status']);
$this->assertEquals(Database::VAR_STRING, $attrByKey['name']['type']);
$this->assertEquals(256, $attrByKey['name']['size']);
$this->assertTrue($attrByKey['name']['required']);
$this->assertEquals('available', $attrByKey['point']['status']);
$this->assertEquals(Database::VAR_POINT, $attrByKey['point']['type']);
$this->assertTrue($attrByKey['point']['required']);
$this->assertEquals('available', $attrByKey['route']['status']);
$this->assertEquals(Database::VAR_LINESTRING, $attrByKey['route']['type']);
$this->assertFalse($attrByKey['route']['required']);
$this->assertEquals('available', $attrByKey['area']['status']);
$this->assertEquals(Database::VAR_POLYGON, $attrByKey['area']['type']);
$this->assertFalse($attrByKey['area']['required']);
// Wait for indexes to be available
sleep(2);
// Verify indexes were created and are available
$indexes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/locations/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]));
$this->assertEquals(200, $indexes['headers']['status-code']);
$this->assertEquals(2, $indexes['body']['total']);
$idxByKey = [];
foreach ($indexes['body']['indexes'] as $idx) {
$idxByKey[$idx['key']] = $idx;
}
$this->assertEquals('available', $idxByKey['idx_name']['status']);
$this->assertEquals(Database::INDEX_KEY, $idxByKey['idx_name']['type']);
$this->assertEquals(['name'], $idxByKey['idx_name']['attributes']);
$this->assertEquals('available', $idxByKey['idx_point']['status']);
$this->assertEquals(Database::INDEX_SPATIAL, $idxByKey['idx_point']['type']);
$this->assertEquals(['point'], $idxByKey['idx_point']['attributes']);
// Verify we can create documents using the spatial attributes
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/locations/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'documentId' => ID::unique(),
'data' => [
'name' => 'New York',
'point' => [40.7128, -74.0060],
'route' => [[40.7128, -74.0060], [40.7589, -73.9851]],
'area' => [[[40.7128, -74.0060], [40.7589, -73.9851], [40.7589, -74.0060], [40.7128, -74.0060]]],
],
]);
$this->assertEquals(201, $document['headers']['status-code']);
$this->assertEquals('New York', $document['body']['name']);
$this->assertEquals([40.7128, -74.0060], $document['body']['point']);
$this->assertEquals([[40.7128, -74.0060], [40.7589, -73.9851]], $document['body']['route']);
$this->assertEquals([[[40.7128, -74.0060], [40.7589, -73.9851], [40.7589, -74.0060], [40.7128, -74.0060]]], $document['body']['area']);
// Test: Create document with only required spatial attribute
$document2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/locations/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'documentId' => ID::unique(),
'data' => [
'name' => 'Los Angeles',
'point' => [34.0522, -77.2437],
],
]);
$this->assertEquals(201, $document2['headers']['status-code']);
$this->assertEquals('Los Angeles', $document2['body']['name']);
$this->assertEquals([34.0522, -77.2437], $document2['body']['point']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]));
}
public function testCreateCollectionWithAttributesAndIndexesErrors(): void
{
// Create database