2020-01-13 08:46:09 +00:00
< ? php
2026-01-09 14:21:31 +00:00
namespace Tests\E2E\Services\Databases ;
2020-01-13 08:46:09 +00:00
2023-01-20 00:36:17 +00:00
use Appwrite\Extend\Exception ;
2020-01-13 08:46:09 +00:00
use Tests\E2E\Client ;
2026-01-10 01:53:29 +00:00
use Tests\E2E\Scopes\SchemaPolling ;
2026-01-09 14:21:31 +00:00
use Tests\E2E\Traits\DatabasesUrlHelpers ;
2023-03-16 16:28:08 +00:00
use Utopia\Database\Database ;
2023-01-20 00:36:17 +00:00
use Utopia\Database\DateTime ;
2023-12-20 10:55:09 +00:00
use Utopia\Database\Document ;
2022-12-14 15:42:25 +00:00
use Utopia\Database\Helpers\ID ;
2022-12-14 16:04:06 +00:00
use Utopia\Database\Helpers\Permission ;
use Utopia\Database\Helpers\Role ;
2025-10-30 22:47:20 +00:00
use Utopia\Database\Operator ;
2023-12-10 19:05:33 +00:00
use Utopia\Database\Query ;
2023-03-12 14:04:18 +00:00
use Utopia\Database\Validator\Datetime as DatetimeValidator ;
2023-03-27 06:03:00 +00:00
2022-06-22 10:51:49 +00:00
trait DatabasesBase
2020-01-13 08:46:09 +00:00
{
2026-01-09 14:21:31 +00:00
use DatabasesUrlHelpers ;
2026-01-10 01:53:29 +00:00
use SchemaPolling ;
2026-02-05 22:56:58 +00:00
/**
* Static caches for test data - keyed by project ID to support parallel test runs
*/
private static array $databaseCache = [];
private static array $collectionCache = [];
private static array $attributesCache = [];
private static array $indexesCache = [];
private static array $documentsCache = [];
private static array $oneToOneCache = [];
private static array $oneToManyCache = [];
/**
* Get cache key for current test instance ( based on project ID )
*/
protected function getCacheKey () : string
{
return $this -> getProject ()[ '$id' ] ? ? 'default' ;
}
/**
* Setup : Create database and return data
* Uses static caching to avoid recreating resources
*/
protected function setupDatabase () : array
{
$cacheKey = $this -> getCacheKey ();
if ( ! empty ( self :: $databaseCache [ $cacheKey ])) {
return self :: $databaseCache [ $cacheKey ];
}
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Test Database'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
self :: $databaseCache [ $cacheKey ] = [ 'databaseId' => $database [ 'body' ][ '$id' ]];
return self :: $databaseCache [ $cacheKey ];
}
/**
* Setup : Create database and collections
* Uses static caching to avoid recreating resources
*/
protected function setupCollection () : array
{
$cacheKey = $this -> getCacheKey ();
if ( ! empty ( self :: $collectionCache [ $cacheKey ])) {
return self :: $collectionCache [ $cacheKey ];
}
$data = $this -> setupDatabase ();
$databaseId = $data [ 'databaseId' ];
$movies = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Movies' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $movies [ 'headers' ][ 'status-code' ]);
$actors = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Actors' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $actors [ 'headers' ][ 'status-code' ]);
self :: $collectionCache [ $cacheKey ] = [
'databaseId' => $databaseId ,
'moviesId' => $movies [ 'body' ][ '$id' ],
'actorsId' => $actors [ 'body' ][ '$id' ],
];
return self :: $collectionCache [ $cacheKey ];
}
/**
* Setup : Create database , collections , and attributes
* Uses static caching to avoid recreating resources
*/
protected function setupAttributes () : array
{
$cacheKey = $this -> getCacheKey ();
if ( ! empty ( self :: $attributesCache [ $cacheKey ])) {
return self :: $attributesCache [ $cacheKey ];
}
$data = $this -> setupCollection ();
$databaseId = $data [ 'databaseId' ];
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
$description = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'description' ,
'size' => 512 ,
'required' => false ,
'default' => '' ,
]);
$tagline = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'tagline' ,
'size' => 512 ,
'required' => false ,
'default' => '' ,
]);
$releaseYear = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/integer' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'releaseYear' ,
'required' => true ,
'min' => 1900 ,
'max' => 2200 ,
]);
$duration = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/integer' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'duration' ,
'required' => false ,
'min' => 60 ,
]);
$actors = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'actors' ,
'size' => 256 ,
'required' => false ,
'array' => true ,
]);
$datetime = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/datetime' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'birthDay' ,
'required' => false ,
]);
$relationship = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/relationship' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getRelatedIdParam () => $data [ 'actorsId' ],
'type' => 'oneToMany' ,
'twoWay' => true ,
'key' => 'starringActors' ,
'twoWayKey' => 'movie'
]);
$integers = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]) . '/integer' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'integers' ,
'required' => false ,
'array' => true ,
'min' => 10 ,
'max' => 99 ,
]);
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $description [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $tagline [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $releaseYear [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $duration [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $actors [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $datetime [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $relationship [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $integers [ 'headers' ][ 'status-code' ]);
// wait for database worker to create attributes
$this -> waitForAllAttributes ( $databaseId , $data [ 'moviesId' ]);
self :: $attributesCache [ $cacheKey ] = $data ;
return self :: $attributesCache [ $cacheKey ];
}
/**
* Setup : Create database , collections , attributes , and indexes
* Uses static caching to avoid recreating resources
*/
protected function setupIndexes () : array
{
$cacheKey = $this -> getCacheKey ();
if ( ! empty ( self :: $indexesCache [ $cacheKey ])) {
return self :: $indexesCache [ $cacheKey ];
}
$data = $this -> setupAttributes ();
$databaseId = $data [ 'databaseId' ];
$titleIndex = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'titleIndex' ,
'type' => 'fulltext' ,
$this -> getIndexAttributesParam () => [ 'title' ],
]);
$releaseYearIndex = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'releaseYear' ,
'type' => 'key' ,
$this -> getIndexAttributesParam () => [ 'releaseYear' ],
]);
$releaseWithDate1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'releaseYearDated' ,
'type' => 'key' ,
$this -> getIndexAttributesParam () => [ 'releaseYear' , '$createdAt' , '$updatedAt' ],
]);
$releaseWithDate2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'birthDay' ,
'type' => 'key' ,
$this -> getIndexAttributesParam () => [ 'birthDay' ],
]);
$this -> assertEquals ( 202 , $titleIndex [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $releaseYearIndex [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $releaseWithDate1 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $releaseWithDate2 [ 'headers' ][ 'status-code' ]);
$this -> waitForAllIndexes ( $databaseId , $data [ 'moviesId' ]);
self :: $indexesCache [ $cacheKey ] = $data ;
return self :: $indexesCache [ $cacheKey ];
}
/**
* Setup : Create database , collections , attributes , indexes , and documents
* Uses static caching to avoid recreating resources
*/
protected function setupDocuments () : array
{
$cacheKey = $this -> getCacheKey ();
if ( ! empty ( self :: $documentsCache [ $cacheKey ])) {
return self :: $documentsCache [ $cacheKey ];
}
$data = $this -> setupIndexes ();
$databaseId = $data [ 'databaseId' ];
$document1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Captain America' ,
'releaseYear' => 1944 ,
'birthDay' => '1975-06-12 14:12:55+02:00' ,
'actors' => [
'Chris Evans' ,
'Samuel Jackson' ,
]
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$document2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Spider-Man: Far From Home' ,
'releaseYear' => 2019 ,
'birthDay' => null ,
'actors' => [
'Tom Holland' ,
'Zendaya Maree Stoermer' ,
'Samuel Jackson' ,
],
'integers' => [ 50 , 60 ]
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$document3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Spider-Man: Homecoming' ,
'releaseYear' => 2017 ,
'birthDay' => '1975-06-12 14:12:55 America/New_York' ,
'duration' => 65 ,
'actors' => [
'Tom Holland' ,
'Zendaya Maree Stoermer' ,
],
'integers' => [ 50 ]
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $document1 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $document2 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $document3 [ 'headers' ][ 'status-code' ]);
2026-02-09 01:20:42 +00:00
$data [ 'documentIds' ] = [
$document1 [ 'body' ][ '$id' ],
$document2 [ 'body' ][ '$id' ],
$document3 [ 'body' ][ '$id' ],
];
2026-02-05 22:56:58 +00:00
self :: $documentsCache [ $cacheKey ] = $data ;
return self :: $documentsCache [ $cacheKey ];
}
/**
* Setup : Create one - to - one relationship collections
* Uses static caching to avoid recreating resources
*/
protected function setupOneToOneRelationship () : array
{
$cacheKey = $this -> getCacheKey ();
if ( ! empty ( self :: $oneToOneCache [ $cacheKey ])) {
return self :: $oneToOneCache [ $cacheKey ];
}
$data = $this -> setupDatabase ();
$databaseId = $data [ 'databaseId' ];
$person = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-02-09 01:55:41 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2026-02-05 22:56:58 +00:00
'name' => 'person' ,
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
$this -> getSecurityParam () => true ,
]);
$this -> assertEquals ( 201 , $person [ 'headers' ][ 'status-code' ]);
$library = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-02-09 01:55:41 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2026-02-05 22:56:58 +00:00
'name' => 'library' ,
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
$this -> getSecurityParam () => true ,
]);
$this -> assertEquals ( 201 , $library [ 'headers' ][ 'status-code' ]);
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'fullName' ,
'size' => 255 ,
'required' => false ,
]);
$this -> waitForAttribute ( $databaseId , $person [ 'body' ][ '$id' ], 'fullName' );
$libraryName = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $library [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'libraryName' ,
'size' => 255 ,
'required' => true ,
]);
$this -> waitForAttribute ( $databaseId , $library [ 'body' ][ '$id' ], 'libraryName' );
$this -> assertEquals ( 202 , $libraryName [ 'headers' ][ 'status-code' ]);
self :: $oneToOneCache [ $cacheKey ] = [
'databaseId' => $databaseId ,
'personCollection' => $person [ 'body' ][ '$id' ],
'libraryCollection' => $library [ 'body' ][ '$id' ],
];
return self :: $oneToOneCache [ $cacheKey ];
}
/**
* Setup : Create one - to - many relationship collections ( extends one - to - one )
* Uses static caching to avoid recreating resources
*/
protected function setupOneToManyRelationship () : array
{
$cacheKey = $this -> getCacheKey ();
if ( ! empty ( self :: $oneToManyCache [ $cacheKey ])) {
return self :: $oneToManyCache [ $cacheKey ];
}
$data = $this -> setupOneToOneRelationship ();
$databaseId = $data [ 'databaseId' ];
$personCollection = $data [ 'personCollection' ];
$libraryCollection = $data [ 'libraryCollection' ];
// One person can own several libraries
2026-02-09 01:55:41 +00:00
$relation = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $personCollection ) . '/relationship' , array_merge ([
2026-02-05 22:56:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-02-09 01:55:41 +00:00
$this -> getRelatedIdParam () => $libraryCollection ,
2026-02-05 22:56:58 +00:00
'type' => Database :: RELATION_ONE_TO_MANY ,
'twoWay' => true ,
'key' => 'libraries' ,
'twoWayKey' => 'person_one_to_many' ,
]);
2026-02-09 03:56:08 +00:00
// Handle 409 if relationship already exists (possible race condition in parallel mode)
if ( $relation [ 'headers' ][ 'status-code' ] === 409 ) {
// Relationship already exists, just wait for it to be available
} else {
$this -> assertEquals ( 202 , $relation [ 'headers' ][ 'status-code' ], 'Relationship creation failed: ' . \json_encode ( $relation [ 'body' ] ? ? 'no body' ));
}
2026-02-09 01:55:41 +00:00
2026-02-09 03:08:55 +00:00
// Wait for both the relationship attribute and its twoWayKey to be available
2026-02-05 22:56:58 +00:00
$this -> waitForAttribute ( $databaseId , $personCollection , 'libraries' );
2026-02-09 03:08:55 +00:00
$this -> waitForAttribute ( $databaseId , $libraryCollection , 'person_one_to_many' );
2026-02-05 22:56:58 +00:00
2026-02-09 03:08:55 +00:00
$serverHeaders = [
2026-02-05 22:56:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2026-02-09 03:08:55 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
];
// Create a person with libraries
$person = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $personCollection ), $serverHeaders , [
2026-02-09 02:28:38 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2026-02-05 22:56:58 +00:00
'data' => [
'fullName' => 'Stevie Wonder' ,
'libraries' => [
[
2026-02-09 02:28:38 +00:00
'$id' => ID :: unique (),
2026-02-05 22:56:58 +00:00
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
'libraryName' => 'Library 10' ,
],
[
2026-02-09 02:28:38 +00:00
'$id' => ID :: unique (),
2026-02-05 22:56:58 +00:00
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
'libraryName' => 'Library 11' ,
]
],
],
'permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
]
]);
2026-02-09 03:56:08 +00:00
$this -> assertEquals ( 201 , $person [ 'headers' ][ 'status-code' ], 'Person with libraries creation failed: ' . \json_encode ( $person [ 'body' ] ? ? 'no body' ));
2026-02-05 22:56:58 +00:00
2026-02-09 01:20:42 +00:00
// Create two person documents with null fullName for isNull query testing
2026-02-09 03:08:55 +00:00
$nullPerson1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $personCollection ), $serverHeaders , [
2026-02-09 01:20:42 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2026-02-09 03:56:08 +00:00
'data' => [
'fullName' => null ,
],
2026-02-09 01:20:42 +00:00
'permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
]
]);
2026-02-09 03:56:08 +00:00
$this -> assertEquals ( 201 , $nullPerson1 [ 'headers' ][ 'status-code' ], 'Null person 1 creation failed: ' . \json_encode ( $nullPerson1 [ 'body' ] ? ? 'no body' ));
2026-02-09 01:20:42 +00:00
2026-02-09 03:08:55 +00:00
$nullPerson2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $personCollection ), $serverHeaders , [
2026-02-09 01:20:42 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2026-02-09 03:56:08 +00:00
'data' => [
'fullName' => null ,
],
2026-02-09 01:20:42 +00:00
'permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
]
]);
2026-02-09 03:56:08 +00:00
$this -> assertEquals ( 201 , $nullPerson2 [ 'headers' ][ 'status-code' ], 'Null person 2 creation failed: ' . \json_encode ( $nullPerson2 [ 'body' ] ? ? 'no body' ));
2026-02-09 01:20:42 +00:00
2026-02-05 22:56:58 +00:00
// Update onDelete to cascade
2026-02-09 03:08:55 +00:00
$this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $personCollection , 'relationship' , 'libraries' ), $serverHeaders , [
2026-02-05 22:56:58 +00:00
'onDelete' => Database :: RELATION_MUTATE_CASCADE ,
]);
2026-02-09 01:55:41 +00:00
self :: $oneToManyCache [ $cacheKey ] = [ 'databaseId' => $databaseId , 'personCollection' => $personCollection , 'libraryCollection' => $libraryCollection ];
2026-02-05 22:56:58 +00:00
return self :: $oneToManyCache [ $cacheKey ];
}
/**
* Helper : Get list of documents ( for tests that need document data )
*/
protected function getDocumentsList () : array
{
$data = $this -> setupDocuments ();
$databaseId = $data [ 'databaseId' ];
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: orderDesc ( 'releaseYear' ) -> toString (),
],
]);
return [ $this -> getRecordResource () => $documents [ 'body' ][ $this -> getRecordResource ()], 'databaseId' => $databaseId ];
}
public function testCreateDatabase () : void
2020-01-13 08:46:09 +00:00
{
/**
* Test for SUCCESS
*/
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2022-06-22 10:51:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
2022-08-14 10:33:36 +00:00
'databaseId' => ID :: unique (),
2022-06-22 10:51:49 +00:00
'name' => 'Test Database'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Test Database' , $database [ 'body' ][ 'name' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $this -> getDatabaseType (), $database [ 'body' ][ 'type' ]);
2022-06-22 10:51:49 +00:00
}
2026-02-05 22:56:58 +00:00
public function testCreateCollection () : void
2022-06-22 10:51:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDatabase ();
2022-06-22 10:51:49 +00:00
$databaseId = $data [ 'databaseId' ];
/**
* Test for SUCCESS
*/
2026-01-09 14:21:31 +00:00
$movies = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2021-06-15 13:38:24 +00:00
'name' => 'Movies' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2022-08-13 14:10:28 +00:00
'permissions' => [
2022-08-27 08:29:32 +00:00
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
2022-08-13 14:10:28 +00:00
],
2020-01-13 08:46:09 +00:00
]);
2022-08-08 11:00:03 +00:00
$this -> assertEquals ( 201 , $movies [ 'headers' ][ 'status-code' ]);
2021-06-11 20:06:54 +00:00
$this -> assertEquals ( $movies [ 'body' ][ 'name' ], 'Movies' );
2026-02-05 09:53:04 +00:00
$this -> assertArrayHasKey ( 'bytesMax' , $movies [ 'body' ]);
$this -> assertArrayHasKey ( 'bytesUsed' , $movies [ 'body' ]);
$this -> assertIsInt ( $movies [ 'body' ][ 'bytesMax' ]);
$this -> assertIsInt ( $movies [ 'body' ][ 'bytesUsed' ]);
$this -> assertGreaterThanOrEqual ( 0 , $movies [ 'body' ][ 'bytesMax' ]);
$this -> assertGreaterThanOrEqual ( 0 , $movies [ 'body' ][ 'bytesUsed' ]);
2020-01-13 08:46:09 +00:00
2026-01-09 14:21:31 +00:00
$actors = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2023-03-25 03:29:40 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-25 03:29:40 +00:00
'name' => 'Actors' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2023-03-25 03:29:40 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $actors [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $actors [ 'body' ][ 'name' ], 'Actors' );
2021-06-11 20:06:54 +00:00
}
2026-02-05 22:56:58 +00:00
public function testConsoleProject () : void
2024-04-09 15:24:01 +00:00
{
2025-04-16 01:07:11 +00:00
if ( $this -> getSide () === 'server' ) {
// Server side can't get past the invalid key check anyway
$this -> expectNotToPerformAssertions ();
return ;
}
2026-02-09 06:15:35 +00:00
$data = $this -> setupCollection ();
2024-04-09 15:24:01 +00:00
$response = $this -> client -> call (
Client :: METHOD_GET ,
2026-01-09 14:21:31 +00:00
$this -> getApiBasePath () . '/console/' . $this -> getContainerResource () . '/' . $data [ 'moviesId' ] . '/' . $this -> getRecordResource (),
2024-04-09 15:24:01 +00:00
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => 'console' ,
], $this -> getHeaders ())
);
2024-04-18 08:25:03 +00:00
2026-01-09 14:21:31 +00:00
// Access should be denied - 401 (forbidden) or 400 (invalid request) are both acceptable
$this -> assertContains ( $response [ 'headers' ][ 'status-code' ], [ 400 , 401 ], 'Console project access should be denied' );
if ( $response [ 'headers' ][ 'status-code' ] === 401 ) {
$this -> assertEquals ( 'general_access_forbidden' , $response [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'This endpoint is not available for the console project. The Appwrite Console is a reserved project ID and cannot be used with the Appwrite SDKs and APIs. Please check if your project ID is correct.' , $response [ 'body' ][ 'message' ]);
}
2024-04-09 15:24:01 +00:00
$response = $this -> client -> call (
Client :: METHOD_GET ,
2026-01-09 14:21:31 +00:00
$this -> getApiBasePath () . '/console/' . $this -> getContainerResource () . '/' . $data [ 'moviesId' ] . '/' . $this -> getRecordResource (),
2024-04-09 15:24:01 +00:00
array_merge ([
'content-type' => 'application/json' ,
2024-04-18 06:26:11 +00:00
// 'x-appwrite-project' => '', empty header
2024-04-09 15:24:01 +00:00
], $this -> getHeaders ())
);
2026-01-09 14:21:31 +00:00
// Request without project should be denied
$this -> assertContains ( $response [ 'headers' ][ 'status-code' ], [ 400 , 401 ], 'Request without project should be denied' );
if ( $response [ 'headers' ][ 'status-code' ] === 401 ) {
$this -> assertEquals ( 'No Appwrite project was specified. Please specify your project ID when initializing your Appwrite SDK.' , $response [ 'body' ][ 'message' ]);
}
2024-04-09 15:24:01 +00:00
}
2026-02-05 22:56:58 +00:00
public function testDisableCollection () : void
2021-12-13 13:23:12 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupCollection ();
2022-06-22 10:51:49 +00:00
$databaseId = $data [ 'databaseId' ];
2021-12-13 13:23:12 +00:00
/**
* Test for SUCCESS
*/
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-12-13 13:23:12 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'name' => 'Movies' ,
'enabled' => false ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2021-12-13 13:23:12 +00:00
]);
2022-08-08 11:00:03 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2021-12-13 13:23:12 +00:00
$this -> assertFalse ( $response [ 'body' ][ 'enabled' ]);
2026-02-05 09:53:04 +00:00
$this -> assertArrayHasKey ( 'bytesMax' , $response [ 'body' ]);
$this -> assertArrayHasKey ( 'bytesUsed' , $response [ 'body' ]);
2021-12-13 13:23:12 +00:00
if ( $this -> getSide () === 'client' ) {
2026-01-09 14:21:31 +00:00
$responseCreateDocument = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-12-13 13:23:12 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2021-12-13 13:23:12 +00:00
'data' => [
'title' => 'Captain America' ,
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2022-08-15 11:24:31 +00:00
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
2022-08-03 04:17:49 +00:00
],
2021-12-13 13:23:12 +00:00
]);
2022-08-24 13:32:52 +00:00
$this -> assertEquals ( 404 , $responseCreateDocument [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$responseListDocument = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-12-13 13:23:12 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2022-08-24 13:32:52 +00:00
$this -> assertEquals ( 404 , $responseListDocument [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$responseGetDocument = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/someID' , array_merge ([
2021-12-13 13:23:12 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2022-08-08 11:00:03 +00:00
$this -> assertEquals ( 404 , $responseGetDocument [ 'headers' ][ 'status-code' ]);
2021-12-13 13:23:12 +00:00
}
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-12-13 13:23:12 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'name' => 'Movies' ,
'enabled' => true ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2021-12-13 13:23:12 +00:00
]);
2022-08-08 11:00:03 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2021-12-13 13:23:12 +00:00
$this -> assertTrue ( $response [ 'body' ][ 'enabled' ]);
}
2026-02-05 22:56:58 +00:00
public function testCreateAttributes () : void
2021-06-11 20:06:54 +00:00
{
2026-02-06 05:50:36 +00:00
// Use dedicated collections for this test to avoid conflicts with setupAttributes()
$data = $this -> setupDatabase ();
2022-06-22 10:51:49 +00:00
$databaseId = $data [ 'databaseId' ];
2023-05-30 02:52:59 +00:00
2026-02-06 05:50:36 +00:00
// Create dedicated collections for attribute testing (separate from shared collections)
$movies = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'AttribTestMovies' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $movies [ 'headers' ][ 'status-code' ]);
$moviesId = $movies [ 'body' ][ '$id' ];
$actors = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'AttribTestActors' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $actors [ 'headers' ][ 'status-code' ]);
$actorsId = $actors [ 'body' ][ '$id' ];
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/string' , array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2021-12-16 15:04:30 +00:00
'key' => 'title' ,
2021-06-11 20:06:54 +00:00
'size' => 256 ,
'required' => true ,
2020-01-13 08:46:09 +00:00
]);
2026-02-06 05:50:36 +00:00
$description = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/string' , array_merge ([
2023-05-30 02:52:59 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'description' ,
2023-06-15 05:28:35 +00:00
'size' => 512 ,
'required' => false ,
'default' => '' ,
]);
2026-02-06 05:50:36 +00:00
$tagline = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/string' , array_merge ([
2023-06-15 05:28:35 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'tagline' ,
'size' => 512 ,
2023-05-30 02:52:59 +00:00
'required' => false ,
'default' => '' ,
]);
2026-02-06 05:50:36 +00:00
$releaseYear = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/integer' , array_merge ([
2021-06-11 20:06:54 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2021-12-16 15:04:30 +00:00
'key' => 'releaseYear' ,
2021-06-11 20:06:54 +00:00
'required' => true ,
2023-03-25 03:29:40 +00:00
'min' => 1900 ,
'max' => 2200 ,
2021-06-11 20:06:54 +00:00
]);
2020-01-13 08:46:09 +00:00
2026-02-06 05:50:36 +00:00
$duration = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/integer' , array_merge ([
2022-06-09 15:15:34 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'duration' ,
'required' => false ,
2023-03-25 03:29:40 +00:00
'min' => 60 ,
2022-06-09 15:15:34 +00:00
]);
2026-02-06 05:50:36 +00:00
$actorsAttr = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/string' , array_merge ([
2021-06-11 20:06:54 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2021-12-16 15:04:30 +00:00
'key' => 'actors' ,
2021-06-11 20:06:54 +00:00
'size' => 256 ,
'required' => false ,
'array' => true ,
]);
2026-02-06 05:50:36 +00:00
$datetime = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/datetime' , array_merge ([
2022-07-25 08:53:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'birthDay' ,
'required' => false ,
]);
2023-03-25 03:29:40 +00:00
2026-02-06 05:50:36 +00:00
$relationship = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/relationship' , array_merge ([
2023-03-25 03:29:40 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-02-06 05:50:36 +00:00
$this -> getRelatedIdParam () => $actorsId ,
2023-03-25 03:29:40 +00:00
'type' => 'oneToMany' ,
'twoWay' => true ,
'key' => 'starringActors' ,
'twoWayKey' => 'movie'
]);
2026-02-06 05:50:36 +00:00
$integers = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/integer' , array_merge ([
2024-01-21 08:10:18 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'integers' ,
'required' => false ,
'array' => true ,
2024-01-21 16:22:02 +00:00
'min' => 10 ,
'max' => 99 ,
2024-01-21 08:10:18 +00:00
]);
2022-08-12 12:54:27 +00:00
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
2021-08-22 14:06:59 +00:00
$this -> assertEquals ( $title [ 'body' ][ 'key' ], 'title' );
2021-06-14 19:54:19 +00:00
$this -> assertEquals ( $title [ 'body' ][ 'type' ], 'string' );
$this -> assertEquals ( $title [ 'body' ][ 'size' ], 256 );
$this -> assertEquals ( $title [ 'body' ][ 'required' ], true );
2025-05-23 06:35:42 +00:00
$this -> assertFalse ( $title [ 'body' ][ 'encrypt' ]);
2023-05-30 02:52:59 +00:00
$this -> assertEquals ( 202 , $description [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $description [ 'body' ][ 'key' ], 'description' );
$this -> assertEquals ( $description [ 'body' ][ 'type' ], 'string' );
2023-06-15 05:28:35 +00:00
$this -> assertEquals ( $description [ 'body' ][ 'size' ], 512 );
2023-05-30 02:52:59 +00:00
$this -> assertEquals ( $description [ 'body' ][ 'required' ], false );
$this -> assertEquals ( $description [ 'body' ][ 'default' ], '' );
2023-06-15 05:28:35 +00:00
$this -> assertEquals ( 202 , $tagline [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $tagline [ 'body' ][ 'key' ], 'tagline' );
$this -> assertEquals ( $tagline [ 'body' ][ 'type' ], 'string' );
$this -> assertEquals ( $tagline [ 'body' ][ 'size' ], 512 );
$this -> assertEquals ( $tagline [ 'body' ][ 'required' ], false );
$this -> assertEquals ( $tagline [ 'body' ][ 'default' ], '' );
2022-08-12 12:54:27 +00:00
$this -> assertEquals ( 202 , $releaseYear [ 'headers' ][ 'status-code' ]);
2021-08-22 14:06:59 +00:00
$this -> assertEquals ( $releaseYear [ 'body' ][ 'key' ], 'releaseYear' );
2021-06-14 19:54:19 +00:00
$this -> assertEquals ( $releaseYear [ 'body' ][ 'type' ], 'integer' );
$this -> assertEquals ( $releaseYear [ 'body' ][ 'required' ], true );
2022-08-12 12:54:27 +00:00
$this -> assertEquals ( 202 , $duration [ 'headers' ][ 'status-code' ]);
2022-06-09 15:15:34 +00:00
$this -> assertEquals ( $duration [ 'body' ][ 'key' ], 'duration' );
$this -> assertEquals ( $duration [ 'body' ][ 'type' ], 'integer' );
$this -> assertEquals ( $duration [ 'body' ][ 'required' ], false );
2026-02-06 05:50:36 +00:00
$this -> assertEquals ( 202 , $actorsAttr [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $actorsAttr [ 'body' ][ 'key' ], 'actors' );
$this -> assertEquals ( $actorsAttr [ 'body' ][ 'type' ], 'string' );
$this -> assertEquals ( $actorsAttr [ 'body' ][ 'size' ], 256 );
$this -> assertEquals ( $actorsAttr [ 'body' ][ 'required' ], false );
$this -> assertEquals ( $actorsAttr [ 'body' ][ 'array' ], true );
2021-06-11 20:06:54 +00:00
2022-08-11 23:53:52 +00:00
$this -> assertEquals ( $datetime [ 'headers' ][ 'status-code' ], 202 );
2022-07-28 15:24:17 +00:00
$this -> assertEquals ( $datetime [ 'body' ][ 'key' ], 'birthDay' );
$this -> assertEquals ( $datetime [ 'body' ][ 'type' ], 'datetime' );
$this -> assertEquals ( $datetime [ 'body' ][ 'required' ], false );
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( $relationship [ 'headers' ][ 'status-code' ], 202 );
$this -> assertEquals ( $relationship [ 'body' ][ 'key' ], 'starringActors' );
$this -> assertEquals ( $relationship [ 'body' ][ 'type' ], 'relationship' );
2026-02-06 05:50:36 +00:00
$this -> assertEquals ( $relationship [ 'body' ][ $this -> getRelatedResourceKey ()], $actorsId );
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( $relationship [ 'body' ][ 'relationType' ], 'oneToMany' );
$this -> assertEquals ( $relationship [ 'body' ][ 'twoWay' ], true );
$this -> assertEquals ( $relationship [ 'body' ][ 'twoWayKey' ], 'movie' );
2024-01-21 08:10:18 +00:00
$this -> assertEquals ( 202 , $integers [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $integers [ 'body' ][ 'key' ], 'integers' );
$this -> assertEquals ( $integers [ 'body' ][ 'type' ], 'integer' );
$this -> assertArrayNotHasKey ( 'size' , $integers [ 'body' ]);
$this -> assertEquals ( $integers [ 'body' ][ 'required' ], false );
$this -> assertEquals ( $integers [ 'body' ][ 'array' ], true );
2021-06-18 17:09:07 +00:00
// wait for database worker to create attributes
2026-02-06 05:50:36 +00:00
$this -> waitForAllAttributes ( $databaseId , $moviesId );
2021-06-18 17:09:07 +00:00
2026-02-06 05:50:36 +00:00
$moviesResponse = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $moviesId ), array_merge ([
2021-06-18 17:09:07 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-06-15 05:28:35 +00:00
]));
2021-06-18 17:09:07 +00:00
2026-02-06 05:50:36 +00:00
$this -> assertArrayHasKey ( 'bytesMax' , $moviesResponse [ 'body' ]);
$this -> assertArrayHasKey ( 'bytesUsed' , $moviesResponse [ 'body' ]);
$this -> assertIsArray ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()]);
$this -> assertCount ( 9 , $moviesResponse [ 'body' ][ $this -> getSchemaResource ()]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 0 ][ 'key' ], $title [ 'body' ][ 'key' ]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 1 ][ 'key' ], $description [ 'body' ][ 'key' ]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 2 ][ 'key' ], $tagline [ 'body' ][ 'key' ]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 3 ][ 'key' ], $releaseYear [ 'body' ][ 'key' ]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 4 ][ 'key' ], $duration [ 'body' ][ 'key' ]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 5 ][ 'key' ], $actorsAttr [ 'body' ][ 'key' ]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 6 ][ 'key' ], $datetime [ 'body' ][ 'key' ]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 7 ][ 'key' ], $relationship [ 'body' ][ 'key' ]);
$this -> assertEquals ( $moviesResponse [ 'body' ][ $this -> getSchemaResource ()][ 8 ][ 'key' ], $integers [ 'body' ][ 'key' ]);
2020-01-13 08:46:09 +00:00
}
2026-02-05 22:56:58 +00:00
public function testListAttributes () : void
2023-07-20 18:50:53 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupAttributes ();
2023-07-20 18:50:53 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-07-20 18:50:53 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: equal ( 'type' , [ 'string' ]) -> toString (),
Query :: limit ( 2 ) -> toString (),
Query :: cursorAfter ( new Document ([ '$id' => 'title' ])) -> toString ()
2024-01-09 00:56:01 +00:00
],
2023-07-20 18:50:53 +00:00
]);
2023-08-09 18:41:18 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 2 , \count ( $response [ 'body' ][ $this -> getSchemaResource ()]));
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-08-09 18:41:18 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
2023-12-20 10:55:09 +00:00
'queries' => [ Query :: select ([ 'key' ]) -> toString ()],
2023-08-09 18:41:18 +00:00
]);
$this -> assertEquals ( Exception :: GENERAL_ARGUMENT_INVALID , $response [ 'body' ][ 'type' ]);
$this -> assertEquals ( 400 , $response [ 'headers' ][ 'status-code' ]);
2023-07-20 18:50:53 +00:00
}
2026-02-05 22:56:58 +00:00
public function testPatchAttribute () : void
2025-02-10 13:40:21 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDatabase ();
2025-02-10 13:40:21 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-02-10 13:40:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-02-10 13:40:21 +00:00
'name' => 'patch' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-02-10 13:40:21 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $collection [ 'body' ][ 'name' ], 'patch' );
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collection [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2025-02-10 13:40:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'title' ,
'required' => true ,
'size' => 100 ,
]);
$this -> assertEquals ( 202 , $attribute [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $attribute [ 'body' ][ 'size' ], 100 );
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $collection [ 'body' ][ '$id' ], 'title' );
2025-02-10 13:40:21 +00:00
2026-01-09 14:21:31 +00:00
$index = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collection [ 'body' ][ '$id' ]), array_merge ([
2025-02-10 13:40:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'titleIndex' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'title' ],
2025-02-10 13:40:21 +00:00
]);
$this -> assertEquals ( 202 , $index [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForIndex ( $databaseId , $collection [ 'body' ][ '$id' ], 'titleIndex' );
2025-02-10 13:40:21 +00:00
/**
2025-02-10 13:40:45 +00:00
* Update attribute size to exceed Index maximum length
2025-02-10 13:40:21 +00:00
*/
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $collection [ 'body' ][ '$id' ]) . '/string/' . $attribute [ 'body' ][ 'key' ], array_merge ([
2025-02-10 13:40:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'size' => 1000 ,
'required' => true ,
'default' => null ,
]);
$this -> assertEquals ( 400 , $attribute [ 'headers' ][ 'status-code' ]);
2025-02-13 09:37:12 +00:00
$this -> assertStringContainsString ( 'Index length is longer than the maximum: 76' , $attribute [ 'body' ][ 'message' ]);
2025-02-10 13:40:21 +00:00
}
2023-08-22 03:25:55 +00:00
public function testUpdateAttributeEnum () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2023-08-22 03:25:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Test Database 2'
]);
2026-01-09 14:21:31 +00:00
$players = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $database [ 'body' ][ '$id' ]), array_merge ([
2023-08-22 03:25:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-08-22 03:25:55 +00:00
'name' => 'Players' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2023-08-22 03:25:55 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
// Create enum attribute
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $database [ 'body' ][ '$id' ], $players [ 'body' ][ '$id' ]) . '/enum' , array_merge ([
2023-08-22 03:25:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'key' => 'position' ,
'elements' => [ 'goalkeeper' , 'defender' , 'midfielder' , 'forward' ],
'required' => true ,
'array' => false ,
]);
$this -> assertEquals ( 202 , $attribute [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $attribute [ 'body' ][ 'key' ], 'position' );
$this -> assertEquals ( $attribute [ 'body' ][ 'elements' ], [ 'goalkeeper' , 'defender' , 'midfielder' , 'forward' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $database [ 'body' ][ '$id' ], $players [ 'body' ][ '$id' ], 'position' );
2023-08-22 03:25:55 +00:00
// Update enum attribute
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $database [ 'body' ][ '$id' ], $players [ 'body' ][ '$id' ]) . '/enum/' . $attribute [ 'body' ][ 'key' ], array_merge ([
2023-08-22 03:25:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'elements' => [ 'goalkeeper' , 'defender' , 'midfielder' , 'forward' , 'coach' ],
'required' => true ,
'default' => null
]);
$this -> assertEquals ( 200 , $attribute [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $attribute [ 'body' ][ 'elements' ], [ 'goalkeeper' , 'defender' , 'midfielder' , 'forward' , 'coach' ]);
}
2026-02-05 22:56:58 +00:00
public function testAttributeResponseModels () : void
2023-03-16 16:28:08 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupAttributes ();
2023-03-16 16:28:08 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2023-03-16 16:28:08 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'Response Models' ,
// 'permissions' missing on purpose to make sure it's optional
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2023-03-16 16:28:08 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $collection [ 'body' ][ 'name' ], 'Response Models' );
2023-03-19 17:09:17 +00:00
2023-03-24 05:56:49 +00:00
$collectionId = $collection [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$attributesPath = $this -> getSchemaUrl ( $databaseId , $collectionId );
2023-03-24 05:56:49 +00:00
$string = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/string' , array_merge ([
2023-03-16 16:28:08 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'string' ,
'size' => 16 ,
'required' => false ,
'default' => 'default' ,
2023-03-16 16:28:08 +00:00
]);
2023-03-24 05:56:49 +00:00
$email = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/email' , array_merge ([
2023-03-23 14:08:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'email' ,
2023-03-23 14:08:38 +00:00
'required' => false ,
2023-03-24 05:56:49 +00:00
'default' => 'default@example.com' ,
2023-03-23 14:08:38 +00:00
]);
2023-03-24 05:56:49 +00:00
$enum = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/enum' , array_merge ([
2023-03-16 16:28:08 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'enum' ,
'elements' => [ 'yes' , 'no' , 'maybe' ],
'required' => false ,
'default' => 'maybe' ,
2023-03-16 16:28:08 +00:00
]);
2023-03-24 05:56:49 +00:00
$ip = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/ip' , array_merge ([
2023-03-16 16:28:08 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'ip' ,
'required' => false ,
'default' => '192.0.2.0' ,
2023-03-16 16:28:08 +00:00
]);
2023-03-24 05:56:49 +00:00
$url = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/url' , array_merge ([
2023-03-16 16:28:08 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-03-24 05:56:49 +00:00
]), [
'key' => 'url' ,
'required' => false ,
'default' => 'http://example.com' ,
]);
2023-03-19 17:09:17 +00:00
2023-03-24 05:56:49 +00:00
$integer = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/integer' , array_merge ([
2023-03-19 17:09:17 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'integer' ,
'required' => false ,
'min' => 1 ,
'max' => 5 ,
'default' => 3
2023-03-19 17:09:17 +00:00
]);
2023-03-24 05:56:49 +00:00
$float = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/float' , array_merge ([
2023-03-19 17:09:17 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'float' ,
'required' => false ,
'min' => 1.5 ,
'max' => 5.5 ,
'default' => 3.5
2023-03-16 16:28:08 +00:00
]);
2023-03-24 05:56:49 +00:00
$boolean = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/boolean' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'boolean' ,
'required' => false ,
'default' => true ,
]);
2023-03-19 17:09:17 +00:00
2023-03-24 05:56:49 +00:00
$datetime = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/datetime' , array_merge ([
2023-03-21 12:32:05 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'datetime' ,
'required' => false ,
'default' => null ,
2023-03-21 12:32:05 +00:00
]);
2023-03-25 03:29:40 +00:00
$relationship = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/relationship' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => $data [ 'actorsId' ],
2023-03-25 03:29:40 +00:00
'type' => 'oneToMany' ,
'twoWay' => true ,
'key' => 'relationship' ,
'twoWayKey' => 'twoWayKey'
]);
2024-01-21 08:10:18 +00:00
$strings = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'names' ,
'size' => 512 ,
'required' => false ,
'array' => true ,
]);
$integers = $this -> client -> call ( Client :: METHOD_POST , $attributesPath . '/integer' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'numbers' ,
'required' => false ,
'array' => true ,
'min' => 1 ,
'max' => 999 ,
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $string [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'string' , $string [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'string' , $string [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $string [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $string [ 'body' ][ 'array' ]);
$this -> assertEquals ( 16 , $string [ 'body' ][ 'size' ]);
$this -> assertEquals ( 'default' , $string [ 'body' ][ 'default' ]);
2023-03-19 17:09:17 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $email [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'email' , $email [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'string' , $email [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $email [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $email [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'email' , $email [ 'body' ][ 'format' ]);
$this -> assertEquals ( 'default@example.com' , $email [ 'body' ][ 'default' ]);
$this -> assertEquals ( 202 , $enum [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'enum' , $enum [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'string' , $enum [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $enum [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $enum [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'enum' , $enum [ 'body' ][ 'format' ]);
$this -> assertEquals ( 'maybe' , $enum [ 'body' ][ 'default' ]);
$this -> assertIsArray ( $enum [ 'body' ][ 'elements' ]);
$this -> assertEquals ([ 'yes' , 'no' , 'maybe' ], $enum [ 'body' ][ 'elements' ]);
$this -> assertEquals ( 202 , $ip [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'ip' , $ip [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'string' , $ip [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $ip [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $ip [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'ip' , $ip [ 'body' ][ 'format' ]);
$this -> assertEquals ( '192.0.2.0' , $ip [ 'body' ][ 'default' ]);
$this -> assertEquals ( 202 , $url [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'url' , $url [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'string' , $url [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $url [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $url [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'url' , $url [ 'body' ][ 'format' ]);
$this -> assertEquals ( 'http://example.com' , $url [ 'body' ][ 'default' ]);
$this -> assertEquals ( 202 , $integer [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'integer' , $integer [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'integer' , $integer [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $integer [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $integer [ 'body' ][ 'array' ]);
$this -> assertEquals ( 1 , $integer [ 'body' ][ 'min' ]);
$this -> assertEquals ( 5 , $integer [ 'body' ][ 'max' ]);
$this -> assertEquals ( 3 , $integer [ 'body' ][ 'default' ]);
$this -> assertEquals ( 202 , $float [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'float' , $float [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'double' , $float [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $float [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $float [ 'body' ][ 'array' ]);
$this -> assertEquals ( 1.5 , $float [ 'body' ][ 'min' ]);
$this -> assertEquals ( 5.5 , $float [ 'body' ][ 'max' ]);
$this -> assertEquals ( 3.5 , $float [ 'body' ][ 'default' ]);
$this -> assertEquals ( 202 , $boolean [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'boolean' , $boolean [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'boolean' , $boolean [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $boolean [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $boolean [ 'body' ][ 'array' ]);
$this -> assertEquals ( true , $boolean [ 'body' ][ 'default' ]);
$this -> assertEquals ( 202 , $datetime [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'datetime' , $datetime [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'datetime' , $datetime [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $datetime [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $datetime [ 'body' ][ 'array' ]);
$this -> assertEquals ( null , $datetime [ 'body' ][ 'default' ]);
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( 202 , $relationship [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'relationship' , $relationship [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'relationship' , $relationship [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $relationship [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $relationship [ 'body' ][ 'array' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $data [ 'actorsId' ], $relationship [ 'body' ][ $this -> getRelatedResourceKey ()]);
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( 'oneToMany' , $relationship [ 'body' ][ 'relationType' ]);
$this -> assertEquals ( true , $relationship [ 'body' ][ 'twoWay' ]);
$this -> assertEquals ( 'twoWayKey' , $relationship [ 'body' ][ 'twoWayKey' ]);
2024-01-21 08:10:18 +00:00
$this -> assertEquals ( 202 , $strings [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'names' , $strings [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'string' , $strings [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $strings [ 'body' ][ 'required' ]);
$this -> assertEquals ( true , $strings [ 'body' ][ 'array' ]);
$this -> assertEquals ( null , $strings [ 'body' ][ 'default' ]);
$this -> assertEquals ( 202 , $integers [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'numbers' , $integers [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'integer' , $integers [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $integers [ 'body' ][ 'required' ]);
$this -> assertEquals ( true , $integers [ 'body' ][ 'array' ]);
$this -> assertEquals ( 1 , $integers [ 'body' ][ 'min' ]);
$this -> assertEquals ( 999 , $integers [ 'body' ][ 'max' ]);
$this -> assertEquals ( null , $integers [ 'body' ][ 'default' ]);
2023-03-25 03:29:40 +00:00
// Wait for database worker to create attributes
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2023-03-24 05:56:49 +00:00
$stringResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $string [ 'body' ][ 'key' ], array_merge ([
2023-03-19 17:31:15 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-19 17:09:17 +00:00
2023-03-24 05:56:49 +00:00
$emailResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $email [ 'body' ][ 'key' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-23 05:34:13 +00:00
2023-03-24 05:56:49 +00:00
$enumResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $enum [ 'body' ][ 'key' ], array_merge ([
2023-03-21 12:32:05 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-23 05:34:13 +00:00
2023-03-24 05:56:49 +00:00
$ipResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $ip [ 'body' ][ 'key' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-19 17:09:17 +00:00
2023-03-24 05:56:49 +00:00
$urlResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $url [ 'body' ][ 'key' ], array_merge ([
2023-03-23 05:34:13 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-23 05:34:13 +00:00
2023-03-24 05:56:49 +00:00
$integerResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $integer [ 'body' ][ 'key' ], array_merge ([
2023-03-21 17:52:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-03-24 05:56:49 +00:00
]));
2023-03-21 17:52:25 +00:00
2023-03-24 05:56:49 +00:00
$floatResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $float [ 'body' ][ 'key' ], array_merge ([
2023-03-21 17:52:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-24 05:56:49 +00:00
$booleanResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $boolean [ 'body' ][ 'key' ], array_merge ([
2023-03-22 15:49:08 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$datetimeResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $datetime [ 'body' ][ 'key' ], array_merge ([
2023-03-22 15:49:08 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-22 15:49:08 +00:00
2023-03-25 03:29:40 +00:00
$relationshipResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $relationship [ 'body' ][ 'key' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2024-01-21 08:10:18 +00:00
$stringsResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $strings [ 'body' ][ 'key' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
$integersResponse = $this -> client -> call ( Client :: METHOD_GET , $attributesPath . '/' . $integers [ 'body' ][ 'key' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $stringResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $string [ 'body' ][ 'key' ], $stringResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $string [ 'body' ][ 'type' ], $stringResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $stringResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $string [ 'body' ][ 'required' ], $stringResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $string [ 'body' ][ 'array' ], $stringResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( 16 , $stringResponse [ 'body' ][ 'size' ]);
$this -> assertEquals ( $string [ 'body' ][ 'default' ], $stringResponse [ 'body' ][ 'default' ]);
2023-03-22 15:49:08 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $emailResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $email [ 'body' ][ 'key' ], $emailResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $email [ 'body' ][ 'type' ], $emailResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $emailResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $email [ 'body' ][ 'required' ], $emailResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $email [ 'body' ][ 'array' ], $emailResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( $email [ 'body' ][ 'format' ], $emailResponse [ 'body' ][ 'format' ]);
$this -> assertEquals ( $email [ 'body' ][ 'default' ], $emailResponse [ 'body' ][ 'default' ]);
2023-03-22 15:49:08 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $enumResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $enum [ 'body' ][ 'key' ], $enumResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $enum [ 'body' ][ 'type' ], $enumResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $enumResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $enum [ 'body' ][ 'required' ], $enumResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $enum [ 'body' ][ 'array' ], $enumResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( $enum [ 'body' ][ 'format' ], $enumResponse [ 'body' ][ 'format' ]);
$this -> assertEquals ( $enum [ 'body' ][ 'default' ], $enumResponse [ 'body' ][ 'default' ]);
$this -> assertEquals ( $enum [ 'body' ][ 'elements' ], $enumResponse [ 'body' ][ 'elements' ]);
2023-03-22 15:49:08 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $ipResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $ip [ 'body' ][ 'key' ], $ipResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $ip [ 'body' ][ 'type' ], $ipResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $ipResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $ip [ 'body' ][ 'required' ], $ipResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $ip [ 'body' ][ 'array' ], $ipResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( $ip [ 'body' ][ 'format' ], $ipResponse [ 'body' ][ 'format' ]);
$this -> assertEquals ( $ip [ 'body' ][ 'default' ], $ipResponse [ 'body' ][ 'default' ]);
2023-03-22 15:49:08 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $urlResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $url [ 'body' ][ 'key' ], $urlResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $url [ 'body' ][ 'type' ], $urlResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $urlResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $url [ 'body' ][ 'required' ], $urlResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $url [ 'body' ][ 'array' ], $urlResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( $url [ 'body' ][ 'format' ], $urlResponse [ 'body' ][ 'format' ]);
$this -> assertEquals ( $url [ 'body' ][ 'default' ], $urlResponse [ 'body' ][ 'default' ]);
2023-03-23 05:34:13 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $integerResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $integer [ 'body' ][ 'key' ], $integerResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $integer [ 'body' ][ 'type' ], $integerResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $integerResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $integer [ 'body' ][ 'required' ], $integerResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $integer [ 'body' ][ 'array' ], $integerResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( $integer [ 'body' ][ 'min' ], $integerResponse [ 'body' ][ 'min' ]);
$this -> assertEquals ( $integer [ 'body' ][ 'max' ], $integerResponse [ 'body' ][ 'max' ]);
$this -> assertEquals ( $integer [ 'body' ][ 'default' ], $integerResponse [ 'body' ][ 'default' ]);
2023-03-22 16:44:12 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $floatResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $float [ 'body' ][ 'key' ], $floatResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $float [ 'body' ][ 'type' ], $floatResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $floatResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $float [ 'body' ][ 'required' ], $floatResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $float [ 'body' ][ 'array' ], $floatResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( $float [ 'body' ][ 'min' ], $floatResponse [ 'body' ][ 'min' ]);
$this -> assertEquals ( $float [ 'body' ][ 'max' ], $floatResponse [ 'body' ][ 'max' ]);
$this -> assertEquals ( $float [ 'body' ][ 'default' ], $floatResponse [ 'body' ][ 'default' ]);
2023-03-22 16:44:12 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $booleanResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $boolean [ 'body' ][ 'key' ], $booleanResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $boolean [ 'body' ][ 'type' ], $booleanResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $booleanResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $boolean [ 'body' ][ 'required' ], $booleanResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $boolean [ 'body' ][ 'array' ], $booleanResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( $boolean [ 'body' ][ 'default' ], $booleanResponse [ 'body' ][ 'default' ]);
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $datetimeResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $datetime [ 'body' ][ 'key' ], $datetimeResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $datetime [ 'body' ][ 'type' ], $datetimeResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $datetimeResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $datetime [ 'body' ][ 'required' ], $datetimeResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $datetime [ 'body' ][ 'array' ], $datetimeResponse [ 'body' ][ 'array' ]);
$this -> assertEquals ( $datetime [ 'body' ][ 'default' ], $datetimeResponse [ 'body' ][ 'default' ]);
2023-03-24 03:48:50 +00:00
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( 200 , $relationshipResponse [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $relationship [ 'body' ][ 'key' ], $relationshipResponse [ 'body' ][ 'key' ]);
$this -> assertEquals ( $relationship [ 'body' ][ 'type' ], $relationshipResponse [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'available' , $relationshipResponse [ 'body' ][ 'status' ]);
$this -> assertEquals ( $relationship [ 'body' ][ 'required' ], $relationshipResponse [ 'body' ][ 'required' ]);
$this -> assertEquals ( $relationship [ 'body' ][ 'array' ], $relationshipResponse [ 'body' ][ 'array' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $relationship [ 'body' ][ $this -> getRelatedResourceKey ()], $relationshipResponse [ 'body' ][ $this -> getRelatedResourceKey ()]);
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( $relationship [ 'body' ][ 'relationType' ], $relationshipResponse [ 'body' ][ 'relationType' ]);
$this -> assertEquals ( $relationship [ 'body' ][ 'twoWay' ], $relationshipResponse [ 'body' ][ 'twoWay' ]);
$this -> assertEquals ( $relationship [ 'body' ][ 'twoWayKey' ], $relationshipResponse [ 'body' ][ 'twoWayKey' ]);
2026-01-09 14:21:31 +00:00
$attributes = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $collectionId ), array_merge ([
2023-03-24 03:48:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-03-24 05:56:49 +00:00
]));
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $attributes [ 'headers' ][ 'status-code' ]);
2024-01-21 08:10:18 +00:00
$this -> assertEquals ( 12 , $attributes [ 'body' ][ 'total' ]);
2023-03-24 03:48:50 +00:00
2025-10-20 15:18:17 +00:00
/**
2025-10-29 09:08:08 +00:00
* Test for SUCCESS with total = false
2025-10-20 15:18:17 +00:00
*/
2026-01-09 14:21:31 +00:00
$attributesWithIncludeTotalFalse = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $collectionId ), array_merge ([
2025-10-20 15:18:17 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2025-10-29 09:08:08 +00:00
'total' => false
2025-10-20 15:18:17 +00:00
]);
2025-10-20 15:38:14 +00:00
$this -> assertEquals ( 200 , $attributesWithIncludeTotalFalse [ 'headers' ][ 'status-code' ]);
2025-10-20 15:18:17 +00:00
$this -> assertIsArray ( $attributesWithIncludeTotalFalse [ 'body' ]);
2026-01-09 14:21:31 +00:00
$this -> assertIsArray ( $attributesWithIncludeTotalFalse [ 'body' ][ $this -> getSchemaResource ()]);
2025-10-20 15:18:17 +00:00
$this -> assertIsInt ( $attributesWithIncludeTotalFalse [ 'body' ][ 'total' ]);
$this -> assertEquals ( 0 , $attributesWithIncludeTotalFalse [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertGreaterThan ( 0 , count ( $attributesWithIncludeTotalFalse [ 'body' ][ $this -> getSchemaResource ()]));
2025-10-20 15:18:17 +00:00
2026-01-09 14:21:31 +00:00
$attributes = $attributes [ 'body' ][ $this -> getSchemaResource ()];
2023-03-24 05:56:49 +00:00
$this -> assertIsArray ( $attributes );
2024-01-21 08:10:18 +00:00
$this -> assertCount ( 12 , $attributes );
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $stringResponse [ 'body' ][ 'key' ], $attributes [ 0 ][ 'key' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'type' ], $attributes [ 0 ][ 'type' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'status' ], $attributes [ 0 ][ 'status' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'required' ], $attributes [ 0 ][ 'required' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'array' ], $attributes [ 0 ][ 'array' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'size' ], $attributes [ 0 ][ 'size' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'default' ], $attributes [ 0 ][ 'default' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'key' ], $attributes [ 1 ][ 'key' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'type' ], $attributes [ 1 ][ 'type' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'status' ], $attributes [ 1 ][ 'status' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'required' ], $attributes [ 1 ][ 'required' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'array' ], $attributes [ 1 ][ 'array' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'default' ], $attributes [ 1 ][ 'default' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'format' ], $attributes [ 1 ][ 'format' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'key' ], $attributes [ 2 ][ 'key' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'type' ], $attributes [ 2 ][ 'type' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'status' ], $attributes [ 2 ][ 'status' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'required' ], $attributes [ 2 ][ 'required' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'array' ], $attributes [ 2 ][ 'array' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'default' ], $attributes [ 2 ][ 'default' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'format' ], $attributes [ 2 ][ 'format' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'elements' ], $attributes [ 2 ][ 'elements' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'key' ], $attributes [ 3 ][ 'key' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'type' ], $attributes [ 3 ][ 'type' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'status' ], $attributes [ 3 ][ 'status' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'required' ], $attributes [ 3 ][ 'required' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'array' ], $attributes [ 3 ][ 'array' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'default' ], $attributes [ 3 ][ 'default' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'format' ], $attributes [ 3 ][ 'format' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'key' ], $attributes [ 4 ][ 'key' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'type' ], $attributes [ 4 ][ 'type' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'status' ], $attributes [ 4 ][ 'status' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'required' ], $attributes [ 4 ][ 'required' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'array' ], $attributes [ 4 ][ 'array' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'default' ], $attributes [ 4 ][ 'default' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'format' ], $attributes [ 4 ][ 'format' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'key' ], $attributes [ 5 ][ 'key' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'type' ], $attributes [ 5 ][ 'type' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'status' ], $attributes [ 5 ][ 'status' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'required' ], $attributes [ 5 ][ 'required' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'array' ], $attributes [ 5 ][ 'array' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'default' ], $attributes [ 5 ][ 'default' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'min' ], $attributes [ 5 ][ 'min' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'max' ], $attributes [ 5 ][ 'max' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'key' ], $attributes [ 6 ][ 'key' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'type' ], $attributes [ 6 ][ 'type' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'status' ], $attributes [ 6 ][ 'status' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'required' ], $attributes [ 6 ][ 'required' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'array' ], $attributes [ 6 ][ 'array' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'default' ], $attributes [ 6 ][ 'default' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'min' ], $attributes [ 6 ][ 'min' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'max' ], $attributes [ 6 ][ 'max' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'key' ], $attributes [ 7 ][ 'key' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'type' ], $attributes [ 7 ][ 'type' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'status' ], $attributes [ 7 ][ 'status' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'required' ], $attributes [ 7 ][ 'required' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'array' ], $attributes [ 7 ][ 'array' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'default' ], $attributes [ 7 ][ 'default' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'key' ], $attributes [ 8 ][ 'key' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'type' ], $attributes [ 8 ][ 'type' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'status' ], $attributes [ 8 ][ 'status' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'required' ], $attributes [ 8 ][ 'required' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'array' ], $attributes [ 8 ][ 'array' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'default' ], $attributes [ 8 ][ 'default' ]);
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'key' ], $attributes [ 9 ][ 'key' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'type' ], $attributes [ 9 ][ 'type' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'status' ], $attributes [ 9 ][ 'status' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'required' ], $attributes [ 9 ][ 'required' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'array' ], $attributes [ 9 ][ 'array' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $relationshipResponse [ 'body' ][ $this -> getRelatedResourceKey ()], $attributes [ 9 ][ $this -> getRelatedResourceKey ()]);
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'relationType' ], $attributes [ 9 ][ 'relationType' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'twoWay' ], $attributes [ 9 ][ 'twoWay' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'twoWayKey' ], $attributes [ 9 ][ 'twoWayKey' ]);
2024-01-21 08:10:18 +00:00
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'key' ], $attributes [ 10 ][ 'key' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'type' ], $attributes [ 10 ][ 'type' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'status' ], $attributes [ 10 ][ 'status' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'required' ], $attributes [ 10 ][ 'required' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'array' ], $attributes [ 10 ][ 'array' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'default' ], $attributes [ 10 ][ 'default' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'key' ], $attributes [ 11 ][ 'key' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'type' ], $attributes [ 11 ][ 'type' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'status' ], $attributes [ 11 ][ 'status' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'required' ], $attributes [ 11 ][ 'required' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'array' ], $attributes [ 11 ][ 'array' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'default' ], $attributes [ 11 ][ 'default' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'min' ], $attributes [ 11 ][ 'min' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'max' ], $attributes [ 11 ][ 'max' ]);
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2023-03-24 03:48:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-03-24 05:56:49 +00:00
]));
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $collection [ 'headers' ][ 'status-code' ]);
2023-03-24 03:48:50 +00:00
2026-01-09 14:21:31 +00:00
$attributes = $collection [ 'body' ][ $this -> getSchemaResource ()];
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertIsArray ( $attributes );
2024-01-21 08:10:18 +00:00
$this -> assertCount ( 12 , $attributes );
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $stringResponse [ 'body' ][ 'key' ], $attributes [ 0 ][ 'key' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'type' ], $attributes [ 0 ][ 'type' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'status' ], $attributes [ 0 ][ 'status' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'required' ], $attributes [ 0 ][ 'required' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'array' ], $attributes [ 0 ][ 'array' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'size' ], $attributes [ 0 ][ 'size' ]);
$this -> assertEquals ( $stringResponse [ 'body' ][ 'default' ], $attributes [ 0 ][ 'default' ]);
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $emailResponse [ 'body' ][ 'key' ], $attributes [ 1 ][ 'key' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'type' ], $attributes [ 1 ][ 'type' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'status' ], $attributes [ 1 ][ 'status' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'required' ], $attributes [ 1 ][ 'required' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'array' ], $attributes [ 1 ][ 'array' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'default' ], $attributes [ 1 ][ 'default' ]);
$this -> assertEquals ( $emailResponse [ 'body' ][ 'format' ], $attributes [ 1 ][ 'format' ]);
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $enumResponse [ 'body' ][ 'key' ], $attributes [ 2 ][ 'key' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'type' ], $attributes [ 2 ][ 'type' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'status' ], $attributes [ 2 ][ 'status' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'required' ], $attributes [ 2 ][ 'required' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'array' ], $attributes [ 2 ][ 'array' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'default' ], $attributes [ 2 ][ 'default' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'format' ], $attributes [ 2 ][ 'format' ]);
$this -> assertEquals ( $enumResponse [ 'body' ][ 'elements' ], $attributes [ 2 ][ 'elements' ]);
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $ipResponse [ 'body' ][ 'key' ], $attributes [ 3 ][ 'key' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'type' ], $attributes [ 3 ][ 'type' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'status' ], $attributes [ 3 ][ 'status' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'required' ], $attributes [ 3 ][ 'required' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'array' ], $attributes [ 3 ][ 'array' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'default' ], $attributes [ 3 ][ 'default' ]);
$this -> assertEquals ( $ipResponse [ 'body' ][ 'format' ], $attributes [ 3 ][ 'format' ]);
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $urlResponse [ 'body' ][ 'key' ], $attributes [ 4 ][ 'key' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'type' ], $attributes [ 4 ][ 'type' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'status' ], $attributes [ 4 ][ 'status' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'required' ], $attributes [ 4 ][ 'required' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'array' ], $attributes [ 4 ][ 'array' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'default' ], $attributes [ 4 ][ 'default' ]);
$this -> assertEquals ( $urlResponse [ 'body' ][ 'format' ], $attributes [ 4 ][ 'format' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'key' ], $attributes [ 5 ][ 'key' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'type' ], $attributes [ 5 ][ 'type' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'status' ], $attributes [ 5 ][ 'status' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'required' ], $attributes [ 5 ][ 'required' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'array' ], $attributes [ 5 ][ 'array' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'default' ], $attributes [ 5 ][ 'default' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'min' ], $attributes [ 5 ][ 'min' ]);
$this -> assertEquals ( $integerResponse [ 'body' ][ 'max' ], $attributes [ 5 ][ 'max' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'key' ], $attributes [ 6 ][ 'key' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'type' ], $attributes [ 6 ][ 'type' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'status' ], $attributes [ 6 ][ 'status' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'required' ], $attributes [ 6 ][ 'required' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'array' ], $attributes [ 6 ][ 'array' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'default' ], $attributes [ 6 ][ 'default' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'min' ], $attributes [ 6 ][ 'min' ]);
$this -> assertEquals ( $floatResponse [ 'body' ][ 'max' ], $attributes [ 6 ][ 'max' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'key' ], $attributes [ 7 ][ 'key' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'type' ], $attributes [ 7 ][ 'type' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'status' ], $attributes [ 7 ][ 'status' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'required' ], $attributes [ 7 ][ 'required' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'array' ], $attributes [ 7 ][ 'array' ]);
$this -> assertEquals ( $booleanResponse [ 'body' ][ 'default' ], $attributes [ 7 ][ 'default' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'key' ], $attributes [ 8 ][ 'key' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'type' ], $attributes [ 8 ][ 'type' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'status' ], $attributes [ 8 ][ 'status' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'required' ], $attributes [ 8 ][ 'required' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'array' ], $attributes [ 8 ][ 'array' ]);
$this -> assertEquals ( $datetimeResponse [ 'body' ][ 'default' ], $attributes [ 8 ][ 'default' ]);
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'key' ], $attributes [ 9 ][ 'key' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'type' ], $attributes [ 9 ][ 'type' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'status' ], $attributes [ 9 ][ 'status' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'required' ], $attributes [ 9 ][ 'required' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'array' ], $attributes [ 9 ][ 'array' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $relationshipResponse [ 'body' ][ $this -> getRelatedResourceKey ()], $attributes [ 9 ][ $this -> getRelatedResourceKey ()]);
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'relationType' ], $attributes [ 9 ][ 'relationType' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'twoWay' ], $attributes [ 9 ][ 'twoWay' ]);
$this -> assertEquals ( $relationshipResponse [ 'body' ][ 'twoWayKey' ], $attributes [ 9 ][ 'twoWayKey' ]);
2024-01-21 08:10:18 +00:00
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'key' ], $attributes [ 10 ][ 'key' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'type' ], $attributes [ 10 ][ 'type' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'status' ], $attributes [ 10 ][ 'status' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'required' ], $attributes [ 10 ][ 'required' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'array' ], $attributes [ 10 ][ 'array' ]);
$this -> assertEquals ( $stringsResponse [ 'body' ][ 'default' ], $attributes [ 10 ][ 'default' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'key' ], $attributes [ 11 ][ 'key' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'type' ], $attributes [ 11 ][ 'type' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'status' ], $attributes [ 11 ][ 'status' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'required' ], $attributes [ 11 ][ 'required' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'array' ], $attributes [ 11 ][ 'array' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'default' ], $attributes [ 11 ][ 'default' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'min' ], $attributes [ 11 ][ 'min' ]);
$this -> assertEquals ( $integersResponse [ 'body' ][ 'max' ], $attributes [ 11 ][ 'max' ]);
2023-03-24 05:56:49 +00:00
/**
* Test for FAILURE
*/
2026-01-09 14:21:31 +00:00
$badEnum = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/enum' , array_merge ([
2023-03-24 03:48:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'enum' ,
'elements' => [ 'yes' , 'no' , '' ],
'required' => false ,
'default' => 'maybe' ,
]);
2023-03-24 03:48:50 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 400 , $badEnum [ 'headers' ][ 'status-code' ]);
2024-01-24 14:56:43 +00:00
$this -> assertEquals ( 'Invalid `elements` param: Value must a valid array no longer than 100 items and Value must be a valid string and at least 1 chars and no longer than 255 chars' , $badEnum [ 'body' ][ 'message' ]);
2023-03-24 03:48:50 +00:00
}
2026-02-05 22:56:58 +00:00
public function testCreateIndexes () : void
2023-03-24 03:48:50 +00:00
{
2026-02-06 05:50:36 +00:00
// Use dedicated collection for index testing to avoid conflicts with setupIndexes()
$data = $this -> setupDatabase ();
2023-03-24 03:48:50 +00:00
$databaseId = $data [ 'databaseId' ];
2023-06-15 05:28:35 +00:00
2026-02-06 05:50:36 +00:00
// Create dedicated collection for index testing
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'IndexTestCollection' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create attributes needed for index testing
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [ 'key' => 'title' , 'size' => 256 , 'required' => true ]);
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
$description = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [ 'key' => 'description' , 'size' => 512 , 'required' => false , 'default' => '' ]);
$this -> assertEquals ( 202 , $description [ 'headers' ][ 'status-code' ]);
$tagline = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [ 'key' => 'tagline' , 'size' => 512 , 'required' => false , 'default' => '' ]);
$this -> assertEquals ( 202 , $tagline [ 'headers' ][ 'status-code' ]);
$releaseYear = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [ 'key' => 'releaseYear' , 'required' => true , 'min' => 1900 , 'max' => 2200 ]);
$this -> assertEquals ( 202 , $releaseYear [ 'headers' ][ 'status-code' ]);
$actors = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [ 'key' => 'actors' , 'size' => 256 , 'required' => false , 'array' => true ]);
$this -> assertEquals ( 202 , $actors [ 'headers' ][ 'status-code' ]);
$birthDay = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/datetime' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [ 'key' => 'birthDay' , 'required' => false ]);
$this -> assertEquals ( 202 , $birthDay [ 'headers' ][ 'status-code' ]);
$integers = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [ 'key' => 'integers' , 'required' => false , 'array' => true , 'min' => 10 , 'max' => 99 ]);
$this -> assertEquals ( 202 , $integers [ 'headers' ][ 'status-code' ]);
// Wait for attributes to be ready
$this -> waitForAllAttributes ( $databaseId , $collectionId );
$titleIndex = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2023-03-24 03:48:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'titleIndex' ,
'type' => 'fulltext' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'title' ],
2023-03-24 03:48:50 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $titleIndex [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'titleIndex' , $titleIndex [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'fulltext' , $titleIndex [ 'body' ][ 'type' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $titleIndex [ 'body' ][ $this -> getSchemaResource ()]);
$this -> assertEquals ( 'title' , $titleIndex [ 'body' ][ $this -> getSchemaResource ()][ 0 ]);
2023-03-24 03:48:50 +00:00
2026-02-06 05:50:36 +00:00
$releaseYearIndex = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2023-03-24 03:48:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'releaseYear' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'releaseYear' ],
2023-03-24 03:48:50 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $releaseYearIndex [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'releaseYear' , $releaseYearIndex [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'key' , $releaseYearIndex [ 'body' ][ 'type' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $releaseYearIndex [ 'body' ][ $this -> getSchemaResource ()]);
$this -> assertEquals ( 'releaseYear' , $releaseYearIndex [ 'body' ][ $this -> getSchemaResource ()][ 0 ]);
2023-03-24 03:48:50 +00:00
2026-02-06 05:50:36 +00:00
$releaseWithDate1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2023-03-24 03:48:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'releaseYearDated' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'releaseYear' , '$createdAt' , '$updatedAt' ],
2023-03-24 03:48:50 +00:00
]);
2024-02-08 13:01:20 +00:00
$this -> assertEquals ( 202 , $releaseWithDate1 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'releaseYearDated' , $releaseWithDate1 [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'key' , $releaseWithDate1 [ 'body' ][ 'type' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 3 , $releaseWithDate1 [ 'body' ][ $this -> getSchemaResource ()]);
$this -> assertEquals ( 'releaseYear' , $releaseWithDate1 [ 'body' ][ $this -> getSchemaResource ()][ 0 ]);
$this -> assertEquals ( '$createdAt' , $releaseWithDate1 [ 'body' ][ $this -> getSchemaResource ()][ 1 ]);
$this -> assertEquals ( '$updatedAt' , $releaseWithDate1 [ 'body' ][ $this -> getSchemaResource ()][ 2 ]);
2023-03-24 03:48:50 +00:00
2026-02-06 05:50:36 +00:00
$releaseWithDate2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2023-03-24 03:48:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'birthDay' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'birthDay' ],
2023-03-24 05:56:49 +00:00
]);
2023-03-24 03:48:50 +00:00
2024-02-08 13:01:20 +00:00
$this -> assertEquals ( 202 , $releaseWithDate2 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'birthDay' , $releaseWithDate2 [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'key' , $releaseWithDate2 [ 'body' ][ 'type' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $releaseWithDate2 [ 'body' ][ $this -> getSchemaResource ()]);
$this -> assertEquals ( 'birthDay' , $releaseWithDate2 [ 'body' ][ $this -> getSchemaResource ()][ 0 ]);
2023-03-24 03:48:50 +00:00
2023-06-15 05:28:35 +00:00
// Test for failure
2026-02-06 05:50:36 +00:00
$fulltextReleaseYear = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2023-06-15 05:28:35 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'releaseYearDated' ,
'type' => 'fulltext' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'releaseYear' ],
2023-06-15 05:28:35 +00:00
]);
$this -> assertEquals ( 400 , $fulltextReleaseYear [ 'headers' ][ 'status-code' ]);
2025-10-20 12:24:50 +00:00
$this -> assertEquals ( $fulltextReleaseYear [ 'body' ][ 'message' ], 'Attribute "releaseYear" cannot be part of a fulltext index, must be of type string' );
2023-06-15 05:28:35 +00:00
2026-02-06 05:50:36 +00:00
$noAttributes = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2023-06-15 05:28:35 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'none' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [],
2023-06-15 05:28:35 +00:00
]);
$this -> assertEquals ( 400 , $noAttributes [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $noAttributes [ 'body' ][ 'message' ], 'No attributes provided for index' );
2026-02-06 05:50:36 +00:00
$duplicates = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2023-06-15 05:28:35 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'duplicate' ,
'type' => 'fulltext' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'releaseYear' , 'releaseYear' ],
2023-06-15 05:28:35 +00:00
]);
$this -> assertEquals ( 400 , $duplicates [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $duplicates [ 'body' ][ 'message' ], 'Duplicate attributes provided' );
2026-02-06 05:50:36 +00:00
$tooLong = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2023-06-15 05:28:35 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'key' => 'tooLong' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'description' , 'tagline' ],
2023-06-15 05:28:35 +00:00
]);
$this -> assertEquals ( 400 , $tooLong [ 'headers' ][ 'status-code' ]);
$this -> assertStringContainsString ( 'Index length is longer than the maximum' , $tooLong [ 'body' ][ 'message' ]);
2026-02-06 05:50:36 +00:00
$fulltextArray = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2024-01-21 08:10:18 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'key' => 'ft' ,
'type' => 'fulltext' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'actors' ],
2024-01-21 08:10:18 +00:00
]);
2024-01-21 16:22:02 +00:00
2024-01-21 08:10:18 +00:00
$this -> assertEquals ( 400 , $fulltextArray [ 'headers' ][ 'status-code' ]);
2025-12-08 10:20:40 +00:00
$this -> assertEquals ( 'Creating indexes on array attributes is not currently supported.' , $fulltextArray [ 'body' ][ 'message' ]);
2024-01-21 16:22:02 +00:00
2026-02-06 05:50:36 +00:00
$actorsArray = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2024-01-21 16:22:02 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'key' => 'index-actors' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'actors' ],
2024-01-21 16:22:02 +00:00
]);
2025-12-08 10:20:40 +00:00
$this -> assertEquals ( 400 , $actorsArray [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Creating indexes on array attributes is not currently supported.' , $actorsArray [ 'body' ][ 'message' ]);
2024-01-21 16:22:02 +00:00
2026-02-06 05:50:36 +00:00
$twoLevelsArray = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2024-01-21 16:22:02 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'key' => 'index-ip-actors' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'releaseYear' , 'actors' ], // 2 levels
2024-02-08 13:01:20 +00:00
'orders' => [ 'DESC' , 'DESC' ],
2024-01-21 16:22:02 +00:00
]);
2025-12-08 10:20:40 +00:00
$this -> assertEquals ( 400 , $twoLevelsArray [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Creating indexes on array attributes is not currently supported.' , $twoLevelsArray [ 'body' ][ 'message' ]);
2024-01-21 16:22:02 +00:00
2026-02-06 05:50:36 +00:00
$unknown = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2024-01-21 16:22:02 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'key' => 'index-unknown' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'Unknown' ],
2024-01-21 16:22:02 +00:00
]);
$this -> assertEquals ( 400 , $unknown [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertStringContainsString ( '\'Unknown\' required for the index could not be found' , $unknown [ 'body' ][ 'message' ]);
2024-01-21 08:10:18 +00:00
2026-02-06 05:50:36 +00:00
$index1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2024-02-08 13:01:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'key' => 'integers-order' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'integers' ], // array attribute
2024-02-08 13:01:20 +00:00
'orders' => [ 'DESC' ], // Check order is removed in API
]);
2025-07-21 07:13:34 +00:00
2025-12-08 10:20:40 +00:00
$this -> assertEquals ( 400 , $index1 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Creating indexes on array attributes is not currently supported.' , $index1 [ 'body' ][ 'message' ]);
2024-02-08 13:01:20 +00:00
2026-02-06 05:50:36 +00:00
$index2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2024-02-08 13:01:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
'key' => 'integers-size' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'integers' ], // array attribute
2024-02-08 13:01:20 +00:00
]);
2025-07-21 07:13:34 +00:00
2025-12-08 10:20:40 +00:00
$this -> assertEquals ( 400 , $index2 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Creating indexes on array attributes is not currently supported.' , $index2 [ 'body' ][ 'message' ]);
2024-02-08 13:01:20 +00:00
/**
* Create Indexes by worker
*/
2026-02-06 05:50:36 +00:00
$this -> waitForAllIndexes ( $databaseId , $collectionId );
2024-02-08 13:01:20 +00:00
2026-02-06 05:50:36 +00:00
$collectionResponse = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2024-02-08 13:01:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), []);
2026-02-06 05:50:36 +00:00
$this -> assertIsArray ( $collectionResponse [ 'body' ][ 'indexes' ]);
$this -> assertCount ( 4 , $collectionResponse [ 'body' ][ 'indexes' ]);
$this -> assertEquals ( $titleIndex [ 'body' ][ 'key' ], $collectionResponse [ 'body' ][ 'indexes' ][ 0 ][ 'key' ]);
$this -> assertEquals ( $releaseYearIndex [ 'body' ][ 'key' ], $collectionResponse [ 'body' ][ 'indexes' ][ 1 ][ 'key' ]);
$this -> assertEquals ( $releaseWithDate1 [ 'body' ][ 'key' ], $collectionResponse [ 'body' ][ 'indexes' ][ 2 ][ 'key' ]);
$this -> assertEquals ( $releaseWithDate2 [ 'body' ][ 'key' ], $collectionResponse [ 'body' ][ 'indexes' ][ 3 ][ 'key' ]);
2025-07-01 12:40:19 +00:00
2026-02-06 05:50:36 +00:00
$this -> assertEventually ( function () use ( $databaseId , $collectionId ) {
$collResp = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-07-01 12:40:19 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-02-06 05:50:36 +00:00
foreach ( $collResp [ 'body' ][ 'indexes' ] as $index ) {
2025-07-01 12:40:19 +00:00
$this -> assertEquals ( 'available' , $index [ 'status' ]);
}
return true ;
}, 60000 , 500 );
2023-03-23 14:08:38 +00:00
}
2026-02-05 22:56:58 +00:00
public function testGetIndexByKeyWithLengths () : void
2025-05-13 05:05:04 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupAttributes ();
2025-05-13 05:05:04 +00:00
$databaseId = $data [ 'databaseId' ];
$collectionId = $data [ 'moviesId' ];
2025-05-13 10:09:13 +00:00
// Test case for valid lengths
2026-01-09 14:21:31 +00:00
$create = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), [
2025-05-13 05:05:04 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'lengthTestIndex' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'title' , 'description' ],
2025-05-13 05:05:04 +00:00
'lengths' => [ 128 , 200 ]
]);
$this -> assertEquals ( 202 , $create [ 'headers' ][ 'status-code' ]);
2025-05-13 10:09:13 +00:00
// Fetch index and check correct lengths
2026-01-09 14:21:31 +00:00
$index = $this -> client -> call ( Client :: METHOD_GET , $this -> getIndexUrl ( $databaseId , $collectionId , " lengthTestIndex " ), [
2025-05-13 05:05:04 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]);
$this -> assertEquals ( 200 , $index [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'lengthTestIndex' , $index [ 'body' ][ 'key' ]);
2025-05-13 10:09:13 +00:00
$this -> assertEquals ([ 128 , 200 ], $index [ 'body' ][ 'lengths' ]);
2025-12-08 10:20:40 +00:00
// Test case for array attribute index (should be blocked)
2026-01-09 14:21:31 +00:00
$create = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), [
2025-08-15 07:35:37 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'lengthOverrideTestIndex' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'actors' ],
2025-08-15 07:35:37 +00:00
'lengths' => [ 120 ]
]);
2025-12-08 10:20:40 +00:00
$this -> assertEquals ( 400 , $create [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Creating indexes on array attributes is not currently supported.' , $create [ 'body' ][ 'message' ]);
2025-08-15 07:35:37 +00:00
2025-05-13 10:09:13 +00:00
// Test case for count of lengths greater than attributes (should throw 400)
2026-01-09 14:21:31 +00:00
$create = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), [
2025-05-13 10:09:13 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'lengthCountExceededIndex' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'title' ],
2025-05-13 10:09:13 +00:00
'lengths' => [ 128 , 128 ]
]);
$this -> assertEquals ( 400 , $create [ 'headers' ][ 'status-code' ]);
// Test case for lengths exceeding total of 768
2026-01-09 14:21:31 +00:00
$create = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), [
2025-05-13 10:09:13 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'lengthTooLargeIndex' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'title' , 'description' , 'tagline' , 'actors' ],
2025-05-13 10:09:13 +00:00
'lengths' => [ 256 , 256 , 256 , 20 ]
]);
$this -> assertEquals ( 400 , $create [ 'headers' ][ 'status-code' ]);
// Test case for negative length values
2026-01-09 14:21:31 +00:00
$create = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), [
2025-05-13 10:09:13 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'negativeLengthIndex' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'title' ],
2025-05-13 10:09:13 +00:00
'lengths' => [ - 1 ]
]);
$this -> assertEquals ( 400 , $create [ 'headers' ][ 'status-code' ]);
2025-05-13 05:05:04 +00:00
}
2026-02-05 22:56:58 +00:00
public function testListIndexes () : void
2023-07-21 11:10:44 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupIndexes ();
2023-07-21 11:10:44 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getIndexUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-08-09 18:41:18 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: equal ( 'type' , [ 'key' ]) -> toString (),
Query :: limit ( 2 ) -> toString ()
],
2023-08-09 18:41:18 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2 , \count ( $response [ 'body' ][ 'indexes' ]));
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getIndexUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-07-21 11:10:44 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: select ([ 'key' ]) -> toString (),
],
2023-07-21 11:10:44 +00:00
]);
2023-08-09 18:41:18 +00:00
$this -> assertEquals ( Exception :: GENERAL_ARGUMENT_INVALID , $response [ 'body' ][ 'type' ]);
$this -> assertEquals ( 400 , $response [ 'headers' ][ 'status-code' ]);
2023-07-21 11:10:44 +00:00
}
2026-02-05 22:56:58 +00:00
public function testCreateDocument () : void
2023-03-23 14:08:38 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupIndexes ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$document1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-23 14:08:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'title' => 'Captain America' ,
'releaseYear' => 1944 ,
'birthDay' => '1975-06-12 14:12:55+02:00' ,
'actors' => [
'Chris Evans' ,
'Samuel Jackson' ,
]
2023-03-24 03:48:50 +00:00
],
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
2023-03-24 03:48:50 +00:00
]);
2026-01-09 14:21:31 +00:00
$document2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-24 03:48:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'title' => 'Spider-Man: Far From Home' ,
'releaseYear' => 2019 ,
'birthDay' => null ,
'actors' => [
'Tom Holland' ,
'Zendaya Maree Stoermer' ,
'Samuel Jackson' ,
2024-01-21 16:22:02 +00:00
],
'integers' => [ 50 , 60 ]
2023-03-23 14:08:38 +00:00
],
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
2023-03-23 14:08:38 +00:00
]);
2026-01-09 14:21:31 +00:00
$document3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-23 14:08:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'title' => 'Spider-Man: Homecoming' ,
'releaseYear' => 2017 ,
'birthDay' => '1975-06-12 14:12:55 America/New_York' ,
2023-03-25 03:29:40 +00:00
'duration' => 65 ,
2023-03-24 05:56:49 +00:00
'actors' => [
'Tom Holland' ,
'Zendaya Maree Stoermer' ,
],
2024-01-21 16:22:02 +00:00
'integers' => [ 50 ]
2023-03-23 14:08:38 +00:00
],
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
2023-03-23 14:08:38 +00:00
]);
2026-01-09 14:21:31 +00:00
$document4 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-23 14:08:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'releaseYear' => 2020 , // Missing title, expect an 400 error
2023-03-23 14:08:38 +00:00
],
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
2023-03-23 14:08:38 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document1 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $data [ 'moviesId' ], $document1 [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $document1 [ 'body' ]);
$this -> assertEquals ( $databaseId , $document1 [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $document1 [ 'body' ][ 'title' ], 'Captain America' );
$this -> assertEquals ( $document1 [ 'body' ][ 'releaseYear' ], 1944 );
$this -> assertIsArray ( $document1 [ 'body' ][ '$permissions' ]);
$this -> assertCount ( 3 , $document1 [ 'body' ][ '$permissions' ]);
$this -> assertCount ( 2 , $document1 [ 'body' ][ 'actors' ]);
$this -> assertEquals ( $document1 [ 'body' ][ 'actors' ][ 0 ], 'Chris Evans' );
$this -> assertEquals ( $document1 [ 'body' ][ 'actors' ][ 1 ], 'Samuel Jackson' );
$this -> assertEquals ( $document1 [ 'body' ][ 'birthDay' ], '1975-06-12T12:12:55.000+00:00' );
2025-05-23 10:51:20 +00:00
$this -> assertTrue ( array_key_exists ( '$sequence' , $document1 [ 'body' ]));
2025-07-29 04:54:39 +00:00
$this -> assertIsInt ( $document1 [ 'body' ][ '$sequence' ]);
2023-03-23 14:08:38 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document2 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $data [ 'moviesId' ], $document2 [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $document2 [ 'body' ]);
$this -> assertEquals ( $databaseId , $document2 [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $document2 [ 'body' ][ 'title' ], 'Spider-Man: Far From Home' );
$this -> assertEquals ( $document2 [ 'body' ][ 'releaseYear' ], 2019 );
$this -> assertEquals ( $document2 [ 'body' ][ 'duration' ], null );
$this -> assertIsArray ( $document2 [ 'body' ][ '$permissions' ]);
$this -> assertCount ( 3 , $document2 [ 'body' ][ '$permissions' ]);
$this -> assertCount ( 3 , $document2 [ 'body' ][ 'actors' ]);
$this -> assertEquals ( $document2 [ 'body' ][ 'actors' ][ 0 ], 'Tom Holland' );
$this -> assertEquals ( $document2 [ 'body' ][ 'actors' ][ 1 ], 'Zendaya Maree Stoermer' );
$this -> assertEquals ( $document2 [ 'body' ][ 'actors' ][ 2 ], 'Samuel Jackson' );
$this -> assertEquals ( $document2 [ 'body' ][ 'birthDay' ], null );
2024-01-21 16:22:02 +00:00
$this -> assertEquals ( $document2 [ 'body' ][ 'integers' ][ 0 ], 50 );
$this -> assertEquals ( $document2 [ 'body' ][ 'integers' ][ 1 ], 60 );
2025-05-23 10:51:20 +00:00
$this -> assertTrue ( array_key_exists ( '$sequence' , $document2 [ 'body' ]));
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document3 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $data [ 'moviesId' ], $document3 [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $document3 [ 'body' ]);
$this -> assertEquals ( $databaseId , $document3 [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $document3 [ 'body' ][ 'title' ], 'Spider-Man: Homecoming' );
$this -> assertEquals ( $document3 [ 'body' ][ 'releaseYear' ], 2017 );
2023-03-25 03:29:40 +00:00
$this -> assertEquals ( $document3 [ 'body' ][ 'duration' ], 65 );
2023-03-24 05:56:49 +00:00
$this -> assertIsArray ( $document3 [ 'body' ][ '$permissions' ]);
$this -> assertCount ( 3 , $document3 [ 'body' ][ '$permissions' ]);
$this -> assertCount ( 2 , $document3 [ 'body' ][ 'actors' ]);
$this -> assertEquals ( $document3 [ 'body' ][ 'actors' ][ 0 ], 'Tom Holland' );
$this -> assertEquals ( $document3 [ 'body' ][ 'actors' ][ 1 ], 'Zendaya Maree Stoermer' );
$this -> assertEquals ( $document3 [ 'body' ][ 'birthDay' ], '1975-06-12T18:12:55.000+00:00' ); // UTC for NY
2025-05-23 10:51:20 +00:00
$this -> assertTrue ( array_key_exists ( '$sequence' , $document3 [ 'body' ]));
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 400 , $document4 [ 'headers' ][ 'status-code' ]);
2023-03-16 16:28:08 +00:00
}
2026-02-05 22:56:58 +00:00
public function testUpsertDocument () : void
2025-05-19 08:26:11 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupIndexes ();
2025-05-19 08:26:11 +00:00
$databaseId = $data [ 'databaseId' ];
$documentId = ID :: unique ();
2025-08-24 08:33:10 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-05-19 08:26:11 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Ragnarok' ,
'releaseYear' => 2000
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
]);
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
2025-05-19 10:29:38 +00:00
$this -> assertCount ( 3 , $document [ 'body' ][ '$permissions' ]);
2025-08-24 08:33:10 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2023-05-30 02:07:12 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-05-19 08:26:11 +00:00
], $this -> getHeaders ()));
2023-05-30 02:07:12 +00:00
2025-05-19 08:26:11 +00:00
$this -> assertEquals ( 'Thor: Ragnarok' , $document [ 'body' ][ 'title' ]);
2025-08-24 14:39:29 +00:00
/**
* Resubmit same document , nothing to update
*/
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-08-24 14:39:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-08-24 15:09:38 +00:00
'data' => [
2025-08-24 14:39:29 +00:00
'title' => 'Thor: Ragnarok' ,
'releaseYear' => 2000 ,
'integers' => [],
'birthDay' => null ,
'duration' => null ,
'starringActors' => [],
'actors' => [],
'tagline' => '' ,
'description' => '' ,
2025-08-24 15:09:38 +00:00
],
2025-08-24 14:39:29 +00:00
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
]);
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Thor: Ragnarok' , $document [ 'body' ][ 'title' ]);
$this -> assertCount ( 3 , $document [ 'body' ][ '$permissions' ]);
2025-05-19 08:26:11 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-05-19 08:26:11 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Love and Thunder' ,
'releaseYear' => 2000
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
]);
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Thor: Love and Thunder' , $document [ 'body' ][ 'title' ]);
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-05-19 08:26:11 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 'Thor: Love and Thunder' , $document [ 'body' ][ 'title' ]);
2025-05-19 10:29:38 +00:00
// removing permission to read and delete
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-05-19 10:29:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Love and Thunder' ,
'releaseYear' => 2000
],
'permissions' => [
Permission :: update ( Role :: users ())
],
]);
// shouldn't be able to read as no read permission
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-05-19 10:29:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
switch ( $this -> getSide ()) {
case 'client' :
$this -> assertEquals ( 404 , $document [ 'headers' ][ 'status-code' ]);
break ;
case 'server' :
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
break ;
}
// shouldn't be able to delete as no delete permission
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_DELETE , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-05-19 08:26:11 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2025-05-20 08:58:16 +00:00
// simulating for the client
// the document should not be allowed to be deleted as needed downward
if ( $this -> getSide () === 'client' ) {
$this -> assertEquals ( 401 , $document [ 'headers' ][ 'status-code' ]);
}
2025-05-19 10:29:38 +00:00
// giving the delete permission
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-05-19 10:29:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Love and Thunder' ,
'releaseYear' => 2000
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ())
],
]);
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_DELETE , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-05-19 10:29:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 204 , $document [ 'headers' ][ 'status-code' ]);
2025-05-20 06:41:41 +00:00
// relationship behaviour
2026-01-09 14:21:31 +00:00
$person = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => 'person-upsert' ,
2025-05-20 06:41:41 +00:00
'name' => 'person' ,
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
Permission :: create ( Role :: users ()),
],
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-05-20 06:41:41 +00:00
]);
$this -> assertEquals ( 201 , $person [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$library = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => 'library-upsert' ,
2025-05-20 06:41:41 +00:00
'name' => 'library' ,
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: create ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-05-20 06:41:41 +00:00
]);
$this -> assertEquals ( 201 , $library [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'fullName' ,
'size' => 255 ,
'required' => false ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $person [ 'body' ][ '$id' ], 'fullName' );
2025-05-20 06:41:41 +00:00
2026-01-09 14:21:31 +00:00
$relation = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/relationship' , array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => 'library-upsert' ,
2025-05-20 06:41:41 +00:00
'type' => Database :: RELATION_ONE_TO_ONE ,
'key' => 'library' ,
'twoWay' => true ,
'onDelete' => Database :: RELATION_MUTATE_CASCADE ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $person [ 'body' ][ '$id' ], 'library' );
2025-05-20 06:41:41 +00:00
2026-01-09 14:21:31 +00:00
$libraryName = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $library [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'libraryName' ,
'size' => 255 ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $library [ 'body' ][ '$id' ], 'libraryName' );
2025-05-20 06:41:41 +00:00
$this -> assertEquals ( 202 , $libraryName [ 'headers' ][ 'status-code' ]);
// upserting values
$documentId = ID :: unique ();
2026-01-09 14:21:31 +00:00
$person1 = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $documentId , array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'library' => [
'$id' => 'library1' ,
'$permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
'libraryName' => 'Library 1' ,
],
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
]
]);
$this -> assertEquals ( 'Library 1' , $person1 [ 'body' ][ 'library' ][ 'libraryName' ]);
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:35:37 +00:00
Query :: select ([ 'fullName' , 'library.*' ]) -> toString (),
2025-05-20 06:41:41 +00:00
Query :: equal ( 'library' , [ 'library1' ]) -> toString (),
],
]);
$this -> assertEquals ( 1 , $documents [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'Library 1' , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'library' ][ 'libraryName' ]);
2025-05-20 06:41:41 +00:00
2026-01-09 14:21:31 +00:00
$person1 = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $documentId , array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'library' => [
'$id' => 'library1' ,
'$permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
'libraryName' => 'Library 2' ,
],
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
]
]);
// data should get updated
$this -> assertEquals ( 'Library 2' , $person1 [ 'body' ][ 'library' ][ 'libraryName' ]);
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:40:59 +00:00
Query :: select ([ 'fullName' , 'library.*' ]) -> toString (),
2025-05-20 06:41:41 +00:00
Query :: equal ( 'library' , [ 'library1' ]) -> toString (),
],
]);
$this -> assertEquals ( 1 , $documents [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'Library 2' , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'library' ][ 'libraryName' ]);
2025-05-20 06:41:41 +00:00
// data should get added
2026-01-09 14:21:31 +00:00
$person1 = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . ID :: unique (), array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'library' => [
'$id' => 'library2' ,
'$permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
'libraryName' => 'Library 2' ,
],
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
]
]);
$this -> assertEquals ( 'Library 2' , $person1 [ 'body' ][ 'library' ][ 'libraryName' ]);
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2025-05-20 06:41:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:40:59 +00:00
Query :: select ([ 'fullName' , 'library.*' ]) -> toString ()
2025-05-20 06:41:41 +00:00
],
]);
$this -> assertEquals ( 2 , $documents [ 'body' ][ 'total' ]);
2025-07-09 18:27:39 +00:00
2025-07-27 05:09:50 +00:00
// test without passing permissions
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-27 05:09:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Ragnarok' ,
'releaseYear' => 2000
]
]);
2025-07-09 18:27:39 +00:00
2025-07-27 05:09:50 +00:00
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Thor: Ragnarok' , $document [ 'body' ][ 'title' ]);
2025-07-09 18:27:39 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-27 05:09:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2025-07-09 18:27:39 +00:00
2025-07-27 05:09:50 +00:00
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
2025-07-09 18:27:39 +00:00
2026-01-09 14:21:31 +00:00
$deleteResponse = $this -> client -> call ( Client :: METHOD_DELETE , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-27 05:09:50 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2025-07-09 18:27:39 +00:00
$this -> assertEquals ( 204 , $deleteResponse [ 'headers' ][ 'status-code' ]);
2025-07-22 08:40:58 +00:00
if ( $this -> getSide () === 'client' ) {
// Skipped on server side: Creating a document with no permissions results in an empty permissions array, whereas on client side it assigns permissions to the current user
// test without passing permissions
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Ragnarok' ,
'releaseYear' => 2000
]
]);
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Thor: Ragnarok' , $document [ 'body' ][ 'title' ]);
$this -> assertCount ( 3 , $document [ 'body' ][ '$permissions' ]);
$permissionsCreated = $document [ 'body' ][ '$permissions' ];
// checking the default created permission
$defaultPermission = [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ]))
];
// ignoring the order of the permission and checking the permissions
$this -> assertEqualsCanonicalizing ( $defaultPermission , $permissionsCreated );
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ]
], $this -> getHeaders ()));
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
// updating the created doc
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Ragnarok' ,
'releaseYear' => 2002
]
]);
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Thor: Ragnarok' , $document [ 'body' ][ 'title' ]);
$this -> assertEquals ( 2002 , $document [ 'body' ][ 'releaseYear' ]);
$this -> assertCount ( 3 , $document [ 'body' ][ '$permissions' ]);
$this -> assertEquals ( $permissionsCreated , $document [ 'body' ][ '$permissions' ]);
// removing the delete permission
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Ragnarok' ,
'releaseYear' => 2002
],
'permissions' => [
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ]))
]
]);
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Thor: Ragnarok' , $document [ 'body' ][ 'title' ]);
$this -> assertEquals ( 2002 , $document [ 'body' ][ 'releaseYear' ]);
$this -> assertCount ( 1 , $document [ 'body' ][ '$permissions' ]);
2026-01-09 14:21:31 +00:00
$deleteResponse = $this -> client -> call ( Client :: METHOD_DELETE , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ]
], $this -> getHeaders ()));
$this -> assertEquals ( 401 , $deleteResponse [ 'headers' ][ 'status-code' ]);
// giving the delete permission
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PUT , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Ragnarok' ,
'releaseYear' => 2002
],
'permissions' => [
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ]))
]
]);
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Thor: Ragnarok' , $document [ 'body' ][ 'title' ]);
$this -> assertEquals ( 2002 , $document [ 'body' ][ 'releaseYear' ]);
$this -> assertCount ( 2 , $document [ 'body' ][ '$permissions' ]);
2026-01-09 14:21:31 +00:00
$deleteResponse = $this -> client -> call ( Client :: METHOD_DELETE , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ], $documentId ), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ]
], $this -> getHeaders ()));
$this -> assertEquals ( 204 , $deleteResponse [ 'headers' ][ 'status-code' ]);
// upsertion for the related document without passing permissions
// data should get added
$newPersonId = ID :: unique ();
2026-01-09 14:21:31 +00:00
$personNoPerm = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $newPersonId , array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'library' => [
'$id' => 'library3' ,
'libraryName' => 'Library 3' ,
],
],
]);
$this -> assertEquals ( 'Library 3' , $personNoPerm [ 'body' ][ 'library' ][ 'libraryName' ]);
$this -> assertCount ( 3 , $personNoPerm [ 'body' ][ 'library' ][ '$permissions' ]);
$this -> assertCount ( 3 , $personNoPerm [ 'body' ][ '$permissions' ]);
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: select ([ 'fullName' , 'library.*' ]) -> toString ()
],
]);
$this -> assertGreaterThanOrEqual ( 1 , $documents [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$documentsDetails = $documents [ 'body' ][ $this -> getRecordResource ()];
2025-07-22 08:40:58 +00:00
foreach ( $documentsDetails as $doc ) {
$this -> assertCount ( 3 , $doc [ '$permissions' ]);
}
$found = false ;
2026-01-09 14:21:31 +00:00
foreach ( $documents [ 'body' ][ $this -> getRecordResource ()] as $doc ) {
2025-07-22 08:40:58 +00:00
if ( isset ( $doc [ 'library' ][ 'libraryName' ]) && $doc [ 'library' ][ 'libraryName' ] === 'Library 3' ) {
$found = true ;
break ;
}
}
$this -> assertTrue ( $found , 'Library 3 should be present in the upserted documents.' );
// Fetch the related library and assert on its permissions (should be default/inherited)
2026-01-09 14:21:31 +00:00
$library3 = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $library [ 'body' ][ '$id' ], 'library3' ), array_merge ([
2025-07-22 08:40:58 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 200 , $library3 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Library 3' , $library3 [ 'body' ][ 'libraryName' ]);
$this -> assertArrayHasKey ( '$permissions' , $library3 [ 'body' ]);
$this -> assertCount ( 3 , $library3 [ 'body' ][ '$permissions' ]);
$this -> assertNotEmpty ( $library3 [ 'body' ][ '$permissions' ]);
2025-08-29 07:30:59 +00:00
// Readonly attributes are ignored
2026-01-09 14:21:31 +00:00
$personNoPerm = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $newPersonId , array_merge ([
2025-08-29 07:30:59 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'$id' => 'some-other-id' ,
2026-01-09 14:21:31 +00:00
$this -> getContainerIdResponseKey () => 'some-other-container' ,
2025-08-29 07:30:59 +00:00
'$databaseId' => 'some-other-database' ,
'$createdAt' => '2024-01-01T00:00:00Z' ,
'$updatedAt' => '2024-01-01T00:00:00Z' ,
'library' => [
'$id' => 'library3' ,
'libraryName' => 'Library 3' ,
'$createdAt' => '2024-01-01T00:00:00Z' ,
'$updatedAt' => '2024-01-01T00:00:00Z' ,
],
],
]);
$update = $personNoPerm ;
$update [ 'body' ][ '$id' ] = 'random' ;
$update [ 'body' ][ '$sequence' ] = 123 ;
$update [ 'body' ][ '$databaseId' ] = 'random' ;
2026-01-09 14:21:31 +00:00
$update [ 'body' ][ $this -> getContainerIdResponseKey ()] = 'random' ;
2025-08-29 08:38:55 +00:00
$update [ 'body' ][ '$createdAt' ] = '2024-01-01T00:00:00.000+00:00' ;
$update [ 'body' ][ '$updatedAt' ] = '2024-01-01T00:00:00.000+00:00' ;
2025-08-29 07:30:59 +00:00
2026-01-09 14:21:31 +00:00
$upserted = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $newPersonId , array_merge ([
2025-08-29 07:30:59 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => $update [ 'body' ]
]);
$this -> assertEquals ( 200 , $upserted [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $personNoPerm [ 'body' ][ '$id' ], $upserted [ 'body' ][ '$id' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $personNoPerm [ 'body' ][ $this -> getContainerIdResponseKey ()], $upserted [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2025-08-29 07:30:59 +00:00
$this -> assertEquals ( $personNoPerm [ 'body' ][ '$databaseId' ], $upserted [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $personNoPerm [ 'body' ][ '$sequence' ], $upserted [ 'body' ][ '$sequence' ]);
2025-08-29 08:38:55 +00:00
if ( $this -> getSide () === 'client' ) {
$this -> assertEquals ( $personNoPerm [ 'body' ][ '$createdAt' ], $upserted [ 'body' ][ '$createdAt' ]);
$this -> assertNotEquals ( '2024-01-01T00:00:00.000+00:00' , $upserted [ 'body' ][ '$updatedAt' ]);
} else {
$this -> assertEquals ( '2024-01-01T00:00:00.000+00:00' , $upserted [ 'body' ][ '$createdAt' ]);
$this -> assertEquals ( '2024-01-01T00:00:00.000+00:00' , $upserted [ 'body' ][ '$updatedAt' ]);
}
2025-07-22 08:40:58 +00:00
}
2023-03-16 16:28:08 +00:00
}
2026-02-05 22:56:58 +00:00
public function testListDocuments () : array
2021-08-24 18:02:33 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2022-06-22 10:51:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-02-09 01:20:42 +00:00
$docIds = $data [ 'documentIds' ];
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-24 18:02:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderAsc ( 'releaseYear' ) -> toString (),
],
2021-08-24 18:02:33 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertEquals ( 2017 , $documents [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'releaseYear' ]);
$this -> assertEquals ( 2019 , $documents [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'releaseYear' ]);
$this -> assertTrue ( array_key_exists ( '$sequence' , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ]));
$this -> assertTrue ( array_key_exists ( '$sequence' , $documents [ 'body' ][ $this -> getRecordResource ()][ 1 ]));
$this -> assertTrue ( array_key_exists ( '$sequence' , $documents [ 'body' ][ $this -> getRecordResource ()][ 2 ]));
$this -> assertCount ( 3 , $documents [ 'body' ][ $this -> getRecordResource ()]);
foreach ( $documents [ 'body' ][ $this -> getRecordResource ()] as $document ) {
$this -> assertEquals ( $data [ 'moviesId' ], $document [ $this -> getContainerIdResponseKey ()]);
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $document );
$this -> assertEquals ( $databaseId , $document [ '$databaseId' ]);
}
2022-06-22 10:51:49 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-24 18:02:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderDesc ( 'releaseYear' ) -> toString (),
],
2021-08-24 18:02:33 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $documents [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'releaseYear' ]);
$this -> assertEquals ( 2017 , $documents [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'releaseYear' ]);
$this -> assertEquals ( 2019 , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertCount ( 3 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2025-04-17 09:29:37 +00:00
// changing description attribute to be null by default instead of empty string
2026-01-09 14:21:31 +00:00
$patchNull = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $data [ 'moviesId' ], 'string' , 'description' ), array_merge ([
2025-04-17 09:14:59 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'default' => null ,
'required' => false ,
]);
2025-04-17 09:29:37 +00:00
// creating a dummy doc with null description
2026-01-09 14:21:31 +00:00
$document1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2025-04-17 09:14:59 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-04-17 09:14:59 +00:00
'data' => [
'title' => 'Dummy' ,
'releaseYear' => 1944 ,
'birthDay' => '1975-06-12 14:12:55+02:00' ,
'actors' => [
'Dummy' ,
],
]
]);
$this -> assertEquals ( 201 , $document1 [ 'headers' ][ 'status-code' ]);
2025-04-17 09:29:37 +00:00
// fetching docs with cursor after the dummy doc with order attr description which is null
2026-01-09 14:21:31 +00:00
$documentsPaginated = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2025-04-17 09:14:59 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: orderAsc ( 'dummy' ) -> toString (),
Query :: cursorAfter ( new Document ([ '$id' => $document1 [ 'body' ][ '$id' ]])) -> toString ()
],
]);
2025-04-17 09:29:37 +00:00
// should throw 400 as the order attr description of the selected doc is null
2025-04-17 09:14:59 +00:00
$this -> assertEquals ( 400 , $documentsPaginated [ 'headers' ][ 'status-code' ]);
2025-04-17 09:29:37 +00:00
// deleting the dummy doc created
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $document1 [ 'body' ][ '$id' ], array_merge ([
2025-04-17 09:14:59 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2026-02-09 00:25:19 +00:00
return $data ;
2023-03-24 05:56:49 +00:00
}
2026-02-05 22:56:58 +00:00
public function testGetDocument () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> getDocumentsList ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
foreach ( $data [ $this -> getRecordResource ()] as $document ) {
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $document [ $this -> getContainerIdResponseKey ()], $document [ '$id' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $response [ 'body' ][ '$id' ], $document [ '$id' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $document [ $this -> getContainerIdResponseKey ()], $response [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $response [ 'body' ]);
$this -> assertEquals ( $document [ '$databaseId' ], $response [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $response [ 'body' ][ 'title' ], $document [ 'title' ]);
$this -> assertEquals ( $response [ 'body' ][ 'releaseYear' ], $document [ 'releaseYear' ]);
$this -> assertEquals ( $response [ 'body' ][ '$permissions' ], $document [ '$permissions' ]);
$this -> assertEquals ( $response [ 'body' ][ 'birthDay' ], $document [ 'birthDay' ]);
2025-05-23 10:45:47 +00:00
$this -> assertTrue ( array_key_exists ( '$sequence' , $response [ 'body' ]));
2024-09-05 02:28:15 +00:00
$this -> assertFalse ( array_key_exists ( '$tenant' , $response [ 'body' ]));
2023-03-24 05:56:49 +00:00
}
}
2026-02-05 22:56:58 +00:00
public function testGetDocumentWithQueries () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> getDocumentsList ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$document = $data [ $this -> getRecordResource ()][ 0 ];
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $document [ $this -> getContainerIdResponseKey ()], $document [ '$id' ]), array_merge ([
2021-08-24 18:02:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:40:59 +00:00
Query :: select ([ 'title' , 'releaseYear' , '$id' ]) -> toString (),
2023-03-24 05:56:49 +00:00
],
2021-08-24 18:02:33 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $document [ 'title' ], $response [ 'body' ][ 'title' ]);
$this -> assertEquals ( $document [ 'releaseYear' ], $response [ 'body' ][ 'releaseYear' ]);
$this -> assertArrayNotHasKey ( 'birthDay' , $response [ 'body' ]);
2025-05-23 10:51:20 +00:00
$sequence = $response [ 'body' ][ '$sequence' ];
2025-05-01 13:25:04 +00:00
2025-05-23 10:51:20 +00:00
// Query by sequence
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $document [ $this -> getContainerIdResponseKey ()], $document [ '$id' ]), array_merge ([
2025-05-01 13:25:04 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
2025-05-23 10:51:20 +00:00
Query :: equal ( '$sequence' , [ $sequence ])
2025-05-01 13:25:04 +00:00
],
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $document [ 'title' ], $response [ 'body' ][ 'title' ]);
$this -> assertEquals ( $document [ 'releaseYear' ], $response [ 'body' ][ 'releaseYear' ]);
2025-05-23 10:51:20 +00:00
$this -> assertTrue ( array_key_exists ( '$sequence' , $response [ 'body' ]));
2023-03-24 05:56:49 +00:00
}
2026-02-05 22:56:58 +00:00
public function testListDocumentsAfterPagination () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-02-09 01:20:42 +00:00
$docIds = $data [ 'documentIds' ];
2023-03-24 05:56:49 +00:00
/**
* Test after without order .
*/
2026-01-09 14:21:31 +00:00
$base = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-24 18:02:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2026-02-09 01:20:42 +00:00
], $this -> getHeaders ()), [
'queries' => [
Query :: equal ( '$id' , $docIds ) -> toString (),
],
]);
2021-08-24 18:02:33 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $base [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'Captain America' , $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'title' ]);
$this -> assertEquals ( 'Spider-Man: Far From Home' , $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'title' ]);
$this -> assertEquals ( 'Spider-Man: Homecoming' , $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'title' ]);
$this -> assertCount ( 3 , $base [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-24 18:02:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2026-01-09 14:21:31 +00:00
Query :: cursorAfter ( new Document ([ '$id' => $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]])) -> toString ()
2023-12-20 10:55:09 +00:00
],
2021-08-24 18:02:33 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
$this -> assertEquals ( $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 1 ][ '$id' ]);
$this -> assertCount ( 2 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-24 18:02:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2026-01-09 14:21:31 +00:00
Query :: cursorAfter ( new Document ([ '$id' => $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ '$id' ]])) -> toString ()
2023-12-20 10:55:09 +00:00
],
2021-08-24 18:02:33 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEmpty ( $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
/**
* Test with ASC order and after .
*/
2026-01-09 14:21:31 +00:00
$base = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2022-07-28 10:26:22 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderAsc ( 'releaseYear' ) -> toString ()
],
2022-07-28 10:26:22 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $base [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertEquals ( 2017 , $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'releaseYear' ]);
$this -> assertEquals ( 2019 , $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'releaseYear' ]);
$this -> assertCount ( 3 , $base [ 'body' ][ $this -> getRecordResource ()]);
2021-08-24 18:02:33 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2026-01-09 14:21:31 +00:00
Query :: cursorAfter ( new Document ([ '$id' => $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ '$id' ]])) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderAsc ( 'releaseYear' ) -> toString ()
],
2023-03-24 05:56:49 +00:00
]);
2021-08-24 18:02:33 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
$this -> assertCount ( 1 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2021-09-10 20:14:31 +00:00
2023-03-24 05:56:49 +00:00
/**
* Test with DESC order and after .
*/
2026-01-09 14:21:31 +00:00
$base = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderDesc ( 'releaseYear' ) -> toString ()
],
2023-03-24 05:56:49 +00:00
]);
2021-08-24 18:02:33 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $base [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'releaseYear' ]);
$this -> assertEquals ( 2017 , $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'releaseYear' ]);
$this -> assertEquals ( 2019 , $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertCount ( 3 , $base [ 'body' ][ $this -> getRecordResource ()]);
2021-08-24 18:02:33 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2026-01-09 14:21:31 +00:00
Query :: cursorAfter ( new Document ([ '$id' => $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ '$id' ]])) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderDesc ( 'releaseYear' ) -> toString ()
],
2023-03-24 05:56:49 +00:00
]);
2021-08-24 18:02:33 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
$this -> assertCount ( 1 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2021-08-24 18:02:33 +00:00
2023-03-24 05:56:49 +00:00
/**
* Test after with unknown document .
*/
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: cursorAfter ( new Document ([ '$id' => 'unknown' ])) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-24 18:02:33 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 400 , $documents [ 'headers' ][ 'status-code' ]);
2022-07-28 10:26:22 +00:00
2024-05-09 16:54:28 +00:00
/**
* Test null value for cursor
*/
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2024-05-09 16:54:28 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
'{"method":"cursorAfter","values":[null]}' ,
],
]);
$this -> assertEquals ( 400 , $documents [ 'headers' ][ 'status-code' ]);
2023-03-24 05:56:49 +00:00
}
2021-08-24 18:02:33 +00:00
2026-02-05 22:56:58 +00:00
public function testListDocumentsBeforePagination () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-02-09 01:20:42 +00:00
$docIds = $data [ 'documentIds' ];
2023-03-24 05:56:49 +00:00
/**
* Test before without order .
*/
2026-01-09 14:21:31 +00:00
$base = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-25 19:37:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2026-02-09 01:20:42 +00:00
], $this -> getHeaders ()), [
'queries' => [
Query :: equal ( '$id' , $docIds ) -> toString (),
],
]);
2021-08-25 19:37:21 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $base [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'Captain America' , $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'title' ]);
$this -> assertEquals ( 'Spider-Man: Far From Home' , $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'title' ]);
$this -> assertEquals ( 'Spider-Man: Homecoming' , $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'title' ]);
$this -> assertCount ( 3 , $base [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-25 19:37:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2026-01-09 14:21:31 +00:00
Query :: cursorBefore ( new Document ([ '$id' => $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ '$id' ]])) -> toString (),
2023-12-20 10:55:09 +00:00
],
2023-03-24 05:56:49 +00:00
]);
2021-08-25 19:37:21 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
$this -> assertEquals ( $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 1 ][ '$id' ]);
$this -> assertCount ( 2 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-09-10 20:14:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2026-01-09 14:21:31 +00:00
Query :: cursorBefore ( new Document ([ '$id' => $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]])) -> toString (),
2023-12-20 10:55:09 +00:00
],
2023-03-24 05:56:49 +00:00
]);
2021-09-10 20:14:31 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEmpty ( $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
/**
2026-02-09 01:20:42 +00:00
* Test with ASC order and before .
2023-03-24 05:56:49 +00:00
*/
2026-01-09 14:21:31 +00:00
$base = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-25 19:37:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderAsc ( 'releaseYear' ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-25 19:37:21 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $base [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertEquals ( 2017 , $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'releaseYear' ]);
$this -> assertEquals ( 2019 , $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'releaseYear' ]);
$this -> assertCount ( 3 , $base [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-25 19:37:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2026-01-09 14:21:31 +00:00
Query :: cursorBefore ( new Document ([ '$id' => $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ '$id' ]])) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderAsc ( 'releaseYear' ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-25 19:37:21 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
$this -> assertCount ( 1 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
/**
2026-02-09 01:20:42 +00:00
* Test with DESC order and before .
2023-03-24 05:56:49 +00:00
*/
2026-01-09 14:21:31 +00:00
$base = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-25 19:37:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderDesc ( 'releaseYear' ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-25 19:37:21 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $base [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $base [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'releaseYear' ]);
$this -> assertEquals ( 2017 , $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'releaseYear' ]);
$this -> assertEquals ( 2019 , $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertCount ( 3 , $base [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-25 19:37:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2026-01-09 14:21:31 +00:00
Query :: cursorBefore ( new Document ([ '$id' => $base [ 'body' ][ $this -> getRecordResource ()][ 1 ][ '$id' ]])) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderDesc ( 'releaseYear' ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-25 19:37:21 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $base [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
$this -> assertCount ( 1 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
}
2026-02-05 22:56:58 +00:00
public function testListDocumentsLimitAndOffset () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-02-09 01:20:42 +00:00
$docIds = $data [ 'documentIds' ];
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-25 19:37:21 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderAsc ( 'releaseYear' ) -> toString (),
Query :: limit ( 1 ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-25 19:37:21 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertCount ( 1 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2022-07-28 10:26:22 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-02-09 01:20:42 +00:00
Query :: equal ( '$id' , $docIds ) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: orderAsc ( 'releaseYear' ) -> toString (),
Query :: limit ( 2 ) -> toString (),
Query :: offset ( 1 ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-25 19:37:21 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 2017 , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertEquals ( 2019 , $documents [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'releaseYear' ]);
$this -> assertCount ( 2 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
}
2022-07-28 10:26:22 +00:00
2026-02-05 22:56:58 +00:00
public function testDocumentsListQueries () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-24 18:02:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: search ( 'title' , 'Captain America' ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-27 20:30:26 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 1 , count ( $documents [ 'body' ][ $this -> getRecordResource ()]));
2022-07-28 10:26:22 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-27 20:30:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2026-01-09 14:21:31 +00:00
Query :: equal ( '$id' , [ $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]]) -> toString (),
2023-12-20 10:55:09 +00:00
],
2023-03-24 05:56:49 +00:00
]);
2021-09-10 20:14:31 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1944 , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
$this -> assertCount ( 1 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2021-09-10 20:14:31 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: search ( 'title' , 'Homecoming' ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-09-10 20:14:31 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 2017 , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'releaseYear' ]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 1 , count ( $documents [ 'body' ][ $this -> getRecordResource ()]));
2021-09-10 20:14:31 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: search ( 'title' , 'spider' ) -> toString (),
],
2023-03-24 05:56:49 +00:00
]);
2021-08-24 18:02:33 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 2 , count ( $documents [ 'body' ][ $this -> getRecordResource ()]));
$releaseYears = array_column ( $documents [ 'body' ][ $this -> getRecordResource ()], 'releaseYear' );
$this -> assertContains ( 2019 , $releaseYears );
$this -> assertContains ( 2017 , $releaseYears );
2022-07-28 15:24:17 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2024-02-08 16:10:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
'{"method":"contains","attribute":"title","values":[bad]}'
],
]);
$this -> assertEquals ( 400 , $documents [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Invalid query: Syntax error' , $documents [ 'body' ][ 'message' ]);
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2024-01-21 16:22:02 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: contains ( 'title' , [ 'spi' ]) -> toString (), // like query
],
]);
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 2 , $documents [ 'body' ][ 'total' ]);
2024-01-21 16:22:02 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-10-07 18:30:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: equal ( 'releaseYear' , [ 1944 ]) -> toString (),
],
2021-10-07 18:30:52 +00:00
]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 1 , count ( $documents [ 'body' ][ $this -> getRecordResource ()]));
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'Captain America' , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'title' ]);
2021-08-24 18:02:33 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-06-14 19:54:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: notEqual ( 'releaseYear' , 1944 ) -> toString (),
],
2021-06-14 19:54:49 +00:00
]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 2 , count ( $documents [ 'body' ][ $this -> getRecordResource ()]));
2021-08-22 16:36:26 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-11-03 15:02:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: greaterThan ( '$createdAt' , '1976-06-12' ) -> toString (),
],
2021-11-03 15:02:41 +00:00
]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 3 , count ( $documents [ 'body' ][ $this -> getRecordResource ()]));
2021-08-22 16:36:26 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2022-06-28 10:53:16 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: lessThan ( '$createdAt' , '1976-06-12' ) -> toString (),
],
2022-06-28 10:53:16 +00:00
]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 0 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2021-08-22 16:36:26 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2021-08-22 16:36:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
2024-01-21 16:22:02 +00:00
Query :: contains ( 'actors' , [ 'Tom Holland' , 'Samuel Jackson' ]) -> toString (),
],
]);
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 3 , $documents [ 'body' ][ 'total' ]);
2024-01-21 16:22:02 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2024-01-21 16:22:02 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: contains ( 'actors' , [ 'Tom' ]) -> toString (), // Full-match not like
2023-12-20 10:55:09 +00:00
],
2023-03-24 05:56:49 +00:00
]);
2024-01-21 16:22:02 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2024-01-21 16:22:02 +00:00
$this -> assertEquals ( 0 , $documents [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2024-01-21 16:22:02 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: greaterThan ( 'birthDay' , '16/01/2024 12:00:00AM' ) -> toString (),
],
]);
$this -> assertEquals ( 400 , $documents [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Invalid query: Query value is invalid for attribute "birthDay"' , $documents [ 'body' ][ 'message' ]);
2021-08-22 16:36:26 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-30 06:57:56 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: greaterThan ( 'birthDay' , '1960-01-01 10:10:10+02:30' ) -> toString (),
],
2023-03-30 06:57:56 +00:00
]);
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 2 , count ( $documents [ 'body' ][ $this -> getRecordResource ()]));
$birthDays = array_column ( $documents [ 'body' ][ $this -> getRecordResource ()], 'birthDay' );
$this -> assertContains ( '1975-06-12T12:12:55.000+00:00' , $birthDays );
$this -> assertContains ( '1975-06-12T18:12:55.000+00:00' , $birthDays );
2023-03-30 06:57:56 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2024-01-21 16:22:02 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: isNull ( 'integers' ) -> toString (),
],
]);
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 1 , $documents [ 'body' ][ 'total' ]);
2024-01-21 16:22:02 +00:00
2023-03-24 05:56:49 +00:00
/**
* Test for Failure
*/
$conditions = [];
2021-06-18 17:18:27 +00:00
2024-10-16 08:35:32 +00:00
for ( $i = 0 ; $i < APP_DATABASE_QUERY_MAX_VALUES + 1 ; $i ++ ) {
2023-03-24 05:56:49 +00:00
$conditions [] = $i ;
}
2022-07-31 10:07:15 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2022-07-31 10:07:15 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: equal ( 'releaseYear' , $conditions ) -> toString (),
],
2022-07-31 10:07:15 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 400 , $documents [ 'headers' ][ 'status-code' ]);
2024-10-16 08:35:32 +00:00
$this -> assertEquals ( 'Invalid query: Query on attribute has greater than ' . APP_DATABASE_QUERY_MAX_VALUES . ' values: releaseYear' , $documents [ 'body' ][ 'message' ]);
2022-07-31 10:07:15 +00:00
2023-12-20 10:55:09 +00:00
$value = '' ;
2021-06-14 19:54:49 +00:00
2023-03-24 05:56:49 +00:00
for ( $i = 0 ; $i < 101 ; $i ++ ) {
2023-12-20 10:55:09 +00:00
$value .= " [ " . $i . " ] Too long title to cross 2k chars query limit " ;
2023-03-24 05:56:49 +00:00
}
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: search ( 'title' , $value ) -> toString (),
],
2020-01-13 08:46:09 +00:00
]);
2024-01-21 16:22:02 +00:00
// Todo: Not sure what to do we with Query length Test VS old? JSON validator will fails if query string will be truncated?
2023-12-20 10:55:09 +00:00
//$this->assertEquals(400, $documents['headers']['status-code']);
2023-03-24 05:56:49 +00:00
2024-05-08 06:08:23 +00:00
// Todo: Disabled for CL - Uncomment after ProxyDatabase cleanup for find method
2026-01-09 14:21:31 +00:00
// $documents = $this->client->call(Client::METHOD_GET, $this->getRecordUrl($databaseId, $data['moviesId']), array_merge([
2024-05-08 06:08:23 +00:00
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $this->getProject()['$id'],
// ], $this->getHeaders()), [
// 'queries' => [
// Query::search('actors', 'Tom')->toString(),
// ],
// ]);
// $this->assertEquals(400, $documents['headers']['status-code']);
// $this->assertEquals('Invalid query: Cannot query search on attribute "actors" because it is an array.', $documents['body']['message']);
2023-03-24 05:56:49 +00:00
}
2026-02-05 22:56:58 +00:00
public function testUpdateDocument () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2020-01-13 08:46:09 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'title' => 'Thor: Ragnaroc' ,
2020-01-13 08:46:09 +00:00
'releaseYear' => 2017 ,
2023-03-24 05:56:49 +00:00
'birthDay' => '1976-06-12 14:12:55' ,
'actors' => [],
2020-01-13 17:53:22 +00:00
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2022-08-15 11:24:31 +00:00
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
2020-01-13 17:53:22 +00:00
],
2020-01-13 08:46:09 +00:00
]);
2023-03-24 05:56:49 +00:00
$id = $document [ 'body' ][ '$id' ];
2020-01-13 08:46:09 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $data [ 'moviesId' ], $document [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $document [ 'body' ]);
$this -> assertEquals ( $databaseId , $document [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Thor: Ragnaroc' );
$this -> assertEquals ( $document [ 'body' ][ 'releaseYear' ], 2017 );
$dateValidator = new DatetimeValidator ();
$this -> assertEquals ( true , $dateValidator -> isValid ( $document [ 'body' ][ '$createdAt' ]));
$this -> assertEquals ( true , $dateValidator -> isValid ( $document [ 'body' ][ 'birthDay' ]));
$this -> assertContains ( Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])), $document [ 'body' ][ '$permissions' ]);
2020-01-13 08:46:09 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()), [
2023-03-24 05:56:49 +00:00
'data' => [
'title' => 'Thor: Ragnarok' ,
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
2020-01-13 08:46:09 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $document [ 'body' ][ '$id' ], $id );
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $data [ 'moviesId' ], $document [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $document [ 'body' ]);
$this -> assertEquals ( $databaseId , $document [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Thor: Ragnarok' );
$this -> assertEquals ( $document [ 'body' ][ 'releaseYear' ], 2017 );
$this -> assertContains ( Permission :: read ( Role :: users ()), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: update ( Role :: users ()), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: delete ( Role :: users ()), $document [ 'body' ][ '$permissions' ]);
2021-12-27 10:45:24 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()));
2020-01-13 08:46:09 +00:00
2023-03-24 05:56:49 +00:00
$id = $document [ 'body' ][ '$id' ];
2020-01-13 08:46:09 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $data [ 'moviesId' ], $document [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $document [ 'body' ]);
$this -> assertEquals ( $databaseId , $document [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Thor: Ragnarok' );
$this -> assertEquals ( $document [ 'body' ][ 'releaseYear' ], 2017 );
2021-12-27 10:45:24 +00:00
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2022-07-05 23:13:48 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-timestamp' => DateTime :: formatTz ( DateTime :: now ()),
], $this -> getHeaders ()), [
'data' => [
'title' => 'Thor: Ragnarok' ,
],
2022-07-05 23:13:48 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2022-07-05 23:13:48 +00:00
2025-08-29 07:30:59 +00:00
// Test readonly attributes are ignored
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2025-08-29 07:30:59 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-timestamp' => DateTime :: formatTz ( DateTime :: now ()),
], $this -> getHeaders ()), [
'data' => [
'$id' => 'newId' ,
'$sequence' => 9999 ,
2026-01-09 14:21:31 +00:00
$this -> getContainerIdResponseKey () => 'newContainerId' ,
2025-08-29 07:30:59 +00:00
'$databaseId' => 'newDatabaseId' ,
2025-08-29 08:38:55 +00:00
'$createdAt' => '2024-01-01T00:00:00.000+00:00' ,
'$updatedAt' => '2024-01-01T00:00:00.000+00:00' ,
2025-08-29 07:30:59 +00:00
'title' => 'Thor: Ragnarok' ,
],
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $id , $response [ 'body' ][ '$id' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $data [ 'moviesId' ], $response [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2025-08-29 07:30:59 +00:00
$this -> assertEquals ( $databaseId , $response [ 'body' ][ '$databaseId' ]);
$this -> assertNotEquals ( 9999 , $response [ 'body' ][ '$sequence' ]);
2025-08-29 08:38:55 +00:00
if ( $this -> getSide () === 'client' ) {
$this -> assertNotEquals ( '2024-01-01T00:00:00.000+00:00' , $response [ 'body' ][ '$createdAt' ]);
$this -> assertNotEquals ( '2024-01-01T00:00:00.000+00:00' , $response [ 'body' ][ '$updatedAt' ]);
} else {
$this -> assertEquals ( '2024-01-01T00:00:00.000+00:00' , $response [ 'body' ][ '$createdAt' ]);
$this -> assertEquals ( '2024-01-01T00:00:00.000+00:00' , $response [ 'body' ][ '$updatedAt' ]);
}
2022-07-05 23:13:48 +00:00
}
2025-10-30 22:47:20 +00:00
public function testOperators () : void
{
// Create database
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Test Database for Operators'
]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-10-30 22:47:20 +00:00
'name' => 'Operator Tests' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-10-30 22:47:20 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create attributes
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'releaseYear' ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'duration' ,
'required' => false ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'actors' ,
'size' => 256 ,
'required' => false ,
'array' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'integers' ,
'required' => false ,
'array' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'tagline' ,
'size' => 512 ,
'required' => false ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/datetime' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'birthDay' ,
'required' => false ,
]);
// Wait for attributes to be created
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-10-30 22:47:20 +00:00
// Create a document to test operators
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-10-30 22:47:20 +00:00
'data' => [
'title' => 'Operator Test' ,
'releaseYear' => 2020 ,
'duration' => 120 ,
'actors' => [ 'Actor1' , 'Actor2' ],
'integers' => [ 10 , 20 ],
'tagline' => 'Original' ,
'birthDay' => '2020-01-01 12:00:00' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $document [ 'headers' ][ 'status-code' ]);
$documentId = $document [ 'body' ][ '$id' ];
// Test increment operator on integer
2026-01-09 14:21:31 +00:00
$updated = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'releaseYear' => Operator :: increment ( 5 ) -> toString (),
'duration' => Operator :: increment ( 10 ) -> toString (),
],
]);
$this -> assertEquals ( 200 , $updated [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2025 , $updated [ 'body' ][ 'releaseYear' ]);
$this -> assertEquals ( 130 , $updated [ 'body' ][ 'duration' ]);
// Test decrement operator
2026-01-09 14:21:31 +00:00
$updated = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'releaseYear' => Operator :: decrement ( 3 ) -> toString (),
],
]);
$this -> assertEquals ( 200 , $updated [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2022 , $updated [ 'body' ][ 'releaseYear' ]);
// Test array append operator
2026-01-09 14:21:31 +00:00
$updated = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'actors' => Operator :: arrayAppend ([ 'Actor3' ]) -> toString (),
],
]);
$this -> assertEquals ( 200 , $updated [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 'Actor1' , 'Actor2' , 'Actor3' ], $updated [ 'body' ][ 'actors' ]);
// Test array prepend operator
2026-01-09 14:21:31 +00:00
$updated = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'actors' => Operator :: arrayPrepend ([ 'Actor0' ]) -> toString (),
],
]);
$this -> assertEquals ( 200 , $updated [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 'Actor0' , 'Actor1' , 'Actor2' , 'Actor3' ], $updated [ 'body' ][ 'actors' ]);
// Test string concat operator
2026-01-09 14:21:31 +00:00
$updated = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'tagline' => Operator :: stringConcat ( ' Appended' ) -> toString (),
],
]);
$this -> assertEquals ( 200 , $updated [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Original Appended' , $updated [ 'body' ][ 'tagline' ]);
// Test multiple operators in a single update
2026-01-09 14:21:31 +00:00
$updated = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'releaseYear' => Operator :: increment ( 1 ) -> toString (),
'integers' => Operator :: arrayAppend ([ 30 ]) -> toString (),
],
]);
$this -> assertEquals ( 200 , $updated [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2023 , $updated [ 'body' ][ 'releaseYear' ]);
$this -> assertEquals ([ 10 , 20 , 30 ], $updated [ 'body' ][ 'integers' ]);
// Test upsert with operators
$upsertId = ID :: unique ();
2026-01-09 14:21:31 +00:00
$upserted = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $upsertId , array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Upsert Test' ,
'releaseYear' => 2020 ,
'actors' => [],
'birthDay' => '2020-01-01 12:00:00' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 200 , $upserted [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$upserted = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $upsertId , array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Upsert Test Updated' ,
'releaseYear' => Operator :: increment ( 5 ) -> toString (),
'actors' => [],
'birthDay' => '2020-01-01 12:00:00' ,
],
]);
$this -> assertEquals ( 200 , $upserted [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2025 , $upserted [ 'body' ][ 'releaseYear' ]);
}
public function testBulkOperators () : void
{
// Create database
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Test Database for Bulk Operators'
]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-10-30 22:47:20 +00:00
'name' => 'Bulk Operator Tests' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-10-30 22:47:20 +00:00
'permissions' => [
Permission :: create ( Role :: users ()),
],
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create attributes
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'releaseYear' ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'actors' ,
'size' => 256 ,
'required' => false ,
'array' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/datetime' , [
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'key' => 'birthDay' ,
'required' => false ,
]);
// Wait for attributes to be created
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-10-30 22:47:20 +00:00
// Create multiple documents
2026-01-09 14:21:31 +00:00
$document1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-10-30 22:47:20 +00:00
'data' => [
'title' => 'Bulk Test 1' ,
'releaseYear' => 2020 ,
'actors' => [ 'Actor1' ],
'birthDay' => '2020-01-01 12:00:00' ,
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
]);
2026-01-09 14:21:31 +00:00
$document2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-10-30 22:47:20 +00:00
'data' => [
'title' => 'Bulk Test 2' ,
'releaseYear' => 2021 ,
'actors' => [ 'Actor2' ],
'birthDay' => '2020-01-01 12:00:00' ,
],
'permissions' => [
Permission :: read ( Role :: users ()),
Permission :: update ( Role :: users ()),
Permission :: delete ( Role :: users ()),
],
]);
$this -> assertEquals ( 201 , $document1 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $document2 [ 'headers' ][ 'status-code' ]);
// Test bulk update with operators
2026-01-09 14:21:31 +00:00
$bulkUpdate = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'data' => [
'releaseYear' => Operator :: increment ( 10 ) -> toString (),
],
'queries' => [
Query :: startsWith ( 'title' , 'Bulk Test' ) -> toString (),
],
]);
$this -> assertEquals ( 200 , $bulkUpdate [ 'headers' ][ 'status-code' ]);
$this -> assertGreaterThanOrEqual ( 2 , $bulkUpdate [ 'body' ][ 'total' ]);
// Verify the updates
2026-01-09 14:21:31 +00:00
$verify1 = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $document1 [ 'body' ][ '$id' ], array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 200 , $verify1 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2030 , $verify1 [ 'body' ][ 'releaseYear' ]);
2026-01-09 14:21:31 +00:00
$verify2 = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $document2 [ 'body' ][ '$id' ], array_merge ([
2025-10-30 22:47:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 200 , $verify2 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2031 , $verify2 [ 'body' ][ 'releaseYear' ]);
}
2026-02-05 22:56:58 +00:00
public function testDeleteDocument () : void
2023-03-22 21:10:47 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2023-03-22 21:10:47 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2023-03-23 14:08:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'title' => 'Thor: Ragnarok' ,
'releaseYear' => 2017 ,
'birthDay' => '1975-06-12 14:12:55' ,
'actors' => [],
2023-03-23 14:08:38 +00:00
],
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
2023-03-23 14:08:38 +00:00
]);
2023-03-22 21:10:47 +00:00
2023-03-24 05:56:49 +00:00
$id = $document [ 'body' ][ '$id' ];
2020-01-13 08:46:09 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2021-08-05 19:01:00 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
2021-08-05 19:01:00 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2021-08-05 19:01:00 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()));
$this -> assertEquals ( 204 , $document [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 404 , $document [ 'headers' ][ 'status-code' ]);
}
2025-06-12 14:28:28 +00:00
public function testInvalidDocumentStructure () : void
2023-03-24 05:56:49 +00:00
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'databaseId' => ID :: unique (),
'name' => 'InvalidDocumentDatabase' ,
]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'InvalidDocumentDatabase' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'invalidDocumentStructure' ,
'permissions' => [
Permission :: create ( Role :: any ()),
Permission :: read ( Role :: any ()),
],
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2021-08-05 19:01:00 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'invalidDocumentStructure' , $collection [ 'body' ][ 'name' ]);
$collectionId = $collection [ 'body' ][ '$id' ];
2021-08-05 19:01:00 +00:00
2026-01-09 14:21:31 +00:00
$email = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/email' , array_merge ([
2021-08-05 19:01:00 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'email' ,
'required' => false ,
2021-08-05 19:01:00 +00:00
]);
2026-01-09 14:21:31 +00:00
$enum = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/enum' , array_merge ([
2021-08-05 19:01:00 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'enum' ,
'elements' => [ 'yes' , 'no' , 'maybe' ],
'required' => false ,
2021-08-05 19:01:00 +00:00
]);
2026-01-09 14:21:31 +00:00
$ip = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/ip' , array_merge ([
2021-08-05 19:01:00 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'ip' ,
'required' => false ,
2021-08-05 19:01:00 +00:00
]);
2026-01-09 14:21:31 +00:00
$url = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/url' , array_merge ([
2021-08-05 19:01:00 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'url' ,
'size' => 256 ,
'required' => false ,
2021-08-05 19:01:00 +00:00
]);
2026-01-09 14:21:31 +00:00
$range = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2021-08-05 19:01:00 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'range' ,
'required' => false ,
'min' => 1 ,
'max' => 10 ,
2021-08-05 19:01:00 +00:00
]);
2023-03-24 05:56:49 +00:00
// TODO@kodumbeats min and max are rounded in error message
2026-01-09 14:21:31 +00:00
$floatRange = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/float' , array_merge ([
2021-08-05 19:01:00 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'floatRange' ,
'required' => false ,
'min' => 1.1 ,
'max' => 1.4 ,
2021-08-05 19:01:00 +00:00
]);
2026-01-09 14:21:31 +00:00
$probability = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/float' , array_merge ([
2021-10-05 10:30:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'probability' ,
'required' => false ,
'default' => 0 ,
'min' => 0 ,
'max' => 1 ,
]);
2021-10-05 10:30:33 +00:00
2026-01-09 14:21:31 +00:00
$upperBound = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2021-10-05 10:30:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'upperBound' ,
'required' => false ,
'max' => 10 ,
2021-10-05 10:30:33 +00:00
]);
2026-01-09 14:21:31 +00:00
$lowerBound = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2021-10-05 10:30:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'lowerBound' ,
'required' => false ,
'min' => 5 ,
2021-10-05 10:30:33 +00:00
]);
/**
2023-03-24 05:56:49 +00:00
* Test for failure
2021-10-05 10:30:33 +00:00
*/
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$invalidRange = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' , 'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'invalidRange' ,
'required' => false ,
'min' => 4 ,
'max' => 3 ,
2021-10-05 10:30:33 +00:00
]);
2026-01-09 14:21:31 +00:00
$defaultArray = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' , 'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'defaultArray' ,
'required' => false ,
'default' => 42 ,
'array' => true ,
]);
2021-10-05 10:30:33 +00:00
2026-01-09 14:21:31 +00:00
$defaultRequired = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2021-10-05 10:30:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'attributeId' => ID :: custom ( 'defaultRequired' ),
'required' => true ,
'default' => 12
2021-10-05 10:30:33 +00:00
]);
2026-01-09 14:21:31 +00:00
$enumDefault = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/enum' , array_merge ([
2021-10-05 10:30:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'attributeId' => ID :: custom ( 'enumDefault' ),
'elements' => [ 'north' , 'west' ],
'default' => 'south'
2021-10-05 10:30:33 +00:00
]);
2026-01-09 14:21:31 +00:00
$enumDefaultStrict = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/enum' , array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'attributeId' => ID :: custom ( 'enumDefault' ),
'elements' => [ 'north' , 'west' ],
'default' => 'NORTH'
]);
2021-10-05 10:30:33 +00:00
2026-01-09 14:21:31 +00:00
$goodDatetime = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/datetime' , array_merge ([
2021-10-05 10:30:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'birthDay' ,
'required' => false ,
'default' => null
2021-10-05 10:30:33 +00:00
]);
2026-01-09 14:21:31 +00:00
$datetimeDefault = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/datetime' , array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'badBirthDay' ,
'required' => false ,
'default' => 'bad'
]);
2021-10-05 10:30:33 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $email [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $ip [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $url [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $range [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $floatRange [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $probability [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $upperBound [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $lowerBound [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $enum [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $goodDatetime [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $invalidRange [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $defaultArray [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $defaultRequired [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $enumDefault [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $enumDefaultStrict [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Minimum value must be lesser than maximum value' , $invalidRange [ 'body' ][ 'message' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'Cannot set default value for array ' . $this -> getSchemaResource (), $defaultArray [ 'body' ][ 'message' ]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 400 , $datetimeDefault [ 'headers' ][ 'status-code' ]);
// wait for worker to add attributes
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2021-10-05 10:30:33 +00:00
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ],
]), []);
2020-01-13 08:46:09 +00:00
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 10 , $collection [ 'body' ][ $this -> getSchemaResource ()]);
2020-01-13 08:46:09 +00:00
2023-03-24 05:56:49 +00:00
/**
* Test for successful validation
*/
2026-01-09 14:21:31 +00:00
$goodEmail = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'email' => 'user@example.com' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2020-01-13 08:46:09 +00:00
]);
2026-01-09 14:21:31 +00:00
$goodEnum = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-11-03 15:02:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'enum' => 'yes' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2021-11-03 15:02:41 +00:00
]);
2020-01-13 08:46:09 +00:00
2026-01-09 14:21:31 +00:00
$goodIp = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-12-29 14:06:44 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'ip' => '1.1.1.1' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2021-12-29 14:06:44 +00:00
]);
2026-01-09 14:21:31 +00:00
$goodUrl = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-11-03 15:02:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'url' => 'http://www.example.com' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2021-11-03 15:02:41 +00:00
]);
2026-01-09 14:21:31 +00:00
$goodRange = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-11-03 15:02:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'range' => 3 ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2021-11-03 15:02:41 +00:00
]);
2026-01-09 14:21:31 +00:00
$goodFloatRange = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-11-03 15:02:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'floatRange' => 1.4 ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2021-11-03 15:02:41 +00:00
]);
2026-01-09 14:21:31 +00:00
$goodProbability = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-11-03 15:02:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'probability' => 0.99999 ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2021-11-03 15:02:41 +00:00
]);
2026-01-09 14:21:31 +00:00
$notTooHigh = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2022-06-27 20:08:23 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'upperBound' => 8 ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2022-06-27 20:08:23 +00:00
]);
2026-01-09 14:21:31 +00:00
$notTooLow = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2022-06-27 20:08:23 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'lowerBound' => 8 ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2022-06-27 20:08:23 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $goodEmail [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $goodEnum [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $goodIp [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $goodUrl [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $goodRange [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $goodFloatRange [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $goodProbability [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $notTooHigh [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $notTooLow [ 'headers' ][ 'status-code' ]);
2022-06-27 20:08:23 +00:00
2023-03-24 05:56:49 +00:00
/*
* Test that custom validators reject documents
*/
2026-01-09 14:21:31 +00:00
$badEmail = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2023-02-28 03:52:11 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'email' => 'user@@example.com' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2023-02-28 03:52:11 +00:00
]);
2021-12-28 18:16:22 +00:00
2026-01-09 14:21:31 +00:00
$badEnum = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-12-28 18:16:22 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'enum' => 'badEnum' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2021-12-28 18:16:22 +00:00
]);
2026-01-09 14:21:31 +00:00
$badIp = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2022-06-22 07:47:02 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'ip' => '1.1.1.1.1' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2022-06-22 07:47:02 +00:00
]);
2026-01-09 14:21:31 +00:00
$badUrl = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2022-07-28 15:24:17 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'url' => 'example...com' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2022-07-28 15:24:17 +00:00
]);
2022-07-31 10:07:15 +00:00
2026-01-09 14:21:31 +00:00
$badRange = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2020-01-13 08:46:09 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'range' => 11 ,
2020-01-13 17:53:22 +00:00
],
2022-08-02 09:18:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2020-01-13 08:46:09 +00:00
]);
2026-01-09 14:21:31 +00:00
$badFloatRange = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2020-01-13 08:46:09 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'floatRange' => 2.5 ,
2021-03-15 11:44:11 +00:00
],
2022-08-02 09:18:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2020-01-13 08:46:09 +00:00
]);
2026-01-09 14:21:31 +00:00
$badProbability = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'probability' => 1.1 ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
]);
2020-01-13 08:46:09 +00:00
2026-01-09 14:21:31 +00:00
$tooHigh = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2023-01-20 00:36:17 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-01-20 00:36:17 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'upperBound' => 11 ,
2023-01-20 00:36:17 +00:00
],
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2023-01-20 00:36:17 +00:00
]);
2026-01-09 14:21:31 +00:00
$tooLow = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2023-01-20 00:36:17 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-01-20 00:36:17 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'lowerBound' => 3 ,
2023-01-20 00:36:17 +00:00
],
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
2023-01-20 00:36:17 +00:00
]);
2026-01-09 14:21:31 +00:00
$badTime = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2023-01-20 00:36:17 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => 'unique()' ,
2023-01-20 00:36:17 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'birthDay' => '2020-10-10 27:30:10+01:00' ,
2023-01-20 00:36:17 +00:00
],
2023-03-24 05:56:49 +00:00
'read' => [ 'user:' . $this -> getUser ()[ '$id' ]],
'write' => [ 'user:' . $this -> getUser ()[ '$id' ]],
2023-01-20 00:36:17 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 400 , $badEmail [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $badEnum [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $badIp [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $badUrl [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $badRange [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $badFloatRange [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $badProbability [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $tooHigh [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $tooLow [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 400 , $badTime [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Invalid document structure: Attribute "email" has invalid format. Value must be a valid email address' , $badEmail [ 'body' ][ 'message' ]);
$this -> assertEquals ( 'Invalid document structure: Attribute "enum" has invalid format. Value must be one of (yes, no, maybe)' , $badEnum [ 'body' ][ 'message' ]);
$this -> assertEquals ( 'Invalid document structure: Attribute "ip" has invalid format. Value must be a valid IP address' , $badIp [ 'body' ][ 'message' ]);
$this -> assertEquals ( 'Invalid document structure: Attribute "url" has invalid format. Value must be a valid URL' , $badUrl [ 'body' ][ 'message' ]);
$this -> assertEquals ( 'Invalid document structure: Attribute "range" has invalid format. Value must be a valid range between 1 and 10' , $badRange [ 'body' ][ 'message' ]);
$this -> assertEquals ( 'Invalid document structure: Attribute "floatRange" has invalid format. Value must be a valid range between 1 and 1' , $badFloatRange [ 'body' ][ 'message' ]);
$this -> assertEquals ( 'Invalid document structure: Attribute "probability" has invalid format. Value must be a valid range between 0 and 1' , $badProbability [ 'body' ][ 'message' ]);
$this -> assertEquals ( 'Invalid document structure: Attribute "upperBound" has invalid format. Value must be a valid range between -9,223,372,036,854,775,808 and 10' , $tooHigh [ 'body' ][ 'message' ]);
2024-02-23 12:55:00 +00:00
$this -> assertEquals ( 'Invalid document structure: Attribute "lowerBound" has invalid format. Value must be a valid range between 5 and 9,223,372,036,854,775,807' , $tooLow [ 'body' ][ 'message' ]);
2020-01-13 08:46:09 +00:00
}
2026-02-05 22:56:58 +00:00
public function testDefaultPermissions () : void
2020-01-13 08:46:09 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2022-06-22 10:51:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $data [ 'moviesId' ]), array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2020-01-13 08:46:09 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'title' => 'Captain America' ,
'releaseYear' => 1944 ,
2021-06-15 13:38:24 +00:00
'actors' => [],
2020-01-13 17:53:22 +00:00
],
2020-01-13 08:46:09 +00:00
]);
2020-02-17 07:16:11 +00:00
$id = $document [ 'body' ][ '$id' ];
2020-01-13 08:46:09 +00:00
2022-08-08 11:00:03 +00:00
$this -> assertEquals ( 201 , $document [ 'headers' ][ 'status-code' ]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Captain America' );
$this -> assertEquals ( $document [ 'body' ][ 'releaseYear' ], 1944 );
$this -> assertIsArray ( $document [ 'body' ][ '$permissions' ]);
if ( $this -> getSide () == 'client' ) {
$this -> assertCount ( 3 , $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])), $document [ 'body' ][ '$permissions' ]);
}
if ( $this -> getSide () == 'server' ) {
$this -> assertCount ( 0 , $document [ 'body' ][ '$permissions' ]);
$this -> assertEquals ([], $document [ 'body' ][ '$permissions' ]);
}
// Updated Permissions
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'title' => 'Captain America 2' ,
'releaseYear' => 1945 ,
'actors' => [],
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ]))
],
]);
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Captain America 2' );
$this -> assertEquals ( $document [ 'body' ][ 'releaseYear' ], 1945 );
// This differs from the old permissions model because we don't inherit
// existing document permissions on update, unless none were supplied,
// so that specific types can be removed if wanted.
$this -> assertCount ( 2 , $document [ 'body' ][ '$permissions' ]);
$this -> assertEquals ([
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
], $document [ 'body' ][ '$permissions' ]);
2020-01-13 08:46:09 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()));
2022-08-08 11:00:03 +00:00
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Captain America 2' );
$this -> assertEquals ( $document [ 'body' ][ 'releaseYear' ], 1945 );
2020-01-13 08:46:09 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertCount ( 2 , $document [ 'body' ][ '$permissions' ]);
$this -> assertEquals ([
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
], $document [ 'body' ][ '$permissions' ]);
// Reset Permissions
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
'data' => [
'title' => 'Captain America 3' ,
'releaseYear' => 1946 ,
'actors' => [],
],
'permissions' => [],
]);
2020-01-13 08:46:09 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Captain America 3' );
$this -> assertEquals ( $document [ 'body' ][ 'releaseYear' ], 1946 );
$this -> assertCount ( 0 , $document [ 'body' ][ '$permissions' ]);
$this -> assertEquals ([], $document [ 'body' ][ '$permissions' ]);
2020-01-13 08:46:09 +00:00
2023-03-24 05:56:49 +00:00
// Check client side can no longer read the document.
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $data [ 'moviesId' ]) . '/' . $this -> getRecordResource () . '/' . $id , array_merge ([
2020-01-13 08:46:09 +00:00
'content-type' => 'application/json' ,
2020-02-17 07:16:11 +00:00
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2020-01-13 08:46:09 +00:00
], $this -> getHeaders ()));
2023-03-24 05:56:49 +00:00
switch ( $this -> getSide ()) {
case 'client' :
$this -> assertEquals ( 404 , $document [ 'headers' ][ 'status-code' ]);
break ;
case 'server' :
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
break ;
}
2021-03-22 07:34:51 +00:00
}
2023-03-24 05:56:49 +00:00
public function testEnforceCollectionAndDocumentPermissions () : void
2021-07-22 20:39:52 +00:00
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), array_merge ([
2022-06-22 10:51:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2022-08-14 10:33:36 +00:00
'databaseId' => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'EnforceCollectionAndDocumentPermissions' ,
2022-06-22 10:51:49 +00:00
]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 'EnforceCollectionAndDocumentPermissions' , $database [ 'body' ][ 'name' ]);
2022-06-22 10:51:49 +00:00
$databaseId = $database [ 'body' ][ '$id' ];
2023-03-24 05:56:49 +00:00
$user = $this -> getUser ()[ '$id' ];
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2021-07-22 20:39:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'enforceCollectionAndDocumentPermissions' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2022-08-13 14:10:28 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: user ( $user )),
Permission :: create ( Role :: user ( $user )),
Permission :: update ( Role :: user ( $user )),
Permission :: delete ( Role :: user ( $user )),
2022-08-13 14:10:28 +00:00
],
2021-07-22 20:39:52 +00:00
]);
2021-07-23 15:04:31 +00:00
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $collection [ 'body' ][ 'name' ], 'enforceCollectionAndDocumentPermissions' );
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $collection [ 'body' ][ $this -> getSecurityResponseKey ()], true );
2021-07-22 20:39:52 +00:00
$collectionId = $collection [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
2021-09-10 20:25:16 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'attribute' ,
'size' => 64 ,
'required' => true ,
2021-09-10 20:25:16 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $attribute [ 'headers' ][ 'status-code' ], 202 );
$this -> assertEquals ( 'attribute' , $attribute [ 'body' ][ 'key' ]);
2021-07-22 20:39:52 +00:00
2023-03-24 05:56:49 +00:00
// wait for db to add attribute
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $collectionId , 'attribute' );
2021-07-22 20:39:52 +00:00
2026-01-09 14:21:31 +00:00
$index = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2021-07-27 01:00:36 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2021-07-23 21:38:31 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'key_attribute' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ $attribute [ 'body' ][ 'key' ]],
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $index [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'key_attribute' , $index [ 'body' ][ 'key' ]);
2021-07-23 21:38:31 +00:00
2026-01-10 01:53:29 +00:00
// wait for db to add index
$this -> waitForIndex ( $databaseId , $collectionId , 'key_attribute' );
2021-07-27 19:12:24 +00:00
2026-01-09 14:21:31 +00:00
$document1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-07-27 01:00:36 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'attribute' => 'one' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $user )),
Permission :: update ( Role :: user ( $user )),
Permission :: delete ( Role :: user ( $user )),
]
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document1 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$document2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-07-27 01:00:36 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'attribute' => 'one' ,
],
'permissions' => [
Permission :: update ( Role :: user ( $user )),
Permission :: delete ( Role :: user ( $user )),
]
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document2 [ 'headers' ][ 'status-code' ]);
2021-07-23 21:38:31 +00:00
2026-01-09 14:21:31 +00:00
$document3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), [
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2021-10-25 20:10:39 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-03-24 05:56:49 +00:00
], [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'data' => [
'attribute' => 'one' ,
],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( 'other' ))),
Permission :: update ( Role :: user ( ID :: custom ( 'other' ))),
],
2021-10-25 20:10:39 +00:00
]);
2021-07-23 21:38:31 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document3 [ 'headers' ][ 'status-code' ]);
2021-10-26 20:14:25 +00:00
2026-01-09 14:21:31 +00:00
$documentsUser1 = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-12-16 10:15:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()));
2021-12-16 10:15:55 +00:00
2023-03-24 05:56:49 +00:00
// Current user has read permission on the collection so can get any document
$this -> assertEquals ( 3 , $documentsUser1 [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 3 , $documentsUser1 [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$document3GetWithCollectionRead = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $document3 [ 'body' ][ '$id' ], array_merge ([
2021-12-16 10:15:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()));
2021-12-16 10:15:55 +00:00
2023-03-24 05:56:49 +00:00
// Current user has read permission on the collection so can get any document
$this -> assertEquals ( 200 , $document3GetWithCollectionRead [ 'headers' ][ 'status-code' ]);
$email = uniqid () . 'user@localhost.test' ;
$password = 'password' ;
$name = 'User Name' ;
$this -> client -> call ( Client :: METHOD_POST , '/account' , [
'origin' => 'http://localhost' ,
2021-12-16 13:06:32 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], [
'userId' => ID :: custom ( 'other' ),
'email' => $email ,
'password' => $password ,
'name' => $name ,
2021-12-16 13:06:32 +00:00
]);
2023-03-24 05:56:49 +00:00
$session2 = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , [
'origin' => 'http://localhost' ,
2022-07-31 12:32:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], [
'email' => $email ,
'password' => $password ,
2022-07-31 12:32:41 +00:00
]);
2023-12-08 23:27:35 +00:00
$session2 = $session2 [ 'cookies' ][ 'a_session_' . $this -> getProject ()[ '$id' ]];
2022-07-31 12:32:41 +00:00
2026-01-09 14:21:31 +00:00
$document3GetWithDocumentRead = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $document3 [ 'body' ][ '$id' ], [
2023-03-24 05:56:49 +00:00
'origin' => 'http://localhost' ,
2022-07-31 12:32:41 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'cookie' => 'a_session_' . $this -> getProject ()[ '$id' ] . '=' . $session2 ,
2022-07-31 12:32:41 +00:00
]);
2023-03-24 05:56:49 +00:00
// Current user has no collection permissions but has read permission for this document
$this -> assertEquals ( 200 , $document3GetWithDocumentRead [ 'headers' ][ 'status-code' ]);
2021-07-22 20:39:52 +00:00
2026-01-09 14:21:31 +00:00
$document2GetFailure = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $document2 [ 'body' ][ '$id' ], [
2023-03-24 05:56:49 +00:00
'origin' => 'http://localhost' ,
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'cookie' => 'a_session_' . $this -> getProject ()[ '$id' ] . '=' . $session2 ,
]);
2021-07-23 21:38:31 +00:00
2023-03-24 05:56:49 +00:00
// Current user has no collection or document permissions for this document
$this -> assertEquals ( 404 , $document2GetFailure [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$documentsUser2 = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), [
2023-03-24 05:56:49 +00:00
'origin' => 'http://localhost' ,
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'cookie' => 'a_session_' . $this -> getProject ()[ '$id' ] . '=' . $session2 ,
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
// Current user has no collection permissions but has read permission for one document
$this -> assertEquals ( 1 , $documentsUser2 [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $documentsUser2 [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
}
2025-06-12 14:28:28 +00:00
public function testEnforceCollectionPermissions () : void
2023-03-24 05:56:49 +00:00
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), array_merge ([
2021-09-10 20:25:16 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'databaseId' => ID :: unique (),
'name' => 'EnforceCollectionPermissions' ,
2021-09-10 20:25:16 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'EnforceCollectionPermissions' , $database [ 'body' ][ 'name' ]);
2021-09-10 20:25:16 +00:00
2023-03-24 05:56:49 +00:00
$databaseId = $database [ 'body' ][ '$id' ];
$user = $this -> getUser ()[ '$id' ];
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'enforceCollectionPermissions' ,
2022-08-03 04:17:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: user ( $user )),
Permission :: create ( Role :: user ( $user )),
Permission :: update ( Role :: user ( $user )),
Permission :: delete ( Role :: user ( $user )),
],
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $collection [ 'body' ][ 'name' ], 'enforceCollectionPermissions' );
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $collection [ 'body' ][ $this -> getSecurityResponseKey ()], false );
2023-03-24 05:56:49 +00:00
$collectionId = $collection [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'attribute' ,
'size' => 64 ,
'required' => true ,
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $attribute [ 'headers' ][ 'status-code' ], 202 );
$this -> assertEquals ( 'attribute' , $attribute [ 'body' ][ 'key' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $collectionId , 'attribute' );
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$index = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'key_attribute' ,
'type' => 'key' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ $attribute [ 'body' ][ 'key' ]],
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $index [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'key_attribute' , $index [ 'body' ][ 'key' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForIndex ( $databaseId , $collectionId , 'key_attribute' );
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$document1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2021-07-23 21:38:31 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'attribute' => 'one' ,
2021-07-23 21:38:31 +00:00
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: user ( $user )),
Permission :: update ( Role :: user ( $user )),
Permission :: delete ( Role :: user ( $user )),
2022-08-03 04:17:49 +00:00
]
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document1 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$document2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-10-25 20:00:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2021-10-25 20:00:33 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'attribute' => 'one' ,
2021-10-25 20:00:33 +00:00
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: update ( Role :: user ( $user )),
Permission :: delete ( Role :: user ( $user )),
2022-08-03 04:17:49 +00:00
]
2021-10-25 20:00:33 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document2 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$document3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), [
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2021-07-23 21:38:31 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'attribute' => 'one' ,
2021-07-23 21:38:31 +00:00
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: user ( ID :: custom ( 'other2' ))),
Permission :: update ( Role :: user ( ID :: custom ( 'other2' ))),
],
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document3 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$documentsUser1 = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()));
2021-07-23 21:38:31 +00:00
2023-03-24 05:56:49 +00:00
// Current user has read permission on the collection so can get any document
$this -> assertEquals ( 3 , $documentsUser1 [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 3 , $documentsUser1 [ 'body' ][ $this -> getRecordResource ()]);
2021-07-23 21:38:31 +00:00
2026-01-09 14:21:31 +00:00
$document3GetWithCollectionRead = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $document3 [ 'body' ][ '$id' ], array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2021-07-23 21:38:31 +00:00
2023-03-24 05:56:49 +00:00
// Current user has read permission on the collection so can get any document
$this -> assertEquals ( 200 , $document3GetWithCollectionRead [ 'headers' ][ 'status-code' ]);
$email = uniqid () . 'user2@localhost.test' ;
$password = 'password' ;
$name = 'User Name' ;
$this -> client -> call ( Client :: METHOD_POST , '/account' , [
'origin' => 'http://localhost' ,
2021-07-22 20:39:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], [
'userId' => ID :: custom ( 'other2' ),
'email' => $email ,
'password' => $password ,
'name' => $name ,
]);
$session2 = $this -> client -> call ( Client :: METHOD_POST , '/account/sessions/email' , [
'origin' => 'http://localhost' ,
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], [
'email' => $email ,
'password' => $password ,
2021-07-22 20:39:52 +00:00
]);
2023-12-08 23:48:34 +00:00
$session2 = $session2 [ 'cookies' ][ 'a_session_' . $this -> getProject ()[ '$id' ]];
2021-07-22 20:39:52 +00:00
2026-01-09 14:21:31 +00:00
$document3GetWithDocumentRead = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $document3 [ 'body' ][ '$id' ], [
2023-03-24 05:56:49 +00:00
'origin' => 'http://localhost' ,
2021-09-10 20:25:16 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'cookie' => 'a_session_' . $this -> getProject ()[ '$id' ] . '=' . $session2 ,
2021-09-10 20:25:16 +00:00
]);
2023-08-22 03:25:55 +00:00
// other2 has no collection permissions and document permissions are disabled
2023-03-28 09:08:36 +00:00
$this -> assertEquals ( 404 , $document3GetWithDocumentRead [ 'headers' ][ 'status-code' ]);
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$documentsUser2 = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), [
2023-03-24 05:56:49 +00:00
'origin' => 'http://localhost' ,
2021-07-22 20:39:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'cookie' => 'a_session_' . $this -> getProject ()[ '$id' ] . '=' . $session2 ,
2021-07-22 20:39:52 +00:00
]);
2023-08-22 03:25:55 +00:00
// other2 has no collection permissions and document permissions are disabled
$this -> assertEquals ( 401 , $documentsUser2 [ 'headers' ][ 'status-code' ]);
2023-03-24 05:56:49 +00:00
// Enable document permissions
2026-02-05 15:03:40 +00:00
$collection = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $collectionId ), [
2021-07-22 20:39:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'name' => $collection [ 'body' ][ 'name' ],
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2021-07-22 20:39:52 +00:00
]);
2026-01-09 14:21:31 +00:00
$documentsUser2 = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), [
2023-03-24 05:56:49 +00:00
'origin' => 'http://localhost' ,
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'cookie' => 'a_session_' . $this -> getProject ()[ '$id' ] . '=' . $session2 ,
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
// Current user has no collection permissions read access to one document
$this -> assertEquals ( 1 , $documentsUser2 [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $documentsUser2 [ 'body' ][ $this -> getRecordResource ()]);
2023-03-24 05:56:49 +00:00
}
2026-02-05 22:56:58 +00:00
public function testUniqueIndexDuplicate () : void
2023-03-24 05:56:49 +00:00
{
2026-02-09 04:53:21 +00:00
// Use a dedicated collection for this test to avoid interference from other tests
// that may add duplicate titles to the shared movies collection in the same process
$data = $this -> setupDatabase ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-02-09 04:53:21 +00:00
$serverHeaders = array_merge ([
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2026-02-09 04:53:21 +00:00
]);
// Create a dedicated collection for unique index testing
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), $serverHeaders , [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'uniqueIndexTest' ,
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
$this -> getSecurityParam () => true ,
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Add a title attribute
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , $serverHeaders , [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
$this -> waitForAttribute ( $databaseId , $collectionId , 'title' );
// Add two documents with unique titles
$this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [ 'title' => 'Unique Title A' ],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
]);
$this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [ 'title' => 'Unique Title B' ],
'permissions' => [
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
]
]);
// Create unique index on title
$uniqueIndex = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), $serverHeaders , [
2023-03-24 05:56:49 +00:00
'key' => 'unique_title' ,
'type' => 'unique' ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'title' ],
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $uniqueIndex [ 'headers' ][ 'status-code' ]);
2026-02-09 04:53:21 +00:00
$this -> waitForIndex ( $databaseId , $collectionId , 'unique_title' );
2023-03-24 05:56:49 +00:00
2026-02-09 04:53:21 +00:00
// test for failure - inserting duplicate title
$duplicate = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-10-25 20:00:33 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2021-10-25 20:00:33 +00:00
'data' => [
2026-02-09 04:53:21 +00:00
'title' => 'Unique Title A' ,
2021-10-25 20:00:33 +00:00
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2022-08-14 10:33:36 +00:00
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
2022-08-03 04:17:49 +00:00
]
2021-10-25 20:00:33 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 409 , $duplicate [ 'headers' ][ 'status-code' ]);
2026-02-09 04:53:21 +00:00
// Test for exception when inserting new doc and then updating to conflict
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2021-07-23 21:38:31 +00:00
'data' => [
2026-02-09 04:53:21 +00:00
'title' => 'Unique Title C' ,
2021-07-23 21:38:31 +00:00
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2022-08-14 10:33:36 +00:00
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
2022-08-03 04:17:49 +00:00
]
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document [ 'headers' ][ 'status-code' ]);
// Test for exception when updating document to conflict
2026-02-09 04:53:21 +00:00
$duplicate = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . $document [ 'body' ][ '$id' ], array_merge ([
2021-07-23 21:38:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2021-07-23 21:38:31 +00:00
'data' => [
2026-02-09 04:53:21 +00:00
'title' => 'Unique Title A' ,
2021-07-23 21:38:31 +00:00
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2022-08-14 10:33:36 +00:00
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
2022-08-03 04:17:49 +00:00
]
2021-07-23 21:38:31 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 409 , $duplicate [ 'headers' ][ 'status-code' ]);
2021-07-22 20:39:52 +00:00
}
2026-02-05 22:56:58 +00:00
public function testPersistentCreatedAt () : void
2021-03-22 07:34:51 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDocuments ();
2023-03-24 05:56:49 +00:00
$headers = $this -> getSide () === 'client' ? array_merge ([
2021-03-22 07:34:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()) : [
2021-03-22 07:34:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
];
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ 'moviesId' ]), $headers , [
$this -> getRecordIdParam () => ID :: unique (),
2021-03-22 07:34:51 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'title' => 'Creation Date Test' ,
'releaseYear' => 2000
]
2021-03-22 07:34:51 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Creation Date Test' );
2021-03-22 07:34:51 +00:00
2023-03-24 05:56:49 +00:00
$documentId = $document [ 'body' ][ '$id' ];
$createdAt = $document [ 'body' ][ '$createdAt' ];
$updatedAt = $document [ 'body' ][ '$updatedAt' ];
2021-03-22 07:34:51 +00:00
2023-03-24 05:56:49 +00:00
\sleep ( 1 );
2021-03-22 07:34:51 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ 'moviesId' ], $documentId ), $headers , [
2021-03-22 07:34:51 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'title' => 'Updated Date Test' ,
]
2021-03-22 07:34:51 +00:00
]);
2023-03-24 05:56:49 +00:00
$updatedAtSecond = $document [ 'body' ][ '$updatedAt' ];
2021-03-22 07:34:51 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Updated Date Test' );
$this -> assertEquals ( $document [ 'body' ][ '$createdAt' ], $createdAt );
$this -> assertNotEquals ( $document [ 'body' ][ '$updatedAt' ], $updatedAt );
2022-08-24 13:32:52 +00:00
2023-03-24 05:56:49 +00:00
\sleep ( 1 );
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ 'moviesId' ], $documentId ), $headers , [
2023-03-24 05:56:49 +00:00
'data' => [
'title' => 'Again Updated Date Test' ,
2025-07-31 15:02:14 +00:00
'$createdAt' => '2022-08-01 13:09:23.040' ,
'$updatedAt' => '2022-08-01 13:09:23.050'
2023-03-24 05:56:49 +00:00
]
]);
2025-07-31 15:02:14 +00:00
if ( $this -> getSide () === 'client' ) {
2025-08-29 09:01:09 +00:00
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Again Updated Date Test' );
$this -> assertNotEquals ( $document [ 'body' ][ '$createdAt' ], DateTime :: formatTz ( '2022-08-01 13:09:23.040' ));
$this -> assertNotEquals ( $document [ 'body' ][ '$updatedAt' ], DateTime :: formatTz ( '2022-08-01 13:09:23.050' ));
2025-07-31 15:02:14 +00:00
} else {
$this -> assertEquals ( $document [ 'body' ][ 'title' ], 'Again Updated Date Test' );
$this -> assertEquals ( $document [ 'body' ][ '$createdAt' ], DateTime :: formatTz ( '2022-08-01 13:09:23.040' ));
$this -> assertEquals ( $document [ 'body' ][ '$updatedAt' ], DateTime :: formatTz ( '2022-08-01 13:09:23.050' ));
2023-03-24 05:56:49 +00:00
2025-07-31 15:02:14 +00:00
}
2020-01-13 08:46:09 +00:00
}
2021-08-18 18:49:57 +00:00
2026-02-05 22:56:58 +00:00
public function testUpdatePermissionsWithEmptyPayload () : void
2021-08-12 01:07:46 +00:00
{
2023-03-24 05:56:49 +00:00
// Create Database
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), array_merge ([
2022-06-22 10:51:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2022-08-14 10:33:36 +00:00
'databaseId' => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'Empty Permissions' ,
2022-06-22 10:51:49 +00:00
]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$databaseId = $database [ 'body' ][ '$id' ];
2023-03-24 05:56:49 +00:00
// Create collection
2026-01-09 14:21:31 +00:00
$movies = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2021-08-12 01:07:46 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'Movies' ,
2022-08-03 04:17:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: create ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
2022-08-03 04:17:49 +00:00
],
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2021-08-12 01:07:46 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $movies [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $movies [ 'body' ][ 'name' ], 'Movies' );
2021-08-12 01:07:46 +00:00
2023-03-24 05:56:49 +00:00
$moviesId = $movies [ 'body' ][ '$id' ];
2021-08-13 20:20:54 +00:00
2023-03-24 05:56:49 +00:00
// create attribute
2026-01-09 14:21:31 +00:00
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $moviesId ) . '/string' , array_merge ([
2021-08-12 01:07:46 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'title' ,
'size' => 256 ,
2021-08-12 01:07:46 +00:00
'required' => true ,
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
2021-08-12 01:07:46 +00:00
2023-03-24 05:56:49 +00:00
// wait for database worker to create attributes
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $moviesId , 'title' );
2021-08-12 01:07:46 +00:00
2023-03-24 05:56:49 +00:00
// add document
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $moviesId ), array_merge ([
2021-09-01 14:57:20 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2021-08-12 01:07:46 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'title' => 'Captain America' ,
2021-08-12 01:07:46 +00:00
],
2022-08-03 04:17:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
2021-08-12 01:07:46 +00:00
]);
2023-03-24 05:56:49 +00:00
$id = $document [ 'body' ][ '$id' ];
2021-08-12 01:07:46 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 3 , $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: read ( Role :: any ()), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: update ( Role :: any ()), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: delete ( Role :: any ()), $document [ 'body' ][ '$permissions' ]);
// Send only read permission
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $moviesId , $id ), array_merge ([
2021-12-16 18:12:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2022-08-03 04:17:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
2022-08-03 04:17:49 +00:00
]
2021-12-16 18:12:06 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 1 , $document [ 'body' ][ '$permissions' ]);
2021-12-16 18:12:06 +00:00
2023-03-24 05:56:49 +00:00
// Send only mutation permissions
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $moviesId , $id ), array_merge ([
2021-12-16 18:12:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2022-08-08 11:00:03 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: update ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
Permission :: delete ( Role :: user ( ID :: custom ( $this -> getUser ()[ '$id' ]))),
2022-08-08 11:00:03 +00:00
],
2021-12-16 18:12:06 +00:00
]);
2023-03-24 05:56:49 +00:00
if ( $this -> getSide () == 'server' ) {
$this -> assertEquals ( 200 , $document [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 2 , $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])), $document [ 'body' ][ '$permissions' ]);
$this -> assertContains ( Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])), $document [ 'body' ][ '$permissions' ]);
}
2021-12-16 18:12:06 +00:00
2023-03-24 05:56:49 +00:00
// remove collection
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $moviesId ), array_merge ([
2021-08-12 01:07:46 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2023-03-24 05:56:49 +00:00
}
2021-08-13 20:20:54 +00:00
2026-02-05 22:56:58 +00:00
public function testAttributeBooleanDefault () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDatabase ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2021-08-13 20:20:54 +00:00
2023-03-24 05:56:49 +00:00
/**
* Test for SUCCESS
*/
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2021-08-13 20:20:54 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'Boolean'
2022-08-08 11:00:03 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$collectionId = $collection [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$true = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/boolean' , array_merge ([
2022-08-08 11:00:03 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'true' ,
'required' => false ,
'default' => true
2021-08-13 20:20:54 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $true [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$false = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/boolean' , array_merge ([
2022-08-08 11:00:03 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'false' ,
'required' => false ,
'default' => false
2022-08-08 11:00:03 +00:00
]);
2021-08-13 20:20:54 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $false [ 'headers' ][ 'status-code' ]);
}
2021-08-13 20:20:54 +00:00
2026-02-05 22:56:58 +00:00
public function testOneToOneRelationship () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDatabase ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
2026-01-09 14:21:31 +00:00
$person = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2021-08-13 20:20:54 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-02-09 01:20:42 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'person' ,
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2021-08-13 20:20:54 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $person [ 'headers' ][ 'status-code' ]);
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$library = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-02-09 01:20:42 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'library' ,
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2022-08-24 13:32:52 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $library [ 'headers' ][ 'status-code' ]);
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'fullName' ,
'size' => 255 ,
'required' => false ,
2022-08-24 13:32:52 +00:00
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $person [ 'body' ][ '$id' ], 'fullName' );
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$relation = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/relationship' , array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-02-09 01:20:42 +00:00
$this -> getRelatedIdParam () => $library [ 'body' ][ '$id' ],
2023-03-24 05:56:49 +00:00
'type' => Database :: RELATION_ONE_TO_ONE ,
'key' => 'library' ,
2023-03-30 17:36:24 +00:00
'twoWay' => true ,
2026-02-09 02:28:38 +00:00
'twoWayKey' => 'person' ,
2023-03-24 05:56:49 +00:00
'onDelete' => Database :: RELATION_MUTATE_CASCADE ,
2022-08-24 13:32:52 +00:00
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $person [ 'body' ][ '$id' ], 'library' );
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$libraryName = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $library [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'libraryName' ,
'size' => 255 ,
2022-08-24 13:32:52 +00:00
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $library [ 'body' ][ '$id' ], 'libraryName' );
2022-08-24 13:32:52 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $libraryName [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 202 , $relation [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'library' , $relation [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'relationship' , $relation [ 'body' ][ 'type' ]);
$this -> assertEquals ( 'processing' , $relation [ 'body' ][ 'status' ]);
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$attributes = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2023-03-27 15:24:02 +00:00
'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 ( 2 , $attributes [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$attributes = $attributes [ 'body' ][ $this -> getSchemaResource ()];
2026-02-09 01:55:41 +00:00
$this -> assertEquals ( $library [ 'body' ][ '$id' ], $attributes [ 1 ][ $this -> getRelatedResourceKey ()]);
2023-03-27 15:24:02 +00:00
$this -> assertEquals ( 'oneToOne' , $attributes [ 1 ][ 'relationType' ]);
2023-03-30 17:36:24 +00:00
$this -> assertEquals ( true , $attributes [ 1 ][ 'twoWay' ]);
2023-03-27 15:24:02 +00:00
$this -> assertEquals ( 'person' , $attributes [ 1 ][ 'twoWayKey' ]);
$this -> assertEquals ( Database :: RELATION_MUTATE_CASCADE , $attributes [ 1 ][ 'onDelete' ]);
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ], '' , 'library' ), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-03-24 05:56:49 +00:00
]));
2022-08-24 13:32:52 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $attribute [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'available' , $attribute [ 'body' ][ 'status' ]);
$this -> assertEquals ( 'library' , $attribute [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'relationship' , $attribute [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $attribute [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $attribute [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'oneToOne' , $attribute [ 'body' ][ 'relationType' ]);
2023-03-30 17:36:24 +00:00
$this -> assertEquals ( true , $attribute [ 'body' ][ 'twoWay' ]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 'person' , $attribute [ 'body' ][ 'twoWayKey' ]);
$this -> assertEquals ( Database :: RELATION_MUTATE_CASCADE , $attribute [ 'body' ][ 'onDelete' ]);
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$person1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2022-08-24 13:32:52 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'library' => [
'$id' => 'library1' ,
'$permissions' => [
Permission :: read ( Role :: any ()),
],
'libraryName' => 'Library 1' ,
],
2022-08-24 13:32:52 +00:00
],
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
2022-08-24 13:32:52 +00:00
]
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 'Library 1' , $person1 [ 'body' ][ 'library' ][ 'libraryName' ]);
2022-08-24 13:32:52 +00:00
2023-04-13 03:59:57 +00:00
// Create without nested ID
2026-01-09 14:21:31 +00:00
$person2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2023-04-13 03:59:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-04-13 03:59:57 +00:00
'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' ]);
2023-03-27 02:42:36 +00:00
// Ensure IDs were set and internal IDs removed
$this -> assertEquals ( $databaseId , $person1 [ 'body' ][ '$databaseId' ]);
$this -> assertEquals ( $databaseId , $person1 [ 'body' ][ 'library' ][ '$databaseId' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $person [ 'body' ][ '$id' ], $person1 [ 'body' ][ $this -> getContainerIdResponseKey ()]);
$this -> assertEquals ( $library [ 'body' ][ '$id' ], $person1 [ 'body' ][ 'library' ][ $this -> getContainerIdResponseKey ()]);
2023-03-27 02:42:36 +00:00
$this -> assertArrayNotHasKey ( '$collection' , $person1 [ 'body' ]);
$this -> assertArrayNotHasKey ( '$collection' , $person1 [ 'body' ][ 'library' ]);
2025-05-23 10:45:47 +00:00
$this -> assertArrayHasKey ( '$sequence' , $person1 [ 'body' ]);
$this -> assertArrayHasKey ( '$sequence' , $person1 [ 'body' ][ 'library' ]);
2023-03-27 02:42:36 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-03-24 05:56:49 +00:00
'queries' => [
2025-06-12 03:40:59 +00:00
Query :: select ([ 'fullName' , 'library.*' ]) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: equal ( 'library' , [ 'library1' ]) -> toString (),
],
2022-08-24 13:32:52 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 1 , $documents [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'Library 1' , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'library' ][ 'libraryName' ]);
$this -> assertArrayHasKey ( 'fullName' , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ]);
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$documents = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $person [ 'body' ][ '$id' ]), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-10-04 11:06:56 +00:00
Query :: select ([ 'library.*' ]) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: equal ( 'library.libraryName' , [ 'Library 1' ]) -> toString (),
2022-08-24 13:32:52 +00:00
],
]);
2025-10-04 09:55:07 +00:00
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2025-10-04 11:06:56 +00:00
$this -> assertEquals ( 1 , $documents [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $documents [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Library 1' , $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'library' ][ 'libraryName' ]);
$this -> assertEquals ( $person1 [ 'body' ][ '$id' ], $documents [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_DELETE , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ], '' , 'library' ), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2022-08-24 13:32:52 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 204 , $response [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> assertEventually ( function () use ( $databaseId , $person ) {
$attribute = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ], '' , 'library' ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
$this -> assertEquals ( 404 , $attribute [ 'headers' ][ 'status-code' ]);
return true ;
}, 60000 , 500 );
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $person [ 'body' ][ '$id' ], '' , 'library' ), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
$this -> assertEquals ( 404 , $attribute [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$person1 = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $person [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $person1 [ 'body' ][ '$id' ], array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2023-03-24 05:56:49 +00:00
$this -> assertArrayNotHasKey ( 'library' , $person1 [ 'body' ]);
2022-08-24 13:32:52 +00:00
2023-03-30 17:36:24 +00:00
//Test Deletion of related twoKey
2026-01-09 14:21:31 +00:00
$attributes = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $library [ 'body' ][ '$id' ]), array_merge ([
2023-03-30 17:36:24 +00:00
'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 ( 1 , $attributes [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'libraryName' , $attributes [ 'body' ][ $this -> getSchemaResource ()][ 0 ][ 'key' ]);
2023-03-24 05:56:49 +00:00
}
2026-02-05 22:56:58 +00:00
public function testOneToManyRelationship () : void
2023-03-24 05:56:49 +00:00
{
2026-02-09 01:20:42 +00:00
// Use setupOneToManyRelationship to ensure relationship and collections are created idempotently
$data = $this -> setupOneToManyRelationship ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
$personCollection = $data [ 'personCollection' ];
2026-02-09 01:55:41 +00:00
$libraryCollection = $data [ 'libraryCollection' ];
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$libraryAttributesResponse = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $libraryCollection ), array_merge ([
2023-03-29 15:34:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> assertIsArray ( $libraryAttributesResponse [ 'body' ][ $this -> getSchemaResource ()]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 2 , $libraryAttributesResponse [ 'body' ][ 'total' ]);
2023-03-29 15:34:49 +00:00
2026-01-09 14:21:31 +00:00
$libraryCollectionResponse = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $libraryCollection ), array_merge ([
2023-03-29 15:34:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> assertIsArray ( $libraryCollectionResponse [ 'body' ][ $this -> getSchemaResource ()]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 2 , count ( $libraryCollectionResponse [ 'body' ][ $this -> getSchemaResource ()]));
2023-03-29 15:34:49 +00:00
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $personCollection , '' , 'libraries' ), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2022-08-24 13:32:52 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $attribute [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'available' , $attribute [ 'body' ][ 'status' ]);
$this -> assertEquals ( 'libraries' , $attribute [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'relationship' , $attribute [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $attribute [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $attribute [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'oneToMany' , $attribute [ 'body' ][ 'relationType' ]);
$this -> assertEquals ( true , $attribute [ 'body' ][ 'twoWay' ]);
2023-03-30 17:36:24 +00:00
$this -> assertEquals ( 'person_one_to_many' , $attribute [ 'body' ][ 'twoWayKey' ]);
2026-02-09 01:20:42 +00:00
$personDocId = ID :: unique ();
$libraryDoc10Id = ID :: unique ();
$libraryDoc11Id = ID :: unique ();
2023-03-24 05:56:49 +00:00
2026-01-09 14:21:31 +00:00
$person2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $personCollection ), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
2026-02-09 01:20:42 +00:00
$this -> getRecordIdParam () => $personDocId ,
2023-03-24 05:56:49 +00:00
'data' => [
2026-02-09 01:20:42 +00:00
'fullName' => 'Ray Charles' ,
2023-03-24 05:56:49 +00:00
'libraries' => [
[
2026-02-09 01:20:42 +00:00
'$id' => $libraryDoc10Id ,
2023-03-24 05:56:49 +00:00
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
'libraryName' => 'Library 10' ,
],
[
2026-02-09 01:20:42 +00:00
'$id' => $libraryDoc11Id ,
2023-03-24 05:56:49 +00:00
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
'libraryName' => 'Library 11' ,
]
],
],
'permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
]
2022-08-24 13:32:52 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $person2 [ 'headers' ][ 'status-code' ]);
$this -> assertArrayHasKey ( 'libraries' , $person2 [ 'body' ]);
$this -> assertEquals ( 2 , count ( $person2 [ 'body' ][ 'libraries' ]));
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $personCollection , $person2 [ 'body' ][ '$id' ]), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-06-09 08:53:04 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:44:02 +00:00
Query :: select ([ '*' , 'libraries.*' ]) -> toString ()
2025-06-09 08:53:04 +00:00
]
]);
2022-08-24 13:32:52 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertArrayNotHasKey ( '$collection' , $response [ 'body' ]);
$this -> assertArrayHasKey ( 'libraries' , $response [ 'body' ]);
$this -> assertEquals ( 2 , count ( $response [ 'body' ][ 'libraries' ]));
2026-02-09 01:20:42 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $libraryCollection , $libraryDoc11Id ), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-06-09 08:53:04 +00:00
], $this -> getHeaders ()), [
'queries' => [
Query :: select ([ 'person_one_to_many.$id' ]) -> toString ()
]
]);
2022-08-24 13:32:52 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2023-03-30 17:36:24 +00:00
$this -> assertArrayHasKey ( 'person_one_to_many' , $response [ 'body' ]);
2026-02-09 01:20:42 +00:00
$this -> assertEquals ( $personDocId , $response [ 'body' ][ 'person_one_to_many' ][ '$id' ]);
2022-08-24 13:32:52 +00:00
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $personCollection , 'relationship' , 'libraries' ), array_merge ([
2022-08-24 13:32:52 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-03-24 05:56:49 +00:00
]), [
'onDelete' => Database :: RELATION_MUTATE_CASCADE ,
2022-08-24 13:32:52 +00:00
]);
2021-08-13 20:20:54 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$attribute = $this -> client -> call ( Client :: METHOD_GET , $this -> getSchemaUrl ( $databaseId , $personCollection , '' , 'libraries' ), array_merge ([
2021-08-13 20:20:54 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2021-08-13 20:20:54 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $attribute [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'available' , $attribute [ 'body' ][ 'status' ]);
$this -> assertEquals ( 'libraries' , $attribute [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'relationship' , $attribute [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $attribute [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $attribute [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'oneToMany' , $attribute [ 'body' ][ 'relationType' ]);
2023-03-31 08:29:02 +00:00
$this -> assertEquals ( true , $attribute [ 'body' ][ 'twoWay' ]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( Database :: RELATION_MUTATE_CASCADE , $attribute [ 'body' ][ 'onDelete' ]);
2021-08-12 01:07:46 +00:00
}
2021-09-01 14:52:38 +00:00
2026-02-05 22:56:58 +00:00
public function testManyToOneRelationship () : void
2021-08-18 18:49:57 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDatabase ();
2022-06-22 10:51:49 +00:00
$databaseId = $data [ 'databaseId' ];
2023-03-24 05:56:49 +00:00
// Create album collection
2026-01-09 14:21:31 +00:00
$albums = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2021-08-18 18:49:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'Albums' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
2021-08-18 18:49:57 +00:00
]);
2023-03-24 05:56:49 +00:00
// Create album name attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $albums [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2021-08-18 18:49:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 255 ,
'required' => true ,
2021-08-18 18:49:57 +00:00
]);
2023-03-24 05:56:49 +00:00
// Create artist collection
2026-01-09 14:21:31 +00:00
$artists = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2021-08-18 18:49:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'Artists' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2022-08-03 04:17:49 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
2021-08-18 18:49:57 +00:00
]);
2023-03-24 05:56:49 +00:00
// Create artist name attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $artists [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2021-08-18 18:49:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 255 ,
'required' => true ,
2021-08-18 18:49:57 +00:00
]);
2023-03-24 05:56:49 +00:00
// Create relationship
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $albums [ 'body' ][ '$id' ]) . '/relationship' , array_merge ([
2022-07-08 09:36:19 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
2023-03-24 05:56:49 +00:00
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => $artists [ 'body' ][ '$id' ],
2023-03-24 05:56:49 +00:00
'type' => Database :: RELATION_MANY_TO_ONE ,
'twoWay' => true ,
'key' => 'artist' ,
'twoWayKey' => 'albums' ,
2022-07-08 09:36:19 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'artist' , $response [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'relationship' , $response [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $response [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $response [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'manyToOne' , $response [ 'body' ][ 'relationType' ]);
$this -> assertEquals ( true , $response [ 'body' ][ 'twoWay' ]);
$this -> assertEquals ( 'albums' , $response [ 'body' ][ 'twoWayKey' ]);
$this -> assertEquals ( 'restrict' , $response [ 'body' ][ 'onDelete' ]);
2022-07-08 09:36:19 +00:00
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $albums [ 'body' ][ '$id' ], 'artist' );
2022-07-08 09:36:19 +00:00
2023-03-24 05:56:49 +00:00
$permissions = [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
];
2022-07-08 09:36:19 +00:00
2023-03-24 05:56:49 +00:00
// Create album
2026-01-09 14:21:31 +00:00
$album = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $albums [ 'body' ][ '$id' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => 'album1' ,
2023-03-24 05:56:49 +00:00
'permissions' => $permissions ,
2022-07-08 09:36:19 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'name' => 'Album 1' ,
'artist' => [
'$id' => ID :: unique (),
'name' => 'Artist 1' ,
],
],
2022-07-08 09:36:19 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $album [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'album1' , $album [ 'body' ][ '$id' ]);
$this -> assertEquals ( 'Album 1' , $album [ 'body' ][ 'name' ]);
$this -> assertEquals ( 'Artist 1' , $album [ 'body' ][ 'artist' ][ 'name' ]);
$this -> assertEquals ( $permissions , $album [ 'body' ][ '$permissions' ]);
$this -> assertEquals ( $permissions , $album [ 'body' ][ 'artist' ][ '$permissions' ]);
2022-07-08 09:36:19 +00:00
2026-01-09 14:21:31 +00:00
$album = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $albums [ 'body' ][ '$id' ], 'album1' ), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-06-09 08:53:04 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:44:02 +00:00
Query :: select ([ '*' , 'artist.name' , 'artist.$permissions' ]) -> toString ()
2025-06-09 08:53:04 +00:00
]
]);
2022-07-08 09:36:19 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $album [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'album1' , $album [ 'body' ][ '$id' ]);
$this -> assertEquals ( 'Album 1' , $album [ 'body' ][ 'name' ]);
$this -> assertEquals ( 'Artist 1' , $album [ 'body' ][ 'artist' ][ 'name' ]);
$this -> assertEquals ( $permissions , $album [ 'body' ][ '$permissions' ]);
$this -> assertEquals ( $permissions , $album [ 'body' ][ 'artist' ][ '$permissions' ]);
2022-07-08 09:36:19 +00:00
2026-01-09 14:21:31 +00:00
$artist = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $artists [ 'body' ][ '$id' ], $album [ 'body' ][ 'artist' ][ '$id' ]), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-06-09 08:53:04 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:44:02 +00:00
Query :: select ([ '*' , 'albums.$id' , 'albums.name' , 'albums.$permissions' ]) -> toString ()
2025-06-09 08:53:04 +00:00
]
]);
2022-07-08 09:36:19 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $artist [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Artist 1' , $artist [ 'body' ][ 'name' ]);
$this -> assertEquals ( $permissions , $artist [ 'body' ][ '$permissions' ]);
$this -> assertEquals ( 1 , count ( $artist [ 'body' ][ 'albums' ]));
$this -> assertEquals ( 'album1' , $artist [ 'body' ][ 'albums' ][ 0 ][ '$id' ]);
$this -> assertEquals ( 'Album 1' , $artist [ 'body' ][ 'albums' ][ 0 ][ 'name' ]);
$this -> assertEquals ( $permissions , $artist [ 'body' ][ 'albums' ][ 0 ][ '$permissions' ]);
2022-07-08 09:36:19 +00:00
}
2026-02-05 22:56:58 +00:00
public function testManyToManyRelationship () : void
2022-06-20 22:24:51 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDatabase ();
2023-03-24 05:56:49 +00:00
$databaseId = $data [ 'databaseId' ];
// Create sports collection
2026-01-09 14:21:31 +00:00
$sports = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2022-06-24 12:18:10 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'Sports' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2023-03-24 05:56:49 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
2022-06-24 12:18:10 +00:00
]);
2023-03-24 05:56:49 +00:00
// Create sport name attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $sports [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 255 ,
'required' => true ,
]);
2022-06-24 12:18:10 +00:00
2023-03-24 05:56:49 +00:00
// Create player collection
2026-01-09 14:21:31 +00:00
$players = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2022-06-20 22:33:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-03-24 05:56:49 +00:00
'name' => 'Players' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2022-08-13 14:10:28 +00:00
'permissions' => [
2023-03-24 05:56:49 +00:00
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
2022-08-13 14:10:28 +00:00
],
2022-06-20 22:33:26 +00:00
]);
2023-03-24 05:56:49 +00:00
// Create player name attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $players [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2022-06-20 22:33:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2023-03-24 05:56:49 +00:00
'key' => 'name' ,
'size' => 255 ,
2022-06-20 22:33:26 +00:00
'required' => true ,
]);
2023-03-24 05:56:49 +00:00
// Create relationship
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $sports [ 'body' ][ '$id' ]) . '/relationship' , array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => $players [ 'body' ][ '$id' ],
2023-03-24 05:56:49 +00:00
'type' => Database :: RELATION_MANY_TO_MANY ,
'twoWay' => true ,
'key' => 'players' ,
'twoWayKey' => 'sports' ,
'onDelete' => Database :: RELATION_MUTATE_SET_NULL ,
]);
2022-06-20 22:33:26 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 202 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'players' , $response [ 'body' ][ 'key' ]);
$this -> assertEquals ( 'relationship' , $response [ 'body' ][ 'type' ]);
$this -> assertEquals ( false , $response [ 'body' ][ 'required' ]);
$this -> assertEquals ( false , $response [ 'body' ][ 'array' ]);
$this -> assertEquals ( 'manyToMany' , $response [ 'body' ][ 'relationType' ]);
$this -> assertEquals ( true , $response [ 'body' ][ 'twoWay' ]);
$this -> assertEquals ( 'sports' , $response [ 'body' ][ 'twoWayKey' ]);
$this -> assertEquals ( 'setNull' , $response [ 'body' ][ 'onDelete' ]);
2022-06-20 22:33:26 +00:00
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $sports [ 'body' ][ '$id' ], 'players' );
2023-03-24 05:56:49 +00:00
$permissions = [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
];
// Create sport
2026-01-09 14:21:31 +00:00
$sport = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $sports [ 'body' ][ '$id' ]), array_merge ([
2022-06-20 22:24:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => 'sport1' ,
2023-03-24 05:56:49 +00:00
'permissions' => $permissions ,
2022-06-20 22:24:51 +00:00
'data' => [
2023-03-24 05:56:49 +00:00
'name' => 'Sport 1' ,
'players' => [
[
'$id' => 'player1' ,
'name' => 'Player 1' ,
],
[
'$id' => 'player2' ,
'name' => 'Player 2' ,
]
],
2022-08-02 09:18:49 +00:00
],
2022-06-20 22:24:51 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 201 , $sport [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'sport1' , $sport [ 'body' ][ '$id' ]);
$this -> assertEquals ( 'Sport 1' , $sport [ 'body' ][ 'name' ]);
$this -> assertEquals ( 'Player 1' , $sport [ 'body' ][ 'players' ][ 0 ][ 'name' ]);
$this -> assertEquals ( 'Player 2' , $sport [ 'body' ][ 'players' ][ 1 ][ 'name' ]);
$this -> assertEquals ( $permissions , $sport [ 'body' ][ '$permissions' ]);
$this -> assertEquals ( $permissions , $sport [ 'body' ][ 'players' ][ 0 ][ '$permissions' ]);
$this -> assertEquals ( $permissions , $sport [ 'body' ][ 'players' ][ 1 ][ '$permissions' ]);
2022-06-20 22:24:51 +00:00
2026-01-09 14:21:31 +00:00
$sport = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $sports [ 'body' ][ '$id' ], 'sport1' ), array_merge ([
2023-03-24 05:56:49 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-06-09 08:53:04 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:44:02 +00:00
Query :: select ([ '*' , 'players.name' , 'players.$permissions' ]) -> toString ()
2025-06-09 08:53:04 +00:00
]
]);
2022-06-20 22:24:51 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $sport [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'sport1' , $sport [ 'body' ][ '$id' ]);
$this -> assertEquals ( 'Sport 1' , $sport [ 'body' ][ 'name' ]);
$this -> assertEquals ( 'Player 1' , $sport [ 'body' ][ 'players' ][ 0 ][ 'name' ]);
$this -> assertEquals ( 'Player 2' , $sport [ 'body' ][ 'players' ][ 1 ][ 'name' ]);
$this -> assertEquals ( $permissions , $sport [ 'body' ][ '$permissions' ]);
$this -> assertEquals ( $permissions , $sport [ 'body' ][ 'players' ][ 0 ][ '$permissions' ]);
$this -> assertEquals ( $permissions , $sport [ 'body' ][ 'players' ][ 1 ][ '$permissions' ]);
2026-01-09 14:21:31 +00:00
$player = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $players [ 'body' ][ '$id' ], $sport [ 'body' ][ 'players' ][ 0 ][ '$id' ]), array_merge ([
2022-06-20 22:24:51 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-06-09 08:53:04 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:44:02 +00:00
Query :: select ([ '*' , 'sports.$id' , 'sports.name' , 'sports.$permissions' ]) -> toString ()
2025-06-09 08:53:04 +00:00
]
]);
2022-06-20 22:24:51 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $player [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Player 1' , $player [ 'body' ][ 'name' ]);
$this -> assertEquals ( $permissions , $player [ 'body' ][ '$permissions' ]);
$this -> assertEquals ( 1 , count ( $player [ 'body' ][ 'sports' ]));
$this -> assertEquals ( 'sport1' , $player [ 'body' ][ 'sports' ][ 0 ][ '$id' ]);
$this -> assertEquals ( 'Sport 1' , $player [ 'body' ][ 'sports' ][ 0 ][ 'name' ]);
$this -> assertEquals ( $permissions , $player [ 'body' ][ 'sports' ][ 0 ][ '$permissions' ]);
}
2026-02-05 22:56:58 +00:00
public function testValidateOperators () : void
2023-03-24 05:56:49 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupOneToManyRelationship ();
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ 'personCollection' ]), array_merge ([
2022-06-22 23:38:56 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2023-03-24 05:56:49 +00:00
'queries' => [
2023-12-20 10:55:09 +00:00
Query :: isNotNull ( '$id' ) -> toString (),
2025-06-09 08:53:04 +00:00
Query :: select ([ '*' , 'libraries.*' ]) -> toString (),
2023-12-20 10:55:09 +00:00
Query :: startsWith ( 'fullName' , 'Stevie' ) -> toString (),
Query :: endsWith ( 'fullName' , 'Wonder' ) -> toString (),
2024-05-09 03:08:27 +00:00
Query :: between ( '$createdAt' , '1975-12-06' , '2050-12-01' ) -> toString (),
2022-08-02 09:18:49 +00:00
],
2022-06-22 23:38:56 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 1 , count ( $response [ 'body' ][ $this -> getRecordResource ()]));
2026-02-09 02:28:38 +00:00
$this -> assertNotEmpty ( $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'Stevie Wonder' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'fullName' ]);
$this -> assertEquals ( 2 , count ( $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'libraries' ]));
2022-06-22 23:38:56 +00:00
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ 'personCollection' ]), array_merge ([
2022-06-22 23:38:56 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
'queries' => [
2023-12-20 10:55:09 +00:00
Query :: isNotNull ( '$id' ) -> toString (),
Query :: isNull ( 'fullName' ) -> toString (),
Query :: select ([ 'fullName' ]) -> toString (),
2023-03-24 05:56:49 +00:00
],
]);
2022-06-22 23:38:56 +00:00
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-02-09 01:20:42 +00:00
$this -> assertGreaterThanOrEqual ( 2 , count ( $response [ 'body' ][ $this -> getRecordResource ()]));
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( null , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'fullName' ]);
$this -> assertArrayNotHasKey ( " libraries " , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ]);
$this -> assertArrayHasKey ( '$databaseId' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ]);
$this -> assertArrayHasKey ( $this -> getContainerIdResponseKey (), $response [ 'body' ][ $this -> getRecordResource ()][ 0 ]);
2022-06-20 22:24:51 +00:00
}
2022-09-30 09:27:19 +00:00
2026-02-05 22:56:58 +00:00
public function testSelectQueries () : void
2022-09-30 09:27:19 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupOneToManyRelationship ();
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ 'personCollection' ]), array_merge ([
2022-09-30 09:27:19 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
'queries' => [
2023-12-20 10:55:09 +00:00
Query :: equal ( 'fullName' , [ 'Stevie Wonder' ]) -> toString (),
Query :: select ([ 'fullName' ]) -> toString (),
2023-03-24 05:56:49 +00:00
],
2022-09-30 09:27:19 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertArrayNotHasKey ( 'libraries' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ]);
$this -> assertArrayHasKey ( '$databaseId' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ]);
$this -> assertArrayHasKey ( $this -> getContainerIdResponseKey (), $response [ 'body' ][ $this -> getRecordResource ()][ 0 ]);
2022-09-30 09:27:19 +00:00
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ 'personCollection' ]), array_merge ([
2022-09-30 09:27:19 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:40:59 +00:00
Query :: select ([ 'libraries.*' , '$id' ]) -> toString (),
2023-03-24 05:56:49 +00:00
],
2022-09-30 09:27:19 +00:00
]);
2026-01-09 14:21:31 +00:00
$document = $response [ 'body' ][ $this -> getRecordResource ()][ 0 ];
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertArrayHasKey ( 'libraries' , $document );
2025-09-19 03:28:41 +00:00
$this -> assertArrayHasKey ( '$databaseId' , $document );
2026-01-09 14:21:31 +00:00
$this -> assertArrayHasKey ( $this -> getContainerIdResponseKey (), $document );
2022-09-30 09:27:19 +00:00
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ 'personCollection' ], $document [ '$id' ]), array_merge ([
2022-09-30 09:27:19 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2023-03-24 05:56:49 +00:00
], $this -> getHeaders ()), [
'queries' => [
2025-06-12 03:40:59 +00:00
Query :: select ([ 'fullName' , '$id' ]) -> toString (),
2023-03-24 05:56:49 +00:00
],
2022-09-30 09:27:19 +00:00
]);
2023-03-24 05:56:49 +00:00
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertArrayHasKey ( 'fullName' , $response [ 'body' ]);
$this -> assertArrayNotHasKey ( 'libraries' , $response [ 'body' ]);
2022-09-30 09:27:19 +00:00
}
2023-05-02 08:27:09 +00:00
2024-04-23 03:20:25 +00:00
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testOrQueries () : void
{
// Create database
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2024-04-23 03:20:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Or queries'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Or queries' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
2026-01-09 14:21:31 +00:00
$presidents = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2024-04-23 03:20:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2024-04-23 03:20:25 +00:00
'name' => 'USA Presidents' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2024-04-23 03:20:25 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $presidents [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $presidents [ 'body' ][ 'name' ], 'USA Presidents' );
// Create Attributes
2026-01-09 14:21:31 +00:00
$firstName = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $presidents [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2024-04-23 03:20:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'first_name' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $firstName [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$lastName = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $presidents [ 'body' ][ '$id' ]) . '/string' , array_merge ([
2024-04-23 03:20:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'last_name' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $lastName [ 'headers' ][ 'status-code' ]);
// Wait for worker
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $presidents [ 'body' ][ '$id' ]);
2024-04-23 03:20:25 +00:00
2026-01-09 14:21:31 +00:00
$document1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $presidents [ 'body' ][ '$id' ]), array_merge ([
2024-04-23 03:20:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2024-04-23 03:20:25 +00:00
'data' => [
'first_name' => 'Donald' ,
'last_name' => 'Trump' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $document1 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$document2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $presidents [ 'body' ][ '$id' ]), array_merge ([
2024-04-23 03:20:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2024-04-23 03:20:25 +00:00
'data' => [
'first_name' => 'George' ,
'last_name' => 'Bush' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $document2 [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$document3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $presidents [ 'body' ][ '$id' ]), array_merge ([
2024-04-23 03:20:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2024-04-23 03:20:25 +00:00
'data' => [
'first_name' => 'Joe' ,
'last_name' => 'Biden' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $document3 [ 'headers' ][ 'status-code' ]);
$documents = $this -> client -> call (
Client :: METHOD_GET ,
2026-01-09 14:21:31 +00:00
$this -> getRecordUrl ( $databaseId , $presidents [ 'body' ][ '$id' ]),
2024-04-23 03:20:25 +00:00
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
2025-06-12 03:40:59 +00:00
Query :: select ([ 'first_name' , 'last_name' ]) -> toString (),
2024-04-23 03:20:25 +00:00
Query :: or ([
Query :: equal ( 'first_name' , [ 'Donald' ]),
Query :: equal ( 'last_name' , [ 'Bush' ])
]) -> toString (),
Query :: limit ( 999 ) -> toString (),
Query :: offset ( 0 ) -> toString ()
],
]
);
$this -> assertEquals ( 200 , $documents [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 2 , $documents [ 'body' ][ $this -> getRecordResource ()]);
2024-04-23 03:20:25 +00:00
}
2023-05-02 08:27:09 +00:00
/**
* @ return void
* @ throws \Exception
*/
2026-02-04 12:30:52 +00:00
public function testUpdateWithExistingRelationships () : void
2023-05-02 08:27:09 +00:00
{
2026-02-04 12:30:52 +00:00
// Create a new database for this test to be self-contained
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Relationships Test Database'
]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$databaseId = $database [ 'body' ][ '$id' ];
2023-05-02 08:27:09 +00:00
2026-01-09 14:21:31 +00:00
$collection1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2023-05-02 08:27:09 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-05-02 08:27:09 +00:00
'name' => 'Collection1' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2023-05-02 08:27:09 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
2026-01-09 14:21:31 +00:00
$collection2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2023-05-02 08:27:09 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-05-02 08:27:09 +00:00
'name' => 'Collection2' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2023-05-02 08:27:09 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$collection1 = $collection1 [ 'body' ][ '$id' ];
$collection2 = $collection2 [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collection1 ) . '/string' , array_merge ([
2023-05-02 08:27:09 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => '49' ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collection2 ) . '/string' , array_merge ([
2023-05-02 08:27:09 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => '49' ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collection1 ) . '/relationship' , array_merge ([
2023-05-02 08:27:09 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => $collection2 ,
2023-05-02 08:27:09 +00:00
'type' => Database :: RELATION_ONE_TO_MANY ,
'twoWay' => true ,
'key' => 'collection2'
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $collection1 , 'collection2' );
2023-05-02 08:27:09 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collection1 ), array_merge ([
2023-05-02 08:27:09 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ]
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-05-02 08:27:09 +00:00
'data' => [
'name' => 'Document 1' ,
'collection2' => [
[
'name' => 'Document 2' ,
],
],
],
]);
2026-01-09 14:21:31 +00:00
$update = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collection1 , $document [ 'body' ][ '$id' ]), array_merge ([
2023-05-02 08:27:09 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ]
], $this -> getHeaders ()), [
'data' => [
'name' => 'Document 1 Updated' ,
],
]);
$this -> assertEquals ( 200 , $update [ 'headers' ][ 'status-code' ]);
}
2023-10-19 04:06:57 +00:00
2026-02-05 22:56:58 +00:00
public function testTimeout () : void
2023-10-19 04:06:57 +00:00
{
2026-02-05 22:56:58 +00:00
$data = $this -> setupDatabase ();
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $data [ 'databaseId' ]), array_merge ([
2023-10-19 04:06:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2023-10-19 04:06:57 +00:00
'name' => 'Slow Queries' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2023-10-19 04:06:57 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$data = [
'$id' => $collection [ 'body' ][ '$id' ],
'databaseId' => $collection [ 'body' ][ 'databaseId' ]
];
2026-01-09 14:21:31 +00:00
$longtext = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $data [ 'databaseId' ], $data [ '$id' ]) . '/string' , array_merge ([
2023-10-19 04:06:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'longtext' ,
'size' => 100000000 ,
'required' => false ,
'default' => null ,
]);
$this -> assertEquals ( $longtext [ 'headers' ][ 'status-code' ], 202 );
2024-06-24 05:58:29 +00:00
for ( $i = 0 ; $i < 10 ; $i ++ ) {
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ '$id' ]), array_merge ([
2023-10-19 04:06:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2023-10-19 04:06:57 +00:00
'data' => [
2026-01-09 14:21:31 +00:00
'longtext' => file_get_contents ( __DIR__ . '/../../../resources/longtext.txt' ),
2023-10-19 04:06:57 +00:00
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
}
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $data [ 'databaseId' ], $data [ '$id' ]), array_merge ([
2023-10-19 04:06:57 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-timeout' => 1 ,
], $this -> getHeaders ()), [
2023-12-20 10:55:09 +00:00
'queries' => [
Query :: notEqual ( 'longtext' , 'appwrite' ) -> toString (),
],
2023-10-19 04:06:57 +00:00
]);
$this -> assertEquals ( 408 , $response [ 'headers' ][ 'status-code' ]);
2024-11-08 07:17:29 +00:00
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $data [ 'databaseId' ]), array_merge ([
2024-11-08 07:17:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2023-10-19 04:06:57 +00:00
}
2025-06-10 03:56:30 +00:00
/**
* @ throws \Exception
*/
2025-06-10 04:22:38 +00:00
public function testIncrementAttribute () : void
2025-06-10 03:56:30 +00:00
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'CounterDatabase'
]);
$databaseId = $database [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-06-10 03:56:30 +00:00
'name' => 'CounterCollection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-06-10 03:56:30 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Add integer attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'count' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $collectionId , 'count' );
2025-06-10 03:56:30 +00:00
// Create document with initial count = 5
2026-01-09 14:21:31 +00:00
$doc = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-06-10 04:22:38 +00:00
'data' => [
'count' => 5
],
2025-06-10 03:56:30 +00:00
'permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
],
]);
$this -> assertEquals ( 201 , $doc [ 'headers' ][ 'status-code' ]);
2025-06-12 00:41:02 +00:00
$docId = $doc [ 'body' ][ '$id' ];
2025-06-10 03:56:30 +00:00
// Increment by default 1
2026-01-09 14:21:31 +00:00
$inc = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $docId ) . " /count/increment " , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]));
$this -> assertEquals ( 200 , $inc [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 6 , $inc [ 'body' ][ 'count' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $collectionId , $inc [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2026-01-04 06:39:11 +00:00
$this -> assertEquals ( $databaseId , $inc [ 'body' ][ '$databaseId' ]);
2025-06-10 03:56:30 +00:00
// Verify count = 6
2026-01-09 14:21:31 +00:00
$get = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId , $docId ), array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 6 , $get [ 'body' ][ 'count' ]);
// Increment by custom value 4
2026-01-09 14:21:31 +00:00
$inc2 = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $docId ) . " /count/increment " , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'value' => 4
]);
$this -> assertEquals ( 200 , $inc2 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 10 , $inc2 [ 'body' ][ 'count' ]);
2026-01-09 14:21:31 +00:00
$get2 = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId , $docId ), array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 10 , $get2 [ 'body' ][ 'count' ]);
// Test max limit exceeded
2026-01-09 14:21:31 +00:00
$err = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $docId ) . " /count/increment " , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [ 'max' => 8 ]);
$this -> assertEquals ( 400 , $err [ 'headers' ][ 'status-code' ]);
// Test attribute not found
2026-01-09 14:21:31 +00:00
$notFound = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $docId ) . " /unknown/increment " , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]));
$this -> assertEquals ( 404 , $notFound [ 'headers' ][ 'status-code' ]);
2025-08-14 07:22:38 +00:00
// Test increment with value 0
2026-01-09 14:21:31 +00:00
$inc3 = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $docId ) . " /count/increment " , array_merge ([
2025-08-14 07:22:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'value' => 0
]);
$this -> assertEquals ( 400 , $inc3 [ 'headers' ][ 'status-code' ]);
2025-06-10 03:56:30 +00:00
}
2025-06-10 04:22:38 +00:00
public function testDecrementAttribute () : void
2025-06-10 03:56:30 +00:00
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'CounterDatabase'
]);
$databaseId = $database [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-06-10 03:56:30 +00:00
'name' => 'CounterCollection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-06-10 03:56:30 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Add integer attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'count' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $collectionId , 'count' );
2025-06-10 03:56:30 +00:00
// Create document with initial count = 10
2026-01-09 14:21:31 +00:00
$doc = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-06-10 03:56:30 +00:00
'data' => [ 'count' => 10 ],
'permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
],
]);
2025-06-10 04:22:38 +00:00
$documentId = $doc [ 'body' ][ '$id' ];
2025-06-10 03:56:30 +00:00
// Decrement by default 1 (count = 10 -> 9)
2026-01-09 14:21:31 +00:00
$dec = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ) . '/count/decrement' , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]));
$this -> assertEquals ( 200 , $dec [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 9 , $dec [ 'body' ][ 'count' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( $collectionId , $dec [ 'body' ][ $this -> getContainerIdResponseKey ()]);
2026-01-04 06:39:11 +00:00
$this -> assertEquals ( $databaseId , $dec [ 'body' ][ '$databaseId' ]);
2025-06-10 03:56:30 +00:00
2026-01-09 14:21:31 +00:00
$get = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 9 , $get [ 'body' ][ 'count' ]);
// Decrement by custom value 3 (count 9 -> 6)
2026-01-09 14:21:31 +00:00
$dec2 = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ) . '/count/decrement' , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'value' => 3
]);
$this -> assertEquals ( 200 , $dec2 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 6 , $dec2 [ 'body' ][ 'count' ]);
2026-01-09 14:21:31 +00:00
$get2 = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 6 , $get2 [ 'body' ][ 'count' ]);
// Test min limit exceeded
2026-01-09 14:21:31 +00:00
$err = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ) . '/count/decrement' , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [ 'min' => 7 ]);
$this -> assertEquals ( 400 , $err [ 'headers' ][ 'status-code' ]);
2025-08-05 08:38:26 +00:00
// Test min limit exceeded with custom value
2026-01-09 14:21:31 +00:00
$err = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ) . '/count/decrement' , array_merge ([
2025-08-05 08:38:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'value' => 3 ,
'min' => 5 ,
]);
$this -> assertEquals ( 400 , $err [ 'headers' ][ 'status-code' ]);
// Test min limit 0
2026-01-09 14:21:31 +00:00
$err = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ) . '/count/decrement' , array_merge ([
2025-08-05 08:38:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'value' => 10 ,
'min' => 0 ,
]);
$this -> assertEquals ( 400 , $err [ 'headers' ][ 'status-code' ]);
2025-06-12 14:28:28 +00:00
// Test type error on non-numeric attribute
2026-01-09 14:21:31 +00:00
$typeErr = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ) . '/count/decrement' , array_merge ([
2025-06-10 03:56:30 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [ 'value' => 'not-a-number' ]);
$this -> assertEquals ( 400 , $typeErr [ 'headers' ][ 'status-code' ]);
2025-08-14 07:22:38 +00:00
// Test decrement with value 0
2026-01-09 14:21:31 +00:00
$inc3 = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ) . " /count/increment " , array_merge ([
2025-08-14 07:22:38 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
]), [
'value' => 0
]);
$this -> assertEquals ( 400 , $inc3 [ 'headers' ][ 'status-code' ]);
2025-06-10 03:56:30 +00:00
}
2025-08-26 10:03:26 +00:00
public function testSpatialPointAttributes () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial Point Test Database'
]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection with spatial and non-spatial attributes
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'name' => 'Spatial Point Collection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:03:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create string attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 256 ,
'required' => true ,
]);
// Create point attribute - handle both 201 (created) and 200 (already exists)
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'location' ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $response [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-08-26 10:03:26 +00:00
// Test 1: Create document with point attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'name' => 'Test Location' ,
'location' => [ 40.7128 , - 74.0060 ] // New York coordinates
]
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 40.7128 , - 74.0060 ], $response [ 'body' ][ 'location' ]);
$documentId = $response [ 'body' ][ '$id' ];
// Test 2: Read document with point attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 40.7128 , - 74.0060 ], $response [ 'body' ][ 'location' ]);
// Test 3: Update document with new point coordinates
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'location' => [ 40.7589 , - 73.9851 ] // Times Square coordinates
]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 40.7589 , - 73.9851 ], $response [ 'body' ][ 'location' ]);
// Test 4: Upsert document with point attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . ID :: unique (), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'name' => 'Upserted Location' ,
2025-09-11 16:25:36 +00:00
'location' => [ 34.0522 , - 80 ] // Los Angeles coordinates
2025-08-26 10:03:26 +00:00
]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2025-09-11 16:25:36 +00:00
$this -> assertEquals ([ 34.0522 , - 80 ], $response [ 'body' ][ 'location' ]);
2025-08-26 10:03:26 +00:00
// Test 5: Create document without permissions (should fail)
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), [
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'name' => 'Unauthorized Location' ,
'location' => [ 0 , 0 ]
]
]);
$this -> assertEquals ( 401 , $response [ 'headers' ][ 'status-code' ]);
// Cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
public function testSpatialLineAttributes () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial Line Test Database'
]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection with spatial and non-spatial attributes
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'name' => 'Spatial Line Collection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:03:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create integer attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/integer' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'distance' ,
'required' => true ,
]);
// Create line attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/line' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'route' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-08-26 10:03:26 +00:00
// Test 1: Create document with line attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'distance' => 100 ,
'route' => [[ 40.7128 , - 74.0060 ], [ 40.7589 , - 73.9851 ]] // Line from Downtown to Times Square
]
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([[ 40.7128 , - 74.0060 ], [ 40.7589 , - 73.9851 ]], $response [ 'body' ][ 'route' ]);
$documentId = $response [ 'body' ][ '$id' ];
// Test 2: Read document with line attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([[ 40.7128 , - 74.0060 ], [ 40.7589 , - 73.9851 ]], $response [ 'body' ][ 'route' ]);
// Test 3: Update document with new line coordinates
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'route' => [[ 40.7128 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7505 , - 73.9934 ]] // Extended route
]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([[ 40.7128 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7505 , - 73.9934 ]], $response [ 'body' ][ 'route' ]);
// Test 4: Upsert document with line attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . ID :: unique (), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'distance' => 200 ,
2025-09-11 16:25:36 +00:00
'route' => [[ 34.0522 , - 80 ], [ 34.0736 , - 90 ]] // LA route
2025-08-26 10:03:26 +00:00
]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2025-09-11 16:25:36 +00:00
$this -> assertEquals ([[ 34.0522 , - 80 ], [ 34.0736 , - 90 ]], $response [ 'body' ][ 'route' ]);
2025-08-26 10:03:26 +00:00
// Test 5: Delete document
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_DELETE , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 204 , $response [ 'headers' ][ 'status-code' ]);
// Test 6: Verify document is deleted
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 404 , $response [ 'headers' ][ 'status-code' ]);
// Cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
public function testSpatialPolygonAttributes () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial Polygon Test Database'
]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection with spatial and non-spatial attributes
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'name' => 'Spatial Polygon Collection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:03:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create boolean attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/boolean' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'active' ,
'required' => true ,
]);
// Create polygon attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/polygon' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'area' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-08-26 10:03:26 +00:00
// Test 1: Create document with polygon attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'active' => true ,
'area' => [[[ 40.7128 , - 74.0060 ], [ 40.7589 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7128 , - 73.9851 ], [ 40.7128 , - 74.0060 ]]] // Manhattan area
]
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([[[ 40.7128 , - 74.0060 ], [ 40.7589 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7128 , - 73.9851 ], [ 40.7128 , - 74.0060 ]]], $response [ 'body' ][ 'area' ]);
$documentId = $response [ 'body' ][ '$id' ];
// Test 2: Read document with polygon attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([[[ 40.7128 , - 74.0060 ], [ 40.7589 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7128 , - 73.9851 ], [ 40.7128 , - 74.0060 ]]], $response [ 'body' ][ 'area' ]);
// Test 3: Update document with new polygon coordinates
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'area' => [[[ 40.7128 , - 74.0060 ], [ 40.7589 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7128 , - 73.9851 ], [ 40.7505 , - 73.9934 ], [ 40.7128 , - 74.0060 ]]] // Extended area
]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([[[ 40.7128 , - 74.0060 ], [ 40.7589 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7128 , - 73.9851 ], [ 40.7505 , - 73.9934 ], [ 40.7128 , - 74.0060 ]]], $response [ 'body' ][ 'area' ]);
// Test 4: Upsert document with polygon attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PUT , $this -> getContainerUrl ( $databaseId , $collectionId ) . '/' . $this -> getRecordResource () . '/' . ID :: unique (), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'active' => false ,
2025-09-11 16:25:36 +00:00
'area' => [[[ 34.0522 , - 80 ], [ 34.0736 , - 80 ], [ 34.0736 , - 90 ], [ 34.0522 , - 90 ], [ 34.0522 , - 80 ]]] // LA area
2025-08-26 10:03:26 +00:00
]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2025-09-11 16:25:36 +00:00
$this -> assertEquals ([[[ 34.0522 , - 80 ], [ 34.0736 , - 80 ], [ 34.0736 , - 90 ], [ 34.0522 , - 90 ], [ 34.0522 , - 80 ]]], $response [ 'body' ][ 'area' ]);
2025-08-26 10:03:26 +00:00
// Test 5: Create document without required polygon attribute (should fail)
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'active' => true
// Missing required 'area' attribute
]
]);
$this -> assertEquals ( 400 , $response [ 'headers' ][ 'status-code' ]);
// Cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
public function testSpatialAttributesMixedCollection () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Mixed Spatial Test Database'
]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection with multiple spatial and non-spatial attributes
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'name' => 'Mixed Spatial Collection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:03:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create multiple attributes
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 256 ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'center' ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/line' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'boundary' ,
'required' => false ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/polygon' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'coverage' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-08-26 10:03:26 +00:00
// Test 1: Create document with all spatial attributes
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'name' => 'Central Park' ,
'center' => [ 40.7829 , - 73.9654 ],
'boundary' => [[ 40.7649 , - 73.9814 ], [ 40.8009 , - 73.9494 ]],
'coverage' => [[[ 40.7649 , - 73.9814 ], [ 40.8009 , - 73.9814 ], [ 40.8009 , - 73.9494 ], [ 40.7649 , - 73.9494 ], [ 40.7649 , - 73.9814 ]]]
]
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 40.7829 , - 73.9654 ], $response [ 'body' ][ 'center' ]);
$this -> assertEquals ([[ 40.7649 , - 73.9814 ], [ 40.8009 , - 73.9494 ]], $response [ 'body' ][ 'boundary' ]);
$this -> assertEquals ([[[ 40.7649 , - 73.9814 ], [ 40.8009 , - 73.9814 ], [ 40.8009 , - 73.9494 ], [ 40.7649 , - 73.9494 ], [ 40.7649 , - 73.9814 ]]], $response [ 'body' ][ 'coverage' ]);
$documentId = $response [ 'body' ][ '$id' ];
// Test 2: Update document with new spatial data
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getRecordUrl ( $databaseId , $collectionId , $documentId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'center' => [ 40.7505 , - 73.9934 ],
'boundary' => [[ 40.7305 , - 74.0134 ], [ 40.7705 , - 73.9734 ]],
'coverage' => [[[ 40.7305 , - 74.0134 ], [ 40.7705 , - 74.0134 ], [ 40.7705 , - 73.9734 ], [ 40.7305 , - 73.9734 ], [ 40.7305 , - 74.0134 ]]]
]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 40.7505 , - 73.9934 ], $response [ 'body' ][ 'center' ]);
$this -> assertEquals ([[ 40.7305 , - 74.0134 ], [ 40.7705 , - 73.9734 ]], $response [ 'body' ][ 'boundary' ]);
$this -> assertEquals ([[[ 40.7305 , - 74.0134 ], [ 40.7705 , - 74.0134 ], [ 40.7705 , - 73.9734 ], [ 40.7305 , - 73.9734 ], [ 40.7305 , - 74.0134 ]]], $response [ 'body' ][ 'coverage' ]);
// Test 3: Create document with minimal required attributes
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'name' => 'Minimal Location' ,
'center' => [ 0 , 0 ],
'coverage' => [[[ 0 , 0 ], [ 1 , 0 ], [ 1 , 1 ], [ 0 , 1 ], [ 0 , 0 ]]]
]
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 0 , 0 ], $response [ 'body' ][ 'center' ]);
// Test 4: Test permission validation - create without user context
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), [
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'data' => [
'name' => 'Unauthorized Location' ,
'center' => [ 0 , 0 ],
'coverage' => [[[ 0 , 0 ], [ 1 , 0 ], [ 1 , 1 ], [ 0 , 1 ], [ 0 , 0 ]]]
]
]);
$this -> assertEquals ( 401 , $response [ 'headers' ][ 'status-code' ]);
// Cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-08-27 11:00:25 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
public function testUpdateSpatialAttributes () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Update Spatial Attributes Test Database'
]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection with spatial attributes
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-27 11:00:25 +00:00
'name' => 'Update Spatial Attributes Collection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-27 11:00:25 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create string attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 256 ,
'required' => true ,
]);
// Create point attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point' , array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'location' ,
'required' => true ,
]);
// Create line attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/line' , array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'route' ,
'required' => false ,
]);
// Create polygon attribute
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/polygon' , array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'area' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-08-27 11:00:25 +00:00
// Test 1: Update point attribute - change required status
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point/location' , array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'required' => false ,
'default' => null ,
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( false , $response [ 'body' ][ 'required' ]);
// Test 2: Update line attribute - change required status and add default value
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/line/route' , array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2025-08-27 12:11:52 +00:00
'required' => false ,
2025-09-05 10:45:17 +00:00
'default' => [[ 0 , 0 ], [ 1 , 1 ]],
2025-08-27 11:00:25 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2025-08-27 12:11:52 +00:00
$this -> assertEquals ( false , $response [ 'body' ][ 'required' ]);
$this -> assertEquals ([[ 0 , 0 ], [ 1 , 1 ]], $response [ 'body' ][ 'default' ]);
2025-08-27 11:00:25 +00:00
// Test 3: Update polygon attribute - change key name
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/polygon/area' , array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'newKey' => 'coverage' ,
'default' => null ,
'required' => false
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'coverage' , $response [ 'body' ][ 'key' ]);
// Test 4: Update point attribute - add default value
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point/location' , array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2025-09-05 10:45:17 +00:00
'default' => [ 0 , 0 ],
2025-08-27 12:11:52 +00:00
'required' => false
2025-08-27 11:00:25 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2025-08-27 12:11:52 +00:00
$this -> assertEquals ([ 0 , 0 ], $response [ 'body' ][ 'default' ]);
2025-08-27 11:00:25 +00:00
// Test 5: Verify attribute updates by creating a document
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-27 11:00:25 +00:00
'data' => [
'name' => 'Test Location' ,
'coverage' => [[[ 0 , 0 ], [ 10 , 0 ], [ 10 , 10 ], [ 0 , 10 ], [ 0 , 0 ]]]
]
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 0 , 0 ], $response [ 'body' ][ 'location' ]); // Should use default value
$this -> assertEquals ([[ 0 , 0 ], [ 1 , 1 ]], $response [ 'body' ][ 'route' ]); // Should use default value
// Cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-27 11:00:25 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
2025-08-26 10:03:26 +00:00
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
public function testSpatialQuery () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial Query Test Database'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection with spatial attributes
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:03:26 +00:00
'name' => 'Spatial Query Collection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:03:26 +00:00
'permissions' => [
Permission :: create ( Role :: any ()),
Permission :: read ( Role :: any ()),
Permission :: delete ( Role :: any ()),
Permission :: update ( Role :: any ()),
],
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create string attribute
2026-01-09 14:21:31 +00:00
$nameAttribute = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/string' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $nameAttribute [ 'headers' ][ 'status-code' ]);
// Create point attribute
2026-01-09 14:21:31 +00:00
$pointAttribute = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'pointAttr' ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $pointAttribute [ 'headers' ][ 'status-code' ]);
// Create line attribute
2026-01-09 14:21:31 +00:00
$lineAttribute = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/line' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'lineAttr' ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $lineAttribute [ 'headers' ][ 'status-code' ]);
// Create polygon attribute
2026-01-09 14:21:31 +00:00
$polygonAttribute = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/polygon' , array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'polyAttr' ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $polygonAttribute [ 'headers' ][ 'status-code' ]);
// Wait for attributes to be created
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-08-26 10:03:26 +00:00
// Create test documents with spatial data
$documents = [
[
'$id' => 'doc1' ,
'name' => 'Test Document 1' ,
'pointAttr' => [ 6.0 , 6.0 ],
2025-09-12 05:54:19 +00:00
'lineAttr' => [[ 1.0 , 1.0 ], [ 1.1 , 1.1 ] , [ 2.0 , 2.0 ]],
2025-08-26 10:03:26 +00:00
'polyAttr' => [[[ 0.0 , 0.0 ], [ 10.0 , 0.0 ], [ 10.0 , 10.0 ], [ 0.0 , 10.0 ], [ 0.0 , 0.0 ]]]
],
[
'$id' => 'doc2' ,
'name' => 'Test Document 2' ,
'pointAttr' => [ 7.0 , 6.0 ],
'lineAttr' => [[ 10.0 , 10.0 ], [ 20.0 , 20.0 ]],
'polyAttr' => [[[ 20.0 , 20.0 ], [ 30.0 , 20.0 ], [ 30.0 , 30.0 ], [ 20.0 , 30.0 ], [ 20.0 , 20.0 ]]]
],
[
'$id' => 'doc3' ,
'name' => 'Test Document 3' ,
'pointAttr' => [ 25.0 , 25.0 ],
'lineAttr' => [[ 25.0 , 25.0 ], [ 35.0 , 35.0 ]],
'polyAttr' => [[[ 40.0 , 40.0 ], [ 50.0 , 40.0 ], [ 50.0 , 50.0 ], [ 40.0 , 50.0 ], [ 40.0 , 40.0 ]]]
]
];
foreach ( $documents as $doc ) {
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => $doc [ '$id' ],
2025-08-26 10:03:26 +00:00
'data' => [
'name' => $doc [ 'name' ],
'pointAttr' => $doc [ 'pointAttr' ],
'lineAttr' => $doc [ 'lineAttr' ],
'polyAttr' => $doc [ 'polyAttr' ]
]
]);
$this -> assertEquals ( 201 , $response [ 'headers' ][ 'status-code' ]);
}
// Test 1: Equality on non-spatial attribute (name)
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: equal ( 'name' , [ 'Test Document 1' ]) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'doc1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-08-26 10:03:26 +00:00
// Test 3: Polygon attribute queries
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: equal ( 'polyAttr' , [[[[ 0.0 , 0.0 ], [ 10.0 , 0.0 ], [ 10.0 , 10.0 ], [ 0.0 , 10.0 ], [ 0.0 , 0.0 ]]]]) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'doc1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-08-26 10:03:26 +00:00
// Test 4: Not equal queries
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: notEqual ( 'pointAttr' , [[ 6.0 , 6.0 ]]) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 2 , $response [ 'body' ][ $this -> getRecordResource ()]);
2025-08-26 10:03:26 +00:00
2025-09-12 05:54:19 +00:00
// Test 4.1: contains on line (point on line)
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-12 05:54:19 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: contains ( 'lineAttr' , [[ 1.1 , 1.1 ]]) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'doc1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-09-12 05:54:19 +00:00
2025-08-26 10:03:26 +00:00
// Test 4.2: notContains on polygon (point outside all polygons)
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: notContains ( 'polyAttr' , [[ 15.0 , 15.0 ]]) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 3 , $response [ 'body' ][ 'total' ]);
// Test 4.3: intersects on polygon (point inside doc1 polygon)
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-09-09 17:26:59 +00:00
'queries' => [ Query :: intersects ( 'polyAttr' , [ 5.0 , 5.0 ]) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 1 , $response [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'doc1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-08-26 10:03:26 +00:00
// Test 4.4: notIntersects on polygon (point outside all polygons)
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-09-09 17:26:59 +00:00
'queries' => [ Query :: notIntersects ( 'polyAttr' , [ 60.0 , 60.0 ]) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 3 , $response [ 'body' ][ 'total' ]);
// Test 4.5: overlaps on polygon (polygon overlapping doc1)
$overlapPoly = [[[ 5.0 , 5.0 ], [ 12.0 , 5.0 ], [ 12.0 , 12.0 ], [ 5.0 , 12.0 ], [ 5.0 , 5.0 ]]];
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-09-09 17:26:59 +00:00
'queries' => [ Query :: overlaps ( 'polyAttr' , $overlapPoly ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 1 , $response [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'doc1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-08-26 10:03:26 +00:00
// Test 4.6: notOverlaps on polygon (polygon that overlaps none)
$noOverlapPoly = [[[ 60.0 , 60.0 ], [ 70.0 , 60.0 ], [ 70.0 , 70.0 ], [ 60.0 , 70.0 ], [ 60.0 , 60.0 ]]];
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-09-09 17:26:59 +00:00
'queries' => [ Query :: notOverlaps ( 'polyAttr' , $noOverlapPoly ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 3 , $response [ 'body' ][ 'total' ]);
// Test 4.7: distance (equals) on point
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-08-26 15:41:30 +00:00
'queries' => [ Query :: distanceEqual ( 'pointAttr' , [ 6.0 , 6.0 ], 1.0 ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 1 , $response [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'doc2' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-08-26 10:03:26 +00:00
// Test 4.8: notDistance (outside radius) on point
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-08-26 15:41:30 +00:00
'queries' => [ Query :: distanceNotEqual ( 'pointAttr' , [ 6.0 , 6.0 ], 1.0 ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2 , $response [ 'body' ][ 'total' ]);
// Test 4.9: distanceGreaterThan
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-08-26 15:41:30 +00:00
'queries' => [ Query :: distanceGreaterThan ( 'pointAttr' , [ 6.0 , 6.0 ], 5.0 ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 1 , $response [ 'body' ][ 'total' ]);
// Test 4.10: distanceLessThan
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-08-26 15:41:30 +00:00
'queries' => [ Query :: distanceLessThan ( 'pointAttr' , [ 6.0 , 6.0 ], 0.5 ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 1 , $response [ 'body' ][ 'total' ]);
// Test 4.11: crosses on line (query line crosses doc1 line)
$crossLine = [[ 1.0 , 2.0 ], [ 2.0 , 1.0 ]];
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-09-09 17:26:59 +00:00
'queries' => [ Query :: crosses ( 'lineAttr' , $crossLine ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 1 , $response [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'doc1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-08-26 10:03:26 +00:00
// Test 4.12: notCrosses on line (query line does not cross any stored lines)
$nonCrossLine = [[ 0.0 , 1.0 ], [ 0.0 , 2.0 ]];
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-09-09 17:26:59 +00:00
'queries' => [ Query :: notCrosses ( 'lineAttr' , $nonCrossLine ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 3 , $response [ 'body' ][ 'total' ]);
// Test 4.13: touches on polygon (query polygon touches doc1 polygon at corner)
$touchPoly = [[[ 10.0 , 10.0 ], [ 20.0 , 10.0 ], [ 20.0 , 20.0 ], [ 10.0 , 20.0 ], [ 10.0 , 10.0 ]]];
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-09-09 17:26:59 +00:00
'queries' => [ Query :: touches ( 'polyAttr' , $touchPoly ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 2 , $response [ 'body' ][ 'total' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'doc1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-08-26 10:03:26 +00:00
// Test 4.14: notTouches on polygon (polygon far away should not touch)
$farPoly = [[[ 60.0 , 60.0 ], [ 70.0 , 60.0 ], [ 70.0 , 70.0 ], [ 60.0 , 70.0 ], [ 60.0 , 60.0 ]]];
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2025-09-09 17:26:59 +00:00
'queries' => [ Query :: notTouches ( 'polyAttr' , $farPoly ) -> toString ()]
2025-08-26 10:03:26 +00:00
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 3 , $response [ 'body' ][ 'total' ]);
// Test 5: Select specific attributes
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: select ([ 'name' , 'pointAttr' ]) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 3 , $response [ 'body' ][ $this -> getRecordResource ()]);
2025-08-26 10:03:26 +00:00
2026-01-09 14:21:31 +00:00
foreach ( $response [ 'body' ][ $this -> getRecordResource ()] as $doc ) {
2025-08-26 10:03:26 +00:00
$this -> assertArrayHasKey ( 'name' , $doc );
$this -> assertArrayHasKey ( 'pointAttr' , $doc );
$this -> assertArrayNotHasKey ( 'lineAttr' , $doc );
$this -> assertArrayNotHasKey ( 'polyAttr' , $doc );
}
// Test 6: Order by name
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: orderAsc ( 'name' ) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 3 , $response [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Test Document 1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'name' ]);
$this -> assertEquals ( 'Test Document 2' , $response [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'name' ]);
$this -> assertEquals ( 'Test Document 3' , $response [ 'body' ][ $this -> getRecordResource ()][ 2 ][ 'name' ]);
2025-08-26 10:03:26 +00:00
// Test 7: Limit results
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: limit ( 2 ) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 2 , $response [ 'body' ][ $this -> getRecordResource ()]);
2025-08-26 10:03:26 +00:00
// Test 8: Offset results
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: offset ( 1 ) -> toString (), Query :: limit ( 2 ) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 2 , $response [ 'body' ][ $this -> getRecordResource ()]);
2025-08-26 10:03:26 +00:00
// Test 9: Complex query with multiple conditions
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: select ([ 'name' , 'pointAttr' ]) -> toString (),
Query :: orderAsc ( 'name' ) -> toString (),
Query :: limit ( 1 ) -> toString ()
]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $response [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Test Document 1' , $response [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'name' ]);
2025-08-26 10:03:26 +00:00
// Test 11: Query with no results
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: equal ( 'name' , [ 'Non-existent Document' ]) -> toString ()]
]);
$this -> assertEquals ( 200 , $response [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 0 , $response [ 'body' ][ $this -> getRecordResource ()]);
2025-08-26 10:03:26 +00:00
// Cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:03:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
2025-08-26 10:45:26 +00:00
public function testSpatialRelationshipOneToOne () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial OneToOne Test DB'
]);
$databaseId = $database [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$place = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'name' => 'Place' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:45:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$placeId = $place [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$location = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'name' => 'Location' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:45:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$locationId = $location [ 'body' ][ '$id' ];
// attributes
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $placeId ) . '/string' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 255 ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $locationId ) . '/point' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'coordinates' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $locationId , 'coordinates' );
2025-08-26 10:45:26 +00:00
// relationship: place.oneToOne -> location
2026-01-09 14:21:31 +00:00
$relation = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $placeId ) . '/relationship' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => $locationId ,
2025-08-26 10:45:26 +00:00
'type' => Database :: RELATION_ONE_TO_ONE ,
'key' => 'location' ,
'twoWay' => true ,
'twoWayKey' => 'place' ,
'onDelete' => Database :: RELATION_MUTATE_CASCADE ,
]);
$this -> assertEquals ( 202 , $relation [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $placeId , 'location' );
2025-08-26 10:45:26 +00:00
// create doc with nested spatial related doc
2026-01-09 14:21:31 +00:00
$doc = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $placeId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'data' => [
'name' => 'Museum' ,
'location' => [
'$id' => ID :: unique (),
'coordinates' => [ 40.7794 , - 73.9632 ],
],
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $doc [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 40.7794 , - 73.9632 ], $doc [ 'body' ][ 'location' ][ 'coordinates' ]);
// fetch with select to ensure relationship shape
2026-01-09 14:21:31 +00:00
$fetched = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $placeId ) . '/' . $this -> getRecordResource () . '/' . $doc [ 'body' ][ '$id' ], array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: select ([ 'name' , 'location.coordinates' ]) -> toString ()
]
]);
$this -> assertEquals ( 200 , $fetched [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ([ 40.7794 , - 73.9632 ], $fetched [ 'body' ][ 'location' ][ 'coordinates' ]);
// cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $placeId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $locationId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
public function testSpatialRelationshipOneToMany () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial OneToMany Test DB'
]);
$databaseId = $database [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$person = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'name' => 'Person' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:45:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$personId = $person [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$visit = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'name' => 'Visit' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:45:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$visitId = $visit [ 'body' ][ '$id' ];
// attributes
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $personId ) . '/string' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'fullName' ,
'size' => 255 ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $visitId ) . '/point' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'point' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $visitId , 'point' );
2025-08-26 10:45:26 +00:00
// relationship person.oneToMany -> visit
2026-01-09 14:21:31 +00:00
$rel = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $personId ) . '/relationship' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => $visitId ,
2025-08-26 10:45:26 +00:00
'type' => Database :: RELATION_ONE_TO_MANY ,
'key' => 'visits' ,
'twoWay' => true ,
'twoWayKey' => 'person' ,
]);
$this -> assertEquals ( 202 , $rel [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $personId , 'visits' );
2025-08-26 10:45:26 +00:00
2026-01-09 14:21:31 +00:00
$personDoc = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $personId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => 'person-spatial-1' ,
2025-08-26 10:45:26 +00:00
'data' => [
'fullName' => 'Alice' ,
'visits' => [
[ '$id' => 'visit-1' , 'point' => [ 40.7589 , - 73.9851 ] ],
[ '$id' => 'visit-2' , 'point' => [ 40.7505 , - 73.9934 ] ],
],
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $personDoc [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 2 , $personDoc [ 'body' ][ 'visits' ]);
$this -> assertEquals ([ 40.7589 , - 73.9851 ], $personDoc [ 'body' ][ 'visits' ][ 0 ][ 'point' ]);
2026-01-09 14:21:31 +00:00
$visitDoc = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $visitId ) . '/' . $this -> getRecordResource () . '/visit-2' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: select ([ 'point' , 'person.$id' ]) -> toString ()
]
]);
$this -> assertEquals ( 200 , $visitDoc [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'person-spatial-1' , $visitDoc [ 'body' ][ 'person' ][ '$id' ]);
// cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $personId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $visitId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
public function testSpatialRelationshipManyToOne () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial ManyToOne Test DB'
]);
$databaseId = $database [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$cities = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'name' => 'City' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:45:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$citiesId = $cities [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$stores = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'name' => 'Store' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:45:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$storesId = $stores [ 'body' ][ '$id' ];
// attributes
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $citiesId ) . '/polygon' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'area' ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $storesId ) . '/string' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 255 ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $storesId , 'name' );
2025-08-26 10:45:26 +00:00
// relationship stores.manyToOne -> cities
2026-01-09 14:21:31 +00:00
$rel = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $storesId ) . '/relationship' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => $citiesId ,
2025-08-26 10:45:26 +00:00
'type' => Database :: RELATION_MANY_TO_ONE ,
'key' => 'city' ,
'twoWay' => true ,
'twoWayKey' => 'stores' ,
]);
$this -> assertEquals ( 202 , $rel [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $storesId , 'city' );
2025-08-26 10:45:26 +00:00
2026-01-09 14:21:31 +00:00
$store = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $storesId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => 'store-1' ,
2025-08-26 10:45:26 +00:00
'data' => [
'name' => 'Main Store' ,
'city' => [
'$id' => ID :: unique (),
'area' => [[[ 40.7128 , - 74.0060 ], [ 40.7589 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7128 , - 73.9851 ], [ 40.7128 , - 74.0060 ]]]
],
]
]);
$this -> assertEquals ( 201 , $store [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'Main Store' , $store [ 'body' ][ 'name' ]);
$this -> assertEquals ([[[ 40.7128 , - 74.0060 ], [ 40.7589 , - 74.0060 ], [ 40.7589 , - 73.9851 ], [ 40.7128 , - 73.9851 ], [ 40.7128 , - 74.0060 ]]], $store [ 'body' ][ 'city' ][ 'area' ]);
2026-01-09 14:21:31 +00:00
$city = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $citiesId ) . '/' . $this -> getRecordResource () . '/' . $store [ 'body' ][ 'city' ][ '$id' ], array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: select ([ 'stores.$id' ]) -> toString ()
]
]);
$this -> assertEquals ( 200 , $city [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'store-1' , $city [ 'body' ][ 'stores' ][ 0 ][ '$id' ]);
// cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $storesId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $citiesId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
public function testSpatialRelationshipManyToMany () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial ManyToMany Test DB'
]);
$databaseId = $database [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$drivers = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'name' => 'Drivers' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:45:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$driversId = $drivers [ 'body' ][ '$id' ];
2026-01-09 14:21:31 +00:00
$zones = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 10:45:26 +00:00
'name' => 'Zones' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 10:45:26 +00:00
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$zonesId = $zones [ 'body' ][ '$id' ];
// attributes
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $driversId ) . '/point' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'home' ,
'required' => true ,
]);
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $zonesId ) . '/polygon' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'area' ,
'required' => true ,
]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $zonesId , 'area' );
2025-08-26 10:45:26 +00:00
// relationship drivers.manyToMany <-> zones
2026-01-09 14:21:31 +00:00
$rel = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $driversId ) . '/relationship' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getRelatedIdParam () => $zonesId ,
2025-08-26 10:45:26 +00:00
'type' => Database :: RELATION_MANY_TO_MANY ,
'key' => 'zones' ,
'twoWay' => true ,
'twoWayKey' => 'drivers' ,
]);
$this -> assertEquals ( 202 , $rel [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $driversId , 'zones' );
2025-08-26 10:45:26 +00:00
// create driver with two zones containing spatial polygons
2026-01-09 14:21:31 +00:00
$driver = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $driversId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => 'driver-1' ,
2025-08-26 10:45:26 +00:00
'data' => [
'home' => [ 40.7128 , - 74.0060 ],
'zones' => [
[ '$id' => 'zone-1' , 'area' => [[[ 0 , 0 ],[ 10 , 0 ],[ 10 , 10 ],[ 0 , 10 ],[ 0 , 0 ]]]],
[ '$id' => 'zone-2' , 'area' => [[[ 20 , 20 ],[ 30 , 20 ],[ 30 , 30 ],[ 20 , 30 ],[ 20 , 20 ]]]],
],
]
]);
$this -> assertEquals ( 201 , $driver [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 2 , $driver [ 'body' ][ 'zones' ]);
$this -> assertEquals ([ 40.7128 , - 74.0060 ], $driver [ 'body' ][ 'home' ]);
2026-01-09 14:21:31 +00:00
$zone = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $zonesId ) . '/' . $this -> getRecordResource () . '/zone-1' , array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [
Query :: select ([ 'drivers.$id' ]) -> toString ()
]
]);
$this -> assertEquals ( 200 , $zone [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'driver-1' , $zone [ 'body' ][ 'drivers' ][ 0 ][ '$id' ]);
// cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $driversId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $zonesId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-08-26 10:45:26 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
2025-08-26 15:24:55 +00:00
public function testSpatialIndex () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-08-26 15:24:55 +00:00
'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' ];
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-08-26 15:24:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-08-26 15:24:55 +00:00
'name' => 'SpatialIdx' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-08-26 15:24:55 +00:00
'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
2026-01-09 14:21:31 +00:00
$reqPoint = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point' , array_merge ([
2025-08-26 15:24:55 +00:00
'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' ]);
2026-01-09 14:21:31 +00:00
$optPoint = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point' , array_merge ([
2025-08-26 15:24:55 +00:00
'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
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $collectionId );
2025-08-26 15:24:55 +00:00
// Create index on required spatial attribute (should succeed)
2026-01-09 14:21:31 +00:00
$okIndex = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 15:24:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'idx_required_point' ,
'type' => Database :: INDEX_SPATIAL ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'pRequired' ],
2025-08-26 15:24:55 +00:00
]);
$this -> assertEquals ( 202 , $okIndex [ 'headers' ][ 'status-code' ]);
// Create index on optional spatial attribute (should fail in case of mariadb)
2026-01-09 14:21:31 +00:00
$badIndex = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 15:24:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'idx_optional_point' ,
'type' => Database :: INDEX_SPATIAL ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'pOptional' ],
2025-08-26 15:24:55 +00:00
]);
$this -> assertEquals ( 400 , $badIndex [ 'headers' ][ 'status-code' ]);
2025-09-02 12:37:34 +00:00
// updating the attribute to required to create index
2026-01-09 14:21:31 +00:00
$updated = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point/' . 'pOptional' , array_merge ([
2025-09-02 12:37:34 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'required' => true ,
'default' => null
]);
$this -> assertEquals ( 200 , $updated [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $collectionId , 'pOptional' );
2026-01-09 14:21:31 +00:00
$retriedIndex = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 12:37:34 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'idx_optional_point' ,
'type' => Database :: INDEX_SPATIAL ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'pOptional' ],
2025-09-02 12:37:34 +00:00
]);
$this -> assertEquals ( 202 , $retriedIndex [ 'headers' ][ 'status-code' ]);
2025-08-26 15:24:55 +00:00
// Cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-08-26 15:24:55 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
2025-09-02 17:30:31 +00:00
public function testSpatialDistanceInMeter () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial Distance Meters Database'
]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create collection with spatial attribute
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => ID :: unique (),
2025-09-02 17:30:31 +00:00
'name' => 'Spatial Distance Meters Collection' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-09-02 17:30:31 +00:00
'permissions' => [
Permission :: create ( Role :: any ()),
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
]);
$collectionId = $collection [ 'body' ][ '$id' ];
// Create point attribute
2026-01-09 14:21:31 +00:00
$response = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $collectionId ) . '/point' , array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'loc' ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $response [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $collectionId , 'loc' );
2025-09-02 17:30:31 +00:00
// Create spatial index
2026-01-09 14:21:31 +00:00
$indexResponse = $this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'idx_loc' ,
'type' => Database :: INDEX_SPATIAL ,
2026-01-09 14:21:31 +00:00
$this -> getIndexAttributesParam () => [ 'loc' ],
2025-09-02 17:30:31 +00:00
]);
2026-01-10 01:53:29 +00:00
$this -> waitForIndex ( $databaseId , $collectionId , 'idx_loc' );
2025-09-02 17:30:31 +00:00
$this -> assertEquals ( 202 , $indexResponse [ 'headers' ][ 'status-code' ]);
// Two points roughly ~1000 meters apart by latitude delta (~0.009 deg ≈ 1km)
2026-01-09 14:21:31 +00:00
$p0 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => 'p0' ,
2025-09-02 17:30:31 +00:00
'data' => [
'loc' => [ 0.0000 , 0.0000 ]
]
]);
2026-01-09 14:21:31 +00:00
$p1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => 'p1' ,
2025-09-02 17:30:31 +00:00
'data' => [
'loc' => [ 0.0090 , 0.0000 ]
]
]);
$this -> assertEquals ( 201 , $p0 [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 201 , $p1 [ 'headers' ][ 'status-code' ]);
// distanceLessThan with meters=true: within 1500m should include both
2026-01-09 14:21:31 +00:00
$within1_5km = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: distanceLessThan ( 'loc' , [ 0.0000 , 0.0000 ], 1500 , true ) -> toString ()]
]);
$this -> assertEquals ( 200 , $within1_5km [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 2 , $within1_5km [ 'body' ][ $this -> getRecordResource ()]);
2025-09-02 17:30:31 +00:00
// Within 500m should include only p0 (exact point)
2026-01-09 14:21:31 +00:00
$within500m = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: distanceLessThan ( 'loc' , [ 0.0000 , 0.0000 ], 500 , true ) -> toString ()]
]);
$this -> assertEquals ( 200 , $within500m [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $within500m [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'p0' , $within500m [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-09-02 17:30:31 +00:00
// distanceGreaterThan 500m should include only p1
2026-01-09 14:21:31 +00:00
$greater500m = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: distanceGreaterThan ( 'loc' , [ 0.0000 , 0.0000 ], 500 , true ) -> toString ()]
]);
$this -> assertEquals ( 200 , $greater500m [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertCount ( 1 , $greater500m [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'p1' , $greater500m [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-09-02 17:30:31 +00:00
// distanceEqual with 0m should return exact match p0
2026-01-09 14:21:31 +00:00
$equalZero = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: distanceEqual ( 'loc' , [ 0.0000 , 0.0000 ], 0 , true ) -> toString ()]
]);
$this -> assertEquals ( 200 , $equalZero [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'p0' , $equalZero [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-09-02 17:30:31 +00:00
// distanceNotEqual with 0m should return p1
2026-01-09 14:21:31 +00:00
$notEqualZero = $this -> client -> call ( Client :: METHOD_GET , $this -> getRecordUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'queries' => [ Query :: distanceNotEqual ( 'loc' , [ 0.0000 , 0.0000 ], 0 , true ) -> toString ()]
]);
$this -> assertEquals ( 200 , $notEqualZero [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$this -> assertEquals ( 'p1' , $notEqualZero [ 'body' ][ $this -> getRecordResource ()][ 0 ][ '$id' ]);
2025-09-02 17:30:31 +00:00
// Cleanup
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getContainerUrl ( $databaseId , $collectionId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
2026-01-09 14:21:31 +00:00
$this -> client -> call ( Client :: METHOD_DELETE , $this -> getDatabaseUrl ( $databaseId ), array_merge ([
2025-09-02 17:30:31 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]));
}
2025-09-17 12:31:29 +00:00
public function testSpatialColCreateOnExistingData () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial Distance Meters Database'
]);
$databaseId = $database [ 'body' ][ '$id' ];
$colId = ID :: unique ();
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => $colId ,
2025-09-17 12:31:29 +00:00
'name' => 'spatial-test' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-09-17 12:31:29 +00:00
'permissions' => [
Permission :: create ( Role :: any ()),
Permission :: read ( Role :: any ()),
],
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$description = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/string' , array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'description' ,
'size' => 512 ,
'required' => false ,
'default' => '' ,
]);
$this -> assertEquals ( 202 , $description [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $colId , 'description' );
2025-09-17 12:31:29 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $colId ), array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-09-17 12:31:29 +00:00
'data' => [
'description' => 'description'
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $document [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$point = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/point' , array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'loc' ,
'required' => true ,
]);
$this -> assertEquals ( 400 , $point [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$point = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/point' , array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'loc' ,
'required' => false ,
'default' => null
]);
$this -> assertEquals ( 202 , $point [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$line = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/line' , array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'route' ,
'required' => true ,
]);
$this -> assertEquals ( 400 , $line [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$line = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/line' , array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'route' ,
'required' => false ,
'default' => null
]);
$this -> assertEquals ( 202 , $line [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$poly = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/polygon' , array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'area' ,
'required' => true ,
]);
$this -> assertEquals ( 400 , $poly [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$poly = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/polygon' , array_merge ([
2025-09-17 12:31:29 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'area' ,
'required' => false ,
'default' => null
]);
$this -> assertEquals ( 202 , $poly [ 'headers' ][ 'status-code' ]);
}
2025-09-17 14:16:06 +00:00
public function testSpatialColCreateOnExistingDataWithDefaults () : void
{
2026-01-09 14:21:31 +00:00
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
2025-09-17 14:16:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'Spatial With Defaults Database'
]);
$databaseId = $database [ 'body' ][ '$id' ];
$colId = ID :: unique ();
2026-01-09 14:21:31 +00:00
$collection = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
2025-09-17 14:16:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
2026-01-09 14:21:31 +00:00
$this -> getContainerIdParam () => $colId ,
2025-09-17 14:16:06 +00:00
'name' => 'spatial-test-defaults' ,
2026-01-09 14:21:31 +00:00
$this -> getSecurityParam () => true ,
2025-09-17 14:16:06 +00:00
'permissions' => [
Permission :: create ( Role :: any ()),
Permission :: read ( Role :: any ()),
],
]);
$this -> assertEquals ( 201 , $collection [ 'headers' ][ 'status-code' ]);
2026-01-09 14:21:31 +00:00
$description = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/string' , array_merge ([
2025-09-17 14:16:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'description' ,
'size' => 512 ,
'required' => false ,
'default' => '' ,
]);
$this -> assertEquals ( 202 , $description [ 'headers' ][ 'status-code' ]);
2026-01-10 01:53:29 +00:00
$this -> waitForAttribute ( $databaseId , $colId , 'description' );
2025-09-17 14:16:06 +00:00
2026-01-09 14:21:31 +00:00
$document = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $colId ), array_merge ([
2025-09-17 14:16:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-09-17 14:16:06 +00:00
'data' => [
'description' => 'description'
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $document [ 'headers' ][ 'status-code' ]);
// Test point with default value
2026-01-09 14:21:31 +00:00
$point = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/point' , array_merge ([
2025-09-17 14:16:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'loc' ,
'required' => false ,
'default' => [ 0.0 , 0.0 ]
]);
$this -> assertEquals ( 202 , $point [ 'headers' ][ 'status-code' ]);
// Test line with default value
2026-01-09 14:21:31 +00:00
$line = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/line' , array_merge ([
2025-09-17 14:16:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'route' ,
'required' => false ,
'default' => [[ 0.0 , 0.0 ], [ 1.0 , 1.0 ]]
]);
$this -> assertEquals ( 202 , $line [ 'headers' ][ 'status-code' ]);
// Test polygon with default value
2026-01-09 14:21:31 +00:00
$poly = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $colId ) . '/polygon' , array_merge ([
2025-09-17 14:16:06 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'area' ,
'required' => false ,
'default' => [[[ 0.0 , 0.0 ], [ 1.0 , 0.0 ], [ 1.0 , 1.0 ], [ 0.0 , 1.0 ], [ 0.0 , 0.0 ]]]
]);
$this -> assertEquals ( 202 , $poly [ 'headers' ][ 'status-code' ]);
2025-09-17 14:32:36 +00:00
2025-09-17 14:30:10 +00:00
// Wait for attributes to be available
2026-01-10 01:53:29 +00:00
$this -> waitForAllAttributes ( $databaseId , $colId );
2025-09-17 14:30:10 +00:00
// Create a new document without spatial data to test default values
2026-01-09 14:21:31 +00:00
$newDocument = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $colId ), array_merge ([
2025-09-17 14:30:10 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
2026-01-09 14:21:31 +00:00
$this -> getRecordIdParam () => ID :: unique (),
2025-09-17 14:30:10 +00:00
'data' => [
'description' => 'test default values'
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: delete ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $newDocument [ 'headers' ][ 'status-code' ]);
2025-09-17 14:32:36 +00:00
2025-09-17 14:30:10 +00:00
$newDocumentId = $newDocument [ 'body' ][ '$id' ];
// Fetch the document to verify default values are applied
2026-01-09 14:21:31 +00:00
$fetchedDocument = $this -> client -> call ( Client :: METHOD_GET , $this -> getContainerUrl ( $databaseId , $colId ) . '/' . $this -> getRecordResource () . '/' . $newDocumentId , array_merge ([
2025-09-17 14:30:10 +00:00
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()));
2025-09-17 14:32:36 +00:00
2025-09-17 14:30:10 +00:00
$this -> assertEquals ( 200 , $fetchedDocument [ 'headers' ][ 'status-code' ]);
2025-09-17 14:32:36 +00:00
2025-09-17 14:30:10 +00:00
// Verify default values are applied
$this -> assertEquals ([ 0.0 , 0.0 ], $fetchedDocument [ 'body' ][ 'loc' ]);
$this -> assertEquals ([[ 0.0 , 0.0 ], [ 1.0 , 1.0 ]], $fetchedDocument [ 'body' ][ 'route' ]);
$this -> assertEquals ([[[ 0.0 , 0.0 ], [ 1.0 , 0.0 ], [ 1.0 , 1.0 ], [ 0.0 , 1.0 ], [ 0.0 , 0.0 ]]], $fetchedDocument [ 'body' ][ 'area' ]);
2025-09-17 14:16:06 +00:00
}
2026-01-10 01:53:29 +00:00
public function testNotContains () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'NotContains test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'NotContains test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$movies = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Movies' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $movies [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $movies [ 'body' ][ 'name' ], 'Movies' );
// Create Attributes
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $movies [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
$genre = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $movies [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'genre' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $genre [ 'headers' ][ 'status-code' ]);
// Wait for worker
$this -> waitForAllAttributes ( $databaseId , $movies [ 'body' ][ '$id' ]);
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $movies [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Spider-Man: Homecoming' ,
'genre' => 'Action' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $movies [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'The Avengers' ,
'genre' => 'Action' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $movies [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Romantic Comedy' ,
'genre' => 'Romance' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
// Test notContains query - should return movies that don't contain "Spider" in title
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $movies [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: select ([ 'title' , 'genre' ]) -> toString (),
Query :: notContains ( 'title' , [ 'Spider' ]) -> toString (),
Query :: limit ( 999 ) -> toString (),
Query :: offset ( 0 ) -> toString ()
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 2 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'The Avengers' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'title' ]);
$this -> assertEquals ( 'Romantic Comedy' , $rows [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'title' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testNotSearch () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'NotSearch test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'NotSearch test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$books = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Books' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $books [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $books [ 'body' ][ 'name' ], 'Books' );
// Create Attributes
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $books [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
$description = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $books [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'description' ,
'size' => 2048 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $description [ 'headers' ][ 'status-code' ]);
$this -> waitForAllAttributes ( $databaseId , $books [ 'body' ][ '$id' ]);
$this -> client -> call ( Client :: METHOD_POST , $this -> getIndexUrl ( $databaseId , $books [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'fts_description' ,
'type' => Database :: INDEX_FULLTEXT ,
$this -> getIndexAttributesParam () => [ 'description' ],
]);
$this -> waitForIndex ( $databaseId , $books [ 'body' ][ '$id' ], 'fts_description' );
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $books [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Science Fiction Adventures' ,
'description' => 'A thrilling journey through space and time' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $books [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Romance Novel' ,
'description' => 'A love story set in modern times' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $books [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Mystery Thriller' ,
'description' => 'A detective solves complex crimes' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
// Test notSearch query - should return books that don't have "space" in the description
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $books [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: notSearch ( 'description' , 'space' ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 2 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Romance Novel' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'title' ]);
$this -> assertEquals ( 'Mystery Thriller' , $rows [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'title' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testNotBetween () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'NotBetween test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'NotBetween test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$products = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Products' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $products [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $products [ 'body' ][ 'name' ], 'Products' );
// Create Attributes
$name = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $products [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $name [ 'headers' ][ 'status-code' ]);
$price = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $products [ 'body' ][ '$id' ]) . '/float' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'price' ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $price [ 'headers' ][ 'status-code' ]);
// Wait for worker
$this -> waitForAllAttributes ( $databaseId , $products [ 'body' ][ '$id' ]);
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Cheap Product' ,
'price' => 5.99 ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Mid Product' ,
'price' => 25.00 ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Expensive Product' ,
'price' => 150.00 ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
// Test notBetween query - should return products NOT priced between 10 and 50
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: notBetween ( 'price' , 10 , 50 ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 2 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Cheap Product' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'name' ]);
$this -> assertEquals ( 'Expensive Product' , $rows [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'name' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testNotStartsWith () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'NotStartsWith test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'NotStartsWith test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$employees = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Employees' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $employees [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $employees [ 'body' ][ 'name' ], 'Employees' );
// Create Attributes
$name = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $employees [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $name [ 'headers' ][ 'status-code' ]);
$department = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $employees [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'department' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $department [ 'headers' ][ 'status-code' ]);
// Wait for worker
$this -> waitForAllAttributes ( $databaseId , $employees [ 'body' ][ '$id' ]);
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $employees [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'John Smith' ,
'department' => 'Engineering' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $employees [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Jane Doe' ,
'department' => 'Marketing' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $employees [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Bob Johnson' ,
'department' => 'Sales' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
// Test notStartsWith query - should return employees whose names don't start with "John"
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $employees [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: notStartsWith ( 'name' , 'John' ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 2 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Jane Doe' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'name' ]);
$this -> assertEquals ( 'Bob Johnson' , $rows [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'name' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testNotEndsWith () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'NotEndsWith test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'NotEndsWith test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$files = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Files' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $files [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $files [ 'body' ][ 'name' ], 'Files' );
// Create Attributes
$filename = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $files [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'filename' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $filename [ 'headers' ][ 'status-code' ]);
$type = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $files [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'type' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $type [ 'headers' ][ 'status-code' ]);
// Wait for worker
$this -> waitForAllAttributes ( $databaseId , $files [ 'body' ][ '$id' ]);
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $files [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'filename' => 'row.pdf' ,
'type' => 'PDF' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $files [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'filename' => 'image.jpg' ,
'type' => 'Image' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $files [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'filename' => 'presentation.pptx' ,
'type' => 'Presentation' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
// Test notEndsWith query - should return files that don't end with ".pdf"
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $files [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: notEndsWith ( 'filename' , '.pdf' ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 2 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'image.jpg' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'filename' ]);
$this -> assertEquals ( 'presentation.pptx' , $rows [ 'body' ][ $this -> getRecordResource ()][ 1 ][ 'filename' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testCreatedBefore () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'CreatedBefore test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'CreatedBefore test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$posts = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Posts' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $posts [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $posts [ 'body' ][ 'name' ], 'Posts' );
// Create Attributes
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $posts [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
$content = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $posts [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'content' ,
'size' => 512 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $content [ 'headers' ][ 'status-code' ]);
// Wait for worker
$this -> waitForAllAttributes ( $databaseId , $posts [ 'body' ][ '$id' ]);
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $posts [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Old Post' ,
'content' => 'This is an old post content' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
// Sleep to ensure different creation times
sleep ( 1 );
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $posts [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Recent Post' ,
'content' => 'This is a recent post content' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
// Get the creation time of the second post to use as boundary
$secondPostCreatedAt = $row2 [ 'body' ][ '$createdAt' ];
// Sleep again
sleep ( 1 );
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $posts [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Newest Post' ,
'content' => 'This is the newest post content' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
// Test createdBefore query - should return posts created before the second post
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $posts [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: createdBefore ( $secondPostCreatedAt ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 1 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Old Post' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'title' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testCreatedAfter () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'CreatedAfter test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'CreatedAfter test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$events = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Events' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $events [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $events [ 'body' ][ 'name' ], 'Events' );
// Create Attributes
$name = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $events [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $name [ 'headers' ][ 'status-code' ]);
$description = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $events [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'description' ,
'size' => 512 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $description [ 'headers' ][ 'status-code' ]);
// Wait for worker
$this -> waitForAllAttributes ( $databaseId , $events [ 'body' ][ '$id' ]);
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $events [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Early Event' ,
'description' => 'This is an early event' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
// Sleep to ensure different creation times
sleep ( 1 );
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $events [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Middle Event' ,
'description' => 'This is a middle event' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
// Get the creation time of the second event to use as boundary
$secondEventCreatedAt = $row2 [ 'body' ][ '$createdAt' ];
// Sleep again
sleep ( 1 );
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $events [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Latest Event' ,
'description' => 'This is the latest event' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
// Test createdAfter query - should return events created after the second event
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $events [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: createdAfter ( $secondEventCreatedAt ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 1 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Latest Event' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'name' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testCreatedBetween () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'CreatedBetween test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'CreatedBetween test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$articles = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Articles' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $articles [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $articles [ 'body' ][ 'name' ], 'Articles' );
// Create Attributes
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $articles [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
$content = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $articles [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'content' ,
'size' => 5000 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $content [ 'headers' ][ 'status-code' ]);
// Wait for attributes to be available
$this -> waitForAllAttributes ( $databaseId , $articles [ 'body' ][ '$id' ]);
// Create first article
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $articles [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'First Article' ,
'content' => 'This is the first article content' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
$firstArticleCreatedAt = $row1 [ 'body' ][ '$createdAt' ];
// Sleep to ensure different timestamps
sleep ( 1 );
// Create second article
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $articles [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Second Article' ,
'content' => 'This is the second article content' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
$secondArticleCreatedAt = $row2 [ 'body' ][ '$createdAt' ];
// Sleep again
sleep ( 1 );
// Create third article
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $articles [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Third Article' ,
'content' => 'This is the third article content' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
$thirdArticleCreatedAt = $row3 [ 'body' ][ '$createdAt' ];
// Sleep again
sleep ( 1 );
// Create fourth article
$row4 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $articles [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Fourth Article' ,
'content' => 'This is the fourth article content' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row4 [ 'headers' ][ 'status-code' ]);
// Test createdBetween query - should return articles created between first and third (inclusive)
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $articles [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: createdBetween ( $firstArticleCreatedAt , $thirdArticleCreatedAt ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 3 , $rows [ 'body' ][ $this -> getRecordResource ()]);
// Verify the returned articles are the correct ones
$titles = array_column ( $rows [ 'body' ][ $this -> getRecordResource ()], 'title' );
$this -> assertContains ( 'First Article' , $titles );
$this -> assertContains ( 'Second Article' , $titles );
$this -> assertContains ( 'Third Article' , $titles );
$this -> assertNotContains ( 'Fourth Article' , $titles );
// Test createdBetween query - should return only the second article when using its timestamp for both bounds
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $articles [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: createdBetween ( $secondArticleCreatedAt , $secondArticleCreatedAt ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 1 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Second Article' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'title' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testUpdatedBefore () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'UpdatedBefore test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'UpdatedBefore test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$tasks = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Tasks' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $tasks [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $tasks [ 'body' ][ 'name' ], 'Tasks' );
// Create Attributes
$title = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'title' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $title [ 'headers' ][ 'status-code' ]);
$status = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'status' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $status [ 'headers' ][ 'status-code' ]);
// Wait for worker
$this -> waitForAllAttributes ( $databaseId , $tasks [ 'body' ][ '$id' ]);
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Task One' ,
'status' => 'pending' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
$taskOneId = $row1 [ 'body' ][ '$id' ];
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Task Two' ,
'status' => 'pending' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
$taskTwoId = $row2 [ 'body' ][ '$id' ];
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'title' => 'Task Three' ,
'status' => 'pending' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
$taskThreeId = $row3 [ 'body' ][ '$id' ];
// Update first task
sleep ( 1 );
$this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $taskOneId , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'status' => 'completed' ,
]
]);
// Update second task and get its updated time
sleep ( 1 );
$updatedTaskTwo = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $taskTwoId , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'status' => 'in_progress' ,
]
]);
$secondTaskUpdatedAt = $updatedTaskTwo [ 'body' ][ '$updatedAt' ];
// Update third task
sleep ( 1 );
$this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $taskThreeId , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'status' => 'review' ,
]
]);
// Test updatedBefore query - should return tasks updated before the second task's update time
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $tasks [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: updatedBefore ( $secondTaskUpdatedAt ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 1 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Task One' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'title' ]);
$this -> assertEquals ( 'completed' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'status' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testUpdatedAfter () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'UpdatedAfter test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'UpdatedAfter test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$orders = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Orders' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $orders [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $orders [ 'body' ][ 'name' ], 'Orders' );
// Create Attributes
$orderNumber = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $orders [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'orderNumber' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $orderNumber [ 'headers' ][ 'status-code' ]);
$status = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $orders [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'status' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $status [ 'headers' ][ 'status-code' ]);
// Wait for worker
$this -> waitForAllAttributes ( $databaseId , $orders [ 'body' ][ '$id' ]);
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $orders [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'orderNumber' => 'ORD-001' ,
'status' => 'pending' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
$orderOneId = $row1 [ 'body' ][ '$id' ];
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $orders [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'orderNumber' => 'ORD-002' ,
'status' => 'pending' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
$orderTwoId = $row2 [ 'body' ][ '$id' ];
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $orders [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'orderNumber' => 'ORD-003' ,
'status' => 'pending' ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
$orderThreeId = $row3 [ 'body' ][ '$id' ];
// Update first order
sleep ( 1 );
$this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $orders [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $orderOneId , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'status' => 'processing' ,
]
]);
// Update second order and get its updated time
sleep ( 1 );
$updatedOrderTwo = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $orders [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $orderTwoId , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'status' => 'shipped' ,
]
]);
$secondOrderUpdatedAt = $updatedOrderTwo [ 'body' ][ '$updatedAt' ];
// Update third order
sleep ( 1 );
$this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $orders [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $orderThreeId , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'status' => 'delivered' ,
]
]);
// Test updatedAfter query - should return orders updated after the second order's update time
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $orders [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: updatedAfter ( $secondOrderUpdatedAt ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 1 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'ORD-003' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'orderNumber' ]);
$this -> assertEquals ( 'delivered' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'status' ]);
}
/**
* @ throws \Utopia\Database\Exception
* @ throws \Utopia\Database\Exception\Query
*/
public function testUpdatedBetween () : void
{
// Create database
$database = $this -> client -> call ( Client :: METHOD_POST , $this -> getApiBasePath (), [
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
], [
'databaseId' => ID :: unique (),
'name' => 'UpdatedBetween test'
]);
$this -> assertNotEmpty ( $database [ 'body' ][ '$id' ]);
$this -> assertEquals ( 201 , $database [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( 'UpdatedBetween test' , $database [ 'body' ][ 'name' ]);
$databaseId = $database [ 'body' ][ '$id' ];
// Create Collection
$products = $this -> client -> call ( Client :: METHOD_POST , $this -> getContainerUrl ( $databaseId ), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
$this -> getContainerIdParam () => ID :: unique (),
'name' => 'Products' ,
$this -> getSecurityParam () => true ,
'permissions' => [
Permission :: create ( Role :: user ( $this -> getUser ()[ '$id' ])),
],
]);
$this -> assertEquals ( 201 , $products [ 'headers' ][ 'status-code' ]);
$this -> assertEquals ( $products [ 'body' ][ 'name' ], 'Products' );
// Create Attributes
$name = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $products [ 'body' ][ '$id' ]) . '/string' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'name' ,
'size' => 256 ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $name [ 'headers' ][ 'status-code' ]);
$price = $this -> client -> call ( Client :: METHOD_POST , $this -> getSchemaUrl ( $databaseId , $products [ 'body' ][ '$id' ]) . '/float' , array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
'x-appwrite-key' => $this -> getProject ()[ 'apiKey' ]
]), [
'key' => 'price' ,
'required' => true ,
]);
$this -> assertEquals ( 202 , $price [ 'headers' ][ 'status-code' ]);
// Wait for attributes to be available
$this -> waitForAllAttributes ( $databaseId , $products [ 'body' ][ '$id' ]);
// Create first product
$row1 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Product A' ,
'price' => 99.99 ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row1 [ 'headers' ][ 'status-code' ]);
// Sleep to ensure different timestamps
sleep ( 1 );
// Create second product
$row2 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Product B' ,
'price' => 149.99 ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row2 [ 'headers' ][ 'status-code' ]);
// Sleep again
sleep ( 1 );
// Create third product
$row3 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Product C' ,
'price' => 199.99 ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row3 [ 'headers' ][ 'status-code' ]);
// Sleep again
sleep ( 1 );
// Create fourth product
$row4 = $this -> client -> call ( Client :: METHOD_POST , $this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]), array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
$this -> getRecordIdParam () => ID :: unique (),
'data' => [
'name' => 'Product D' ,
'price' => 249.99 ,
],
'permissions' => [
Permission :: read ( Role :: user ( $this -> getUser ()[ '$id' ])),
Permission :: update ( Role :: user ( $this -> getUser ()[ '$id' ])),
]
]);
$this -> assertEquals ( 201 , $row4 [ 'headers' ][ 'status-code' ]);
// Now update products in sequence to get different updatedAt timestamps
sleep ( 1 );
// Update first product
$update1 = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $products [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $row1 [ 'body' ][ '$id' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'price' => 89.99 ,
]
]);
$this -> assertEquals ( 200 , $update1 [ 'headers' ][ 'status-code' ]);
$firstProductUpdatedAt = $update1 [ 'body' ][ '$updatedAt' ];
sleep ( 1 );
// Update second product
$update2 = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $products [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $row2 [ 'body' ][ '$id' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'price' => 139.99 ,
]
]);
$this -> assertEquals ( 200 , $update2 [ 'headers' ][ 'status-code' ]);
$secondProductUpdatedAt = $update2 [ 'body' ][ '$updatedAt' ];
sleep ( 1 );
// Update third product
$update3 = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $products [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $row3 [ 'body' ][ '$id' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'price' => 189.99 ,
]
]);
$this -> assertEquals ( 200 , $update3 [ 'headers' ][ 'status-code' ]);
$thirdProductUpdatedAt = $update3 [ 'body' ][ '$updatedAt' ];
sleep ( 1 );
// Update fourth product
$update4 = $this -> client -> call ( Client :: METHOD_PATCH , $this -> getContainerUrl ( $databaseId , $products [ 'body' ][ '$id' ]) . '/' . $this -> getRecordResource () . '/' . $row4 [ 'body' ][ '$id' ], array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()), [
'data' => [
'price' => 239.99 ,
]
]);
$this -> assertEquals ( 200 , $update4 [ 'headers' ][ 'status-code' ]);
// Test updatedBetween query - should return products updated between first and third (inclusive)
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: updatedBetween ( $firstProductUpdatedAt , $thirdProductUpdatedAt ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 3 , $rows [ 'body' ][ $this -> getRecordResource ()]);
// Verify the returned products are the correct ones
$names = array_column ( $rows [ 'body' ][ $this -> getRecordResource ()], 'name' );
$this -> assertContains ( 'Product A' , $names );
$this -> assertContains ( 'Product B' , $names );
$this -> assertContains ( 'Product C' , $names );
$this -> assertNotContains ( 'Product D' , $names );
// Test updatedBetween query - should return only the second product when using its timestamp for both bounds
$rows = $this -> client -> call (
Client :: METHOD_GET ,
$this -> getRecordUrl ( $databaseId , $products [ 'body' ][ '$id' ]),
array_merge ([
'content-type' => 'application/json' ,
'x-appwrite-project' => $this -> getProject ()[ '$id' ],
], $this -> getHeaders ()),
[
'queries' => [
Query :: updatedBetween ( $secondProductUpdatedAt , $secondProductUpdatedAt ) -> toString (),
],
]
);
$this -> assertEquals ( 200 , $rows [ 'headers' ][ 'status-code' ]);
$this -> assertCount ( 1 , $rows [ 'body' ][ $this -> getRecordResource ()]);
$this -> assertEquals ( 'Product B' , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'name' ]);
$this -> assertEquals ( 139.99 , $rows [ 'body' ][ $this -> getRecordResource ()][ 0 ][ 'price' ]);
}
2022-05-23 14:54:50 +00:00
}