mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
136
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b86d23151 | ||
|
|
71a4e515cc | ||
|
|
1116370745 | ||
|
|
6e498beb03 | ||
|
|
f97d272085 | ||
|
|
1a3c4d7b6c | ||
|
|
77c69ce793 | ||
|
|
b41eb48611 | ||
|
|
53174fb3e0 | ||
|
|
a770e6c289 | ||
|
|
2633654859 | ||
|
|
be676cf349 | ||
|
|
c1b9f75d47 | ||
|
|
7fd25eb380 | ||
|
|
f3b79f96ab | ||
|
|
45ce82c5c6 | ||
|
|
f76b9a8700 | ||
|
|
0e4dbcca22 | ||
|
|
aa3b6b462d | ||
|
|
a0797868fd | ||
|
|
997aafc646 | ||
|
|
a456ae5acb | ||
|
|
c2e7daaf1e | ||
|
|
922950929a | ||
|
|
21af384227 | ||
|
|
3574d89012 | ||
|
|
b0e47fbb2c | ||
|
|
1762b9d2ec | ||
|
|
79d8ada95d | ||
|
|
affe208d1a | ||
|
|
0a53c677b1 | ||
|
|
0e709f1f97 | ||
|
|
0c514d5696 | ||
|
|
da45edcd46 | ||
|
|
396b152bcf | ||
|
|
d811fb00d9 | ||
|
|
0520eea383 | ||
|
|
8051b6f64e | ||
|
|
406fd1b94a | ||
|
|
6a70a1958f | ||
|
|
b222f4e4bb | ||
|
|
66babf9dae | ||
|
|
0adacef23f | ||
|
|
bcd69e34ce | ||
|
|
6775b9505a | ||
|
|
4967887797 | ||
|
|
971e1270d7 | ||
|
|
be6c0a63f1 | ||
|
|
5e5f5ef49f | ||
|
|
bafb326ef7 | ||
|
|
f030631e6e | ||
|
|
1b8462d2e2 | ||
|
|
08f0a43465 | ||
|
|
87380a2b01 | ||
|
|
0748a08fdc | ||
|
|
2e4efb5d2f | ||
|
|
730a967104 | ||
|
|
95af73a479 | ||
|
|
d7619f7057 | ||
|
|
1ec142fe07 | ||
|
|
1c73d54153 | ||
|
|
1daef72ca9 | ||
|
|
c5b415af59 | ||
|
|
b1915fa20c | ||
|
|
82032ac60a | ||
|
|
27121a7f1e | ||
|
|
bef969738e | ||
|
|
bea6ccbe92 | ||
|
|
c126dba3b5 | ||
|
|
c72e69371b | ||
|
|
a3c6e45e92 | ||
|
|
db068f31ba | ||
|
|
50673c3223 | ||
|
|
7d5d97e53b | ||
|
|
0b1136c678 | ||
|
|
5d59e17b8c | ||
|
|
7de871c3d9 | ||
|
|
2c1a92951e | ||
|
|
5991b1f966 | ||
|
|
4e24b117f5 | ||
|
|
edaa3764c2 | ||
|
|
7db91c2ab0 | ||
|
|
acd8ff839e | ||
|
|
7f5857b232 | ||
|
|
139474d3fb | ||
|
|
30469128d3 | ||
|
|
64f4e081b5 | ||
|
|
c80ff1b541 | ||
|
|
edcee5167a | ||
|
|
1aea7bd6f2 | ||
|
|
a9233717b6 | ||
|
|
ccb34dc401 | ||
|
|
761a4bb0c7 | ||
|
|
11f0e8f5df | ||
|
|
df26136dd8 | ||
|
|
aab780476e | ||
|
|
1ae2d09e4b | ||
|
|
a6a2fa77df | ||
|
|
a79f46ed78 | ||
|
|
638f7431b1 | ||
|
|
fa3c9a5b76 | ||
|
|
c388fea5d0 | ||
|
|
a407d2ea84 | ||
|
|
da56ef39f8 | ||
|
|
275b9a1186 | ||
|
|
2f514ae55e | ||
|
|
38517b8004 | ||
|
|
8758e2e5a0 | ||
|
|
dacc6a97d0 | ||
|
|
13fc2222f8 | ||
|
|
900d8f248e | ||
|
|
de572c3aa9 | ||
|
|
d4fd5e79d9 | ||
|
|
87247826e0 | ||
|
|
05f4d05cf3 | ||
|
|
d12d6acd62 | ||
|
|
133eac66e7 | ||
|
|
53a6fef69e | ||
|
|
0c4f540325 | ||
|
|
19e22e1da7 | ||
|
|
23c1e4fb79 | ||
|
|
904b2da8ce | ||
|
|
ee129e28f1 | ||
|
|
c50ba30f1b | ||
|
|
265ccdb03a | ||
|
|
3b93e925d4 | ||
|
|
10b38c7c6d | ||
|
|
adf6b02462 | ||
|
|
f47c484d8d | ||
|
|
6e1d2008f8 | ||
|
|
38fb9f2814 | ||
|
|
8d37e843e0 | ||
|
|
975510c6a0 | ||
|
|
a971976587 | ||
|
|
9bee2f5a25 | ||
|
|
21e830146b |
@@ -31,6 +31,7 @@ use Appwrite\URL\URL as URLParser;
|
||||
use Appwrite\Utopia\Database\Documents\User;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Identities;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use libphonenumber\NumberParseException;
|
||||
@@ -54,10 +55,7 @@ use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Email;
|
||||
use Utopia\Http\Http;
|
||||
@@ -3058,7 +3056,7 @@ Http::get('/v1/account/logs')
|
||||
],
|
||||
contentType: ContentType::JSON,
|
||||
))
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
|
||||
@@ -23,6 +23,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Providers;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Subscribers;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Targets;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Topics;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Response;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\Audit\Audit;
|
||||
@@ -37,10 +38,7 @@ use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Authorization\Input;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Http;
|
||||
@@ -1136,7 +1134,7 @@ Http::get('/v1/messaging/providers/:providerId/logs')
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -2540,7 +2538,7 @@ Http::get('/v1/messaging/topics/:topicId/logs')
|
||||
]
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -2955,7 +2953,7 @@ Http::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
]
|
||||
))
|
||||
->param('subscriberId', '', new UID(), 'Subscriber ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -3753,7 +3751,7 @@ Http::get('/v1/messaging/messages/:messageId/logs')
|
||||
],
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
||||
@@ -17,8 +17,9 @@ use Utopia\Database\Exception\Order as OrderException;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\QueryContext;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries\Documents;
|
||||
use Utopia\Database\Validator\Queries\V2 as DocumentsValidator;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Http;
|
||||
@@ -547,9 +548,11 @@ Http::post('/v1/migrations/csv/exports')
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$validator = new Documents(
|
||||
attributes: $collection->getAttribute('attributes', []),
|
||||
indexes: $collection->getAttribute('indexes', []),
|
||||
$context = new QueryContext();
|
||||
$context->add($collection);
|
||||
|
||||
$validator = new DocumentsValidator(
|
||||
$context,
|
||||
idAttributeType: $dbForProject->getAdapter()->getIdAttributeType(),
|
||||
);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ use Appwrite\Utopia\Database\Documents\User;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Teams;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use libphonenumber\NumberParseException;
|
||||
@@ -48,7 +49,6 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Email;
|
||||
use Utopia\Http\Http;
|
||||
@@ -1436,7 +1436,7 @@ Http::get('/v1/teams/:teamId/logs')
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
||||
@@ -25,6 +25,7 @@ use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Identities;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Targets;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Users;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
@@ -56,8 +57,6 @@ use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Email;
|
||||
use Utopia\Http\Http;
|
||||
@@ -933,7 +932,7 @@ Http::get('/v1/users/:userId/logs')
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
||||
@@ -25,6 +25,7 @@ use Appwrite\Utopia\Request\Filters\V18 as RequestV18;
|
||||
use Appwrite\Utopia\Request\Filters\V19 as RequestV19;
|
||||
use Appwrite\Utopia\Request\Filters\V20 as RequestV20;
|
||||
use Appwrite\Utopia\Request\Filters\V21 as RequestV21;
|
||||
use Appwrite\Utopia\Request\Filters\V22 as RequestV22;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filters\V16 as ResponseV16;
|
||||
use Appwrite\Utopia\Response\Filters\V17 as ResponseV17;
|
||||
@@ -931,6 +932,9 @@ Http::init()
|
||||
if (version_compare($requestFormat, '1.9.0', '<')) {
|
||||
$request->addFilter(new RequestV21());
|
||||
}
|
||||
if (version_compare($requestFormat, '1.10.0', '<')) {
|
||||
$request->addFilter(new RequestV22());
|
||||
}
|
||||
}
|
||||
|
||||
$localeParam = (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', ''));
|
||||
|
||||
@@ -46,7 +46,7 @@ const APP_RESOURCE_TOKEN_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_FILE_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_BUSTER = 4321;
|
||||
const APP_VERSION_STABLE = '1.8.1';
|
||||
const APP_VERSION_STABLE = '1.10.0';
|
||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
||||
|
||||
@@ -69,6 +69,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence()) || empty($document->getAttribute('databaseInternalId'))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$attributes = $database->getAuthorization()->skip(fn () => $database->find('attributes', [
|
||||
Query::equal('collectionInternalId', [$document->getSequence()]),
|
||||
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
|
||||
@@ -104,6 +108,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence()) || empty($document->getAttribute('databaseInternalId'))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('indexes', [
|
||||
Query::equal('collectionInternalId', [$document->getSequence()]),
|
||||
@@ -119,6 +127,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('platforms', [
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
@@ -133,6 +145,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('keys', [
|
||||
Query::equal('resourceType', ['projects']),
|
||||
@@ -148,6 +164,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('devKeys', [
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
@@ -162,6 +182,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('webhooks', [
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
@@ -176,6 +200,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database->find('sessions', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -189,6 +217,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('tokens', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
@@ -203,6 +235,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('challenges', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
@@ -217,6 +253,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('authenticators', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
@@ -231,6 +271,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('memberships', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
@@ -245,6 +289,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$resourceType = match ($document->getCollection()) {
|
||||
'functions' => ['function'],
|
||||
'sites' => ['site'],
|
||||
@@ -331,6 +379,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('targets', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
@@ -345,6 +397,10 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
if (empty($document->getSequence())) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$targetIds = $database->getAuthorization()->skip(fn () => \array_map(
|
||||
fn ($document) => $document->getAttribute('targetInternalId'),
|
||||
$database->find('subscribers', [
|
||||
|
||||
@@ -1144,8 +1144,7 @@ Http::setResource('schema', function ($utopia, $dbForProject, $authorization) {
|
||||
|
||||
$complexity = function (int $complexity, array $args) {
|
||||
$queries = Query::parseQueries($args['queries'] ?? []);
|
||||
$query = Query::getByType($queries, [Query::TYPE_LIMIT])[0] ?? null;
|
||||
$limit = $query ? $query->getValue() : APP_LIMIT_LIST_DEFAULT;
|
||||
$limit = Query::getLimitQuery($queries, APP_LIMIT_LIST_DEFAULT);
|
||||
|
||||
return $complexity * $limit;
|
||||
};
|
||||
|
||||
+2
-2
@@ -52,7 +52,7 @@
|
||||
"utopia-php/cache": "1.0.*",
|
||||
"utopia-php/cli": "0.22.*",
|
||||
"utopia-php/config": "1.*",
|
||||
"utopia-php/database": "5.*",
|
||||
"utopia-php/database": "dev-joins8 as 5.0.0",
|
||||
"utopia-php/detector": "0.2.*",
|
||||
"utopia-php/domains": "1.*",
|
||||
"utopia-php/emails": "0.6.*",
|
||||
@@ -64,7 +64,7 @@
|
||||
"utopia-php/locale": "0.8.*",
|
||||
"utopia-php/logger": "0.6.*",
|
||||
"utopia-php/messaging": "0.20.*",
|
||||
"utopia-php/migration": "1.5.*",
|
||||
"utopia-php/migration": "dev-joins as 1.5.0",
|
||||
"utopia-php/platform": "0.7.*",
|
||||
"utopia-php/pools": "1.*",
|
||||
"utopia-php/preloader": "0.2.*",
|
||||
|
||||
Generated
+47
-31
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "367aaf665ff75a13d5d7c8b3bedb89a9",
|
||||
"content-hash": "f8cc09a687dfc6a38921e80b7a3dc6de",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -3797,16 +3797,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "5.0.2",
|
||||
"version": "dev-joins8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "aa80f86f5bf3f0d8c13abd3213bf1649f542d366"
|
||||
"reference": "2eb66b29e093810d3f5dde15536398c186093a83"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/aa80f86f5bf3f0d8c13abd3213bf1649f542d366",
|
||||
"reference": "aa80f86f5bf3f0d8c13abd3213bf1649f542d366",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/2eb66b29e093810d3f5dde15536398c186093a83",
|
||||
"reference": "2eb66b29e093810d3f5dde15536398c186093a83",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3814,10 +3814,10 @@
|
||||
"ext-mongodb": "*",
|
||||
"ext-pdo": "*",
|
||||
"php": ">=8.4",
|
||||
"utopia-php/cache": "1.0.*",
|
||||
"utopia-php/cache": "1.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/mongo": "0.11.*",
|
||||
"utopia-php/pools": "1.0.*"
|
||||
"utopia-php/mongo": "1.*",
|
||||
"utopia-php/pools": "1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "1.23.*",
|
||||
@@ -3849,9 +3849,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/5.0.2"
|
||||
"source": "https://github.com/utopia-php/database/tree/joins8"
|
||||
},
|
||||
"time": "2026-02-08T05:23:42+00:00"
|
||||
"time": "2026-02-12T09:52:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -4464,16 +4464,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.5.2",
|
||||
"version": "dev-joins",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "93904948f6dd07491821615fd9b9acbcaadec12e"
|
||||
"reference": "ac60b6d3a341159116b58533c36d7410f212229a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/93904948f6dd07491821615fd9b9acbcaadec12e",
|
||||
"reference": "93904948f6dd07491821615fd9b9acbcaadec12e",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/ac60b6d3a341159116b58533c36d7410f212229a",
|
||||
"reference": "ac60b6d3a341159116b58533c36d7410f212229a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4482,7 +4482,7 @@
|
||||
"ext-openssl": "*",
|
||||
"halaxa/json-machine": "^1.2",
|
||||
"php": ">=8.1",
|
||||
"utopia-php/database": "5.*",
|
||||
"utopia-php/database": "dev-joins8 as 5.0.0",
|
||||
"utopia-php/dsn": "0.2.*",
|
||||
"utopia-php/storage": "0.18.*"
|
||||
},
|
||||
@@ -4513,22 +4513,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.5.2"
|
||||
"source": "https://github.com/utopia-php/migration/tree/joins"
|
||||
},
|
||||
"time": "2026-02-11T06:19:35+00:00"
|
||||
"time": "2026-02-11T13:25:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
"version": "0.11.0",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/mongo.git",
|
||||
"reference": "34bc0cda8ea368cde68702a6fffe2c3ac625398e"
|
||||
"reference": "45bedf36c2c946ec7a0a3e59b9f12f772de0b01d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/34bc0cda8ea368cde68702a6fffe2c3ac625398e",
|
||||
"reference": "34bc0cda8ea368cde68702a6fffe2c3ac625398e",
|
||||
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/45bedf36c2c946ec7a0a3e59b9f12f772de0b01d",
|
||||
"reference": "45bedf36c2c946ec7a0a3e59b9f12f772de0b01d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4574,9 +4574,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/mongo/issues",
|
||||
"source": "https://github.com/utopia-php/mongo/tree/0.11.0"
|
||||
"source": "https://github.com/utopia-php/mongo/tree/1.0.0"
|
||||
},
|
||||
"time": "2025-10-20T11:11:23+00:00"
|
||||
"time": "2026-02-12T05:54:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/platform",
|
||||
@@ -5389,16 +5389,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.8.28",
|
||||
"version": "1.8.29",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "4762aa017b28a3a7e4e53da6e193d0c196ec3fd4"
|
||||
"reference": "eae24f143aa0e352acc8ae8975a0692fd77d2ec3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/4762aa017b28a3a7e4e53da6e193d0c196ec3fd4",
|
||||
"reference": "4762aa017b28a3a7e4e53da6e193d0c196ec3fd4",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/eae24f143aa0e352acc8ae8975a0692fd77d2ec3",
|
||||
"reference": "eae24f143aa0e352acc8ae8975a0692fd77d2ec3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5434,9 +5434,9 @@
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.8.28"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.8.29"
|
||||
},
|
||||
"time": "2026-02-11T10:35:18+00:00"
|
||||
"time": "2026-02-12T07:22:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@@ -8893,9 +8893,25 @@
|
||||
"time": "2024-03-07T20:33:40+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"aliases": [
|
||||
{
|
||||
"package": "utopia-php/database",
|
||||
"version": "dev-joins8",
|
||||
"alias": "5.0.0",
|
||||
"alias_normalized": "5.0.0.0"
|
||||
},
|
||||
{
|
||||
"package": "utopia-php/migration",
|
||||
"version": "dev-joins",
|
||||
"alias": "1.5.0",
|
||||
"alias_normalized": "1.5.0.0"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"stability-flags": {
|
||||
"utopia-php/database": 20,
|
||||
"utopia-php/migration": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
||||
@@ -99,6 +99,7 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
- ./dev:/usr/src/code/dev
|
||||
# - ./vendor/utopia-php/framework:/usr/src/code/vendor/utopia-php/framework
|
||||
- ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database
|
||||
depends_on:
|
||||
- ${_APP_DB_HOST:-mariadb}
|
||||
- redis
|
||||
|
||||
@@ -152,7 +152,7 @@ As the name implies, `param()` is used to define a request parameter.
|
||||
|
||||
```php
|
||||
App::get('/v1/account/logs')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
```
|
||||
|
||||
### 6. inject
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
stopOnFailure="true"
|
||||
>
|
||||
<extensions>
|
||||
<extension class="Appwrite\Tests\TestHook" />
|
||||
|
||||
@@ -46,7 +46,8 @@ class EventProcessor
|
||||
|
||||
while ($sum >= $limit) {
|
||||
$functions = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('functions', [
|
||||
Query::select(['$id', 'events']),
|
||||
Query::select('$id'),
|
||||
Query::select('events'),
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
Query::orderAsc('$sequence'),
|
||||
|
||||
@@ -75,7 +75,7 @@ class Realtime extends MessagingAdapter
|
||||
|
||||
$strings = [];
|
||||
if (empty($queryGroup)) {
|
||||
$strings[] = Query::select(['*'])->toString();
|
||||
$strings[] = Query::select('*')->toString();
|
||||
} else {
|
||||
foreach ($queryGroup as $query) {
|
||||
$strings[] = $query->toString();
|
||||
@@ -376,7 +376,7 @@ class Realtime extends MessagingAdapter
|
||||
}
|
||||
$subscriptions[0]['channels'][] = $channel;
|
||||
if (empty($subscriptions[0]['queries'])) {
|
||||
$subscriptions[0]['queries'] = [Query::select(['*'])];
|
||||
$subscriptions[0]['queries'] = [Query::select('*')];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
+12
-4
@@ -448,12 +448,20 @@ class Create extends Action
|
||||
}
|
||||
|
||||
try {
|
||||
$dbForProject->withPreserveDates(
|
||||
fn () => $dbForProject->createDocuments(
|
||||
$results = [];
|
||||
|
||||
$dbForProject->withPreserveDates(function () use (&$results, $dbForProject, $database, $collection, $documents) {
|
||||
$dbForProject->createDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
$documents,
|
||||
)
|
||||
);
|
||||
onNext: function ($doc) use (&$results) {
|
||||
$results[] = $doc;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$documents = $results;
|
||||
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception($this->getDuplicateException(), params: [$documentId]);
|
||||
} catch (NotFoundException) {
|
||||
|
||||
+2
-4
@@ -10,6 +10,7 @@ use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\Audit\Audit;
|
||||
@@ -18,9 +19,6 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -67,7 +65,7 @@ class XList extends Action
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
|
||||
+14
@@ -99,6 +99,20 @@ class XList extends Action
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$joins = Query::getJoinQueries($queries, false);
|
||||
foreach ($joins as $join) {
|
||||
$col = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $join->getCollectionId()));
|
||||
|
||||
if ($col->isEmpty() || (!$col->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
|
||||
throw new Exception($this->getParentNotFoundException(), params: [$join->getCollectionId()]);
|
||||
}
|
||||
|
||||
$collectionTableId = 'database_' . $database->getSequence() . '_collection_' . $col->getSequence();
|
||||
|
||||
$join->setCollectionId($collectionTableId);
|
||||
$dbForProject->addJoinCollectionId($collectionTableId);
|
||||
}
|
||||
|
||||
$cursor = Query::getCursorQueries($queries, false);
|
||||
$cursor = \reset($cursor);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use DeviceDetector\DeviceDetector as Detector;
|
||||
use MaxMind\Db\Reader;
|
||||
@@ -18,9 +19,6 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -66,7 +64,7 @@ class XList extends Action
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
|
||||
@@ -8,6 +8,7 @@ use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use DeviceDetector\DeviceDetector as Detector;
|
||||
use MaxMind\Db\Reader;
|
||||
@@ -17,9 +18,6 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -62,7 +60,7 @@ class XList extends Action
|
||||
),
|
||||
])
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
|
||||
@@ -7,6 +7,7 @@ use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use DeviceDetector\DeviceDetector as Detector;
|
||||
use MaxMind\Db\Reader;
|
||||
@@ -16,9 +17,6 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -57,7 +55,7 @@ class XList extends Action
|
||||
),
|
||||
])
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
|
||||
@@ -7,9 +7,8 @@ use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
|
||||
@@ -45,7 +44,7 @@ class XList extends CollectionLogXList
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('tableId', '', new UID(), 'Table ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
|
||||
@@ -7,9 +7,8 @@ use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
|
||||
@@ -46,7 +45,7 @@ class XList extends DocumentLogXList
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('tableId', '', new UID(), 'Table ID.')
|
||||
->param('rowId', '', new UID(), 'Row ID.')
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
|
||||
@@ -12,7 +12,6 @@ use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filters\ListSelection;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Order;
|
||||
@@ -109,7 +108,8 @@ class XList extends Action
|
||||
$selectQueries = Query::groupByType($queries)['selections'] ?? [];
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
|
||||
$projects = $this->find($dbForPlatform, $queries, $selectQueries);
|
||||
$projects = $dbForPlatform->find('projects', $queries);
|
||||
|
||||
$total = $includeTotal ? $dbForPlatform->count('projects', $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (Order $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
@@ -122,73 +122,4 @@ class XList extends Action
|
||||
'total' => $total,
|
||||
]), Response::MODEL_PROJECT_LIST);
|
||||
}
|
||||
|
||||
// Build mapping of columns to their subQuery filters
|
||||
private static function getAttributeToSubQueryFilters(): array
|
||||
{
|
||||
if (self::$attributeToSubQueryFilters !== null) {
|
||||
return self::$attributeToSubQueryFilters;
|
||||
}
|
||||
|
||||
self::$attributeToSubQueryFilters = [];
|
||||
|
||||
$collections = Config::getParam('collections', []);
|
||||
$projectAttributes = $collections['platform']['projects']['attributes'] ?? [];
|
||||
|
||||
foreach ($projectAttributes as $attribute) {
|
||||
$attributeId = $attribute['$id'] ?? null;
|
||||
$filters = $attribute['filters'] ?? [];
|
||||
|
||||
if ($attributeId === null || empty($filters)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// extract only subQuery filters
|
||||
$subQueryFilters = \array_filter($filters, function ($filter) {
|
||||
return \str_starts_with($filter, 'subQuery');
|
||||
});
|
||||
|
||||
if (!empty($subQueryFilters)) {
|
||||
self::$attributeToSubQueryFilters[$attributeId] = \array_values($subQueryFilters);
|
||||
}
|
||||
}
|
||||
|
||||
return self::$attributeToSubQueryFilters;
|
||||
}
|
||||
|
||||
private function find(Database $dbForPlatform, array $queries, array $selectQueries): array
|
||||
{
|
||||
if (empty($selectQueries)) {
|
||||
return $dbForPlatform->find('projects', $queries);
|
||||
}
|
||||
|
||||
$selectedAttributes = [];
|
||||
foreach ($selectQueries as $query) {
|
||||
foreach ($query->getValues() as $value) {
|
||||
$selectedAttributes[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (\in_array('*', $selectedAttributes)) {
|
||||
return $dbForPlatform->find('projects', $queries);
|
||||
}
|
||||
|
||||
$filtersToSkipMap = [];
|
||||
$selectedAttributesMap = \array_flip($selectedAttributes);
|
||||
$attributeToSubQueryFilters = self::getAttributeToSubQueryFilters();
|
||||
|
||||
foreach ($attributeToSubQueryFilters as $attributeName => $subQueryFilters) {
|
||||
if (!isset($selectedAttributesMap[$attributeName])) {
|
||||
foreach ($subQueryFilters as $filter) {
|
||||
$filtersToSkipMap[$filter] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$filtersToSkip = \array_keys($filtersToSkipMap);
|
||||
|
||||
return empty($filtersToSkip)
|
||||
? $dbForPlatform->find('projects', $queries)
|
||||
: $dbForPlatform->skipFilters(fn () => $dbForPlatform->find('projects', $queries), $filtersToSkip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class Get extends Action
|
||||
$storageStats = $authorization->skip(fn () => $dbForLogs->getDocument(
|
||||
'stats',
|
||||
$statsDocId,
|
||||
[Query::select(['value'])]
|
||||
[Query::select('value')]
|
||||
));
|
||||
|
||||
$totalSize = $storageStats->getAttribute('value', 0);
|
||||
|
||||
@@ -138,7 +138,7 @@ class XList extends Action
|
||||
|
||||
return $dbForLogs->find('stats', [
|
||||
Query::equal('$id', $statsIds),
|
||||
Query::select(['value']),
|
||||
Query::select('value'),
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use Appwrite\Platform\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Coroutine\WaitGroup;
|
||||
use Utopia\Config\Adapters\Dotenv as ConfigDotenv;
|
||||
@@ -15,9 +16,6 @@ use Utopia\Config\Exceptions\Parse;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Detector\Detection\Framework\Analog;
|
||||
use Utopia\Detector\Detection\Framework\Angular;
|
||||
use Utopia\Detector\Detection\Framework\Astro;
|
||||
@@ -97,7 +95,7 @@ class XList extends Action
|
||||
->param('installationId', '', new Text(256), 'Installation Id')
|
||||
->param('type', '', new WhiteList(['runtime', 'framework']), 'Detector type. Must be one of the following: runtime, framework')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_OFFSET]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->inject('gitHub')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
|
||||
@@ -353,7 +353,10 @@ class Deletes extends Action
|
||||
$queries[] = Query::equal('resourceType', [$resourceType]);
|
||||
}
|
||||
|
||||
$queries[] = Query::select($this->selects);
|
||||
foreach ($this->selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
$queries[] = Query::orderAsc();
|
||||
|
||||
$this->deleteByGroup(
|
||||
@@ -390,12 +393,16 @@ class Deletes extends Action
|
||||
);
|
||||
|
||||
$queries = [
|
||||
Query::select([...$this->selects, 'accessedAt']),
|
||||
Query::select('accessedAt'),
|
||||
Query::lessThan('accessedAt', $datetime),
|
||||
Query::orderDesc('accessedAt'),
|
||||
Query::orderDesc(),
|
||||
];
|
||||
|
||||
foreach ($this->selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
$this->deleteByGroup(
|
||||
'cache',
|
||||
$queries,
|
||||
@@ -426,27 +433,37 @@ class Deletes extends Action
|
||||
|
||||
$selects = [...$this->selects, 'time'];
|
||||
|
||||
// Delete Usage stats from projectDB
|
||||
$this->deleteByGroup('stats', [
|
||||
Query::select($selects),
|
||||
$queries = [
|
||||
Query::equal('period', ['1h']),
|
||||
Query::lessThan('time', $hourlyUsageRetentionDatetime),
|
||||
Query::orderDesc('time'),
|
||||
Query::orderDesc(),
|
||||
], $dbForProject);
|
||||
];
|
||||
|
||||
foreach ($selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
// Delete Usage stats from projectDB
|
||||
$this->deleteByGroup('stats', $queries, $dbForProject);
|
||||
|
||||
if ($project->getId() !== 'console') {
|
||||
/** @var Database $dbForLogs */
|
||||
$dbForLogs = call_user_func($getLogsDB, $project);
|
||||
|
||||
// Delete Usage stats from logsDB
|
||||
$this->deleteByGroup('stats', [
|
||||
Query::select($selects),
|
||||
$queries = [
|
||||
Query::equal('period', ['1h']),
|
||||
Query::lessThan('time', $hourlyUsageRetentionDatetime),
|
||||
Query::orderDesc('time'),
|
||||
Query::orderDesc(),
|
||||
], $dbForLogs);
|
||||
];
|
||||
|
||||
foreach ($selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
// Delete Usage stats from logsDB
|
||||
$this->deleteByGroup('stats', $queries, $dbForLogs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,13 +770,19 @@ class Deletes extends Action
|
||||
/** @var Database $dbForProject */
|
||||
$dbForProject = $getProjectDB($project);
|
||||
|
||||
// Delete Executions
|
||||
$this->deleteByGroup('executions', [
|
||||
Query::select([...$this->selects, '$createdAt']),
|
||||
$queries = [
|
||||
Query::select('$createdAt'),
|
||||
Query::lessThan('$createdAt', $datetime),
|
||||
Query::orderDesc('$createdAt'),
|
||||
Query::orderDesc(),
|
||||
], $dbForProject);
|
||||
];
|
||||
|
||||
foreach ($this->selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
// Delete Executions
|
||||
$this->deleteByGroup('executions', $queries, $dbForProject);
|
||||
|
||||
/* delete based on custom retention, if any */
|
||||
$this->deleteExecutionsByLimit($project, $getProjectDB, $executionsRetentionCount);
|
||||
@@ -792,7 +815,7 @@ class Deletes extends Action
|
||||
$delete = function (Database $dbForProject, string $resourceInternalId, string $resourceType) use ($executionsRetentionCount) {
|
||||
// get the execution at position `N+1`
|
||||
$execution = $dbForProject->findOne('executions', [
|
||||
Query::select(['$createdAt']),
|
||||
Query::select('$createdAt'),
|
||||
Query::equal('resourceInternalId', [$resourceInternalId]),
|
||||
Query::equal('resourceType', [$resourceType]),
|
||||
Query::orderDesc('$createdAt'),
|
||||
@@ -803,14 +826,19 @@ class Deletes extends Action
|
||||
// delete everything older
|
||||
$cutoffTime = $execution->getAttribute('$createdAt');
|
||||
|
||||
$this->deleteByGroup('executions', [
|
||||
Query::select([...$this->selects, '$createdAt']),
|
||||
$queries = [
|
||||
Query::equal('resourceInternalId', [$resourceInternalId]),
|
||||
Query::equal('resourceType', [$resourceType]),
|
||||
Query::lessThan('$createdAt', $cutoffTime),
|
||||
Query::orderDesc('$createdAt'),
|
||||
Query::orderDesc(),
|
||||
], $dbForProject);
|
||||
];
|
||||
|
||||
foreach ([...$this->selects, '$createdAt'] as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
$this->deleteByGroup('executions', $queries, $dbForProject);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -849,13 +877,19 @@ class Deletes extends Action
|
||||
$duration = $project->getAttribute('auths', [])['duration'] ?? TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
$expired = DateTime::addSeconds(new \DateTime(), -1 * $duration);
|
||||
|
||||
// Delete Sessions
|
||||
$this->deleteByGroup('sessions', [
|
||||
Query::select([...$this->selects, '$createdAt']),
|
||||
$queries = [
|
||||
Query::select('$createdAt'),
|
||||
Query::lessThan('$createdAt', $expired),
|
||||
Query::orderDesc('$createdAt'),
|
||||
Query::orderDesc(),
|
||||
], $dbForProject);
|
||||
];
|
||||
|
||||
foreach ($this->selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
// Delete Sessions
|
||||
$this->deleteByGroup('sessions', $queries, $dbForProject);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -877,14 +911,22 @@ class Deletes extends Action
|
||||
|
||||
Console::info("Deleting CSV export files older than " . $oneWeekAgo);
|
||||
|
||||
$this->deleteByGroup('bucket_' . $bucket->getSequence(), [
|
||||
Query::select([...$this->selects, '$createdAt', 'name', 'path']),
|
||||
$queries = [
|
||||
Query::select('$createdAt'),
|
||||
Query::select('name'),
|
||||
Query::select('path'),
|
||||
Query::equal('bucketId', ['default']),
|
||||
Query::createdBefore($oneWeekAgo),
|
||||
Query::endsWith('name', '.csv'),
|
||||
Query::orderDesc('$createdAt'),
|
||||
Query::orderDesc(),
|
||||
], $dbForPlatform, function (Document $file) use ($deviceForFiles) {
|
||||
];
|
||||
|
||||
foreach ($this->selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
$this->deleteByGroup('bucket_' . $bucket->getSequence(), $queries, $dbForPlatform, function (Document $file) use ($deviceForFiles) {
|
||||
$path = $file->getAttribute('path');
|
||||
if ($deviceForFiles->exists($path)) {
|
||||
$deviceForFiles->delete($path);
|
||||
@@ -988,12 +1030,18 @@ class Deletes extends Action
|
||||
* Delete Logs
|
||||
*/
|
||||
Console::info("Deleting logs for site " . $siteId);
|
||||
$this->deleteByGroup('executions', [
|
||||
Query::select($this->selects),
|
||||
|
||||
$queries = [
|
||||
Query::equal('resourceInternalId', [$siteInternalId]),
|
||||
Query::equal('resourceType', ['sites']),
|
||||
Query::orderAsc()
|
||||
], $dbForProject);
|
||||
];
|
||||
|
||||
foreach ($this->selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
$this->deleteByGroup('executions', $queries, $dbForProject);
|
||||
|
||||
/**
|
||||
* Delete VCS Repositories and VCS Comments
|
||||
@@ -1074,12 +1122,18 @@ class Deletes extends Action
|
||||
* Delete Executions
|
||||
*/
|
||||
Console::info("Deleting executions for function " . $functionId);
|
||||
$this->deleteByGroup('executions', [
|
||||
Query::select($this->selects),
|
||||
|
||||
$queries = [
|
||||
Query::equal('resourceInternalId', [$functionInternalId]),
|
||||
Query::equal('resourceType', ['functions']),
|
||||
Query::orderAsc()
|
||||
], $dbForProject);
|
||||
];
|
||||
|
||||
foreach ($this->selects as $select) {
|
||||
$queries[] = Query::select($select);
|
||||
}
|
||||
|
||||
$this->deleteByGroup('executions', $queries, $dbForProject);
|
||||
|
||||
/**
|
||||
* Delete VCS Repositories and VCS Comments
|
||||
|
||||
@@ -121,7 +121,8 @@ class Functions extends Action
|
||||
$offset = 0;
|
||||
while ($sum >= $limit) {
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::select(['$id', 'events']), // Skip variables subqueries
|
||||
Query::select('$id'), // Skip variables subqueries
|
||||
Query::select('events'),
|
||||
Query::contains('events', $events),
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
|
||||
@@ -44,8 +44,7 @@ class RuntimeQuery extends Query
|
||||
return false;
|
||||
}
|
||||
|
||||
$values = $query->getValues();
|
||||
return count($values) === 1 && $values[0] === '*';
|
||||
return $query->getAttribute() === '*';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,8 +82,7 @@ class RuntimeQuery extends Query
|
||||
// Check for select("*") upfront
|
||||
foreach ($queries as $query) {
|
||||
if ($query->getMethod() === Query::TYPE_SELECT) {
|
||||
$values = $query->getValues();
|
||||
if (count($values) === 1 && $values[0] === '*') {
|
||||
if ($query->getAttribute() === '*') {
|
||||
return ['type' => 'selectAll'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,16 +5,58 @@ namespace Appwrite\Utopia\Database\Validator\Queries;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Filter;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\Query\Order;
|
||||
use Utopia\Database\Validator\Query\Select;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\QueryContext;
|
||||
|
||||
class Base extends Queries
|
||||
class Base extends Types
|
||||
{
|
||||
protected Document $collection;
|
||||
|
||||
protected array $types = [
|
||||
Query::TYPE_LIMIT,
|
||||
Query::TYPE_OFFSET,
|
||||
Query::TYPE_CURSOR_AFTER,
|
||||
Query::TYPE_CURSOR_BEFORE,
|
||||
Query::TYPE_ORDER_ASC,
|
||||
Query::TYPE_ORDER_DESC,
|
||||
Query::TYPE_ORDER_RANDOM,
|
||||
Query::TYPE_EQUAL,
|
||||
Query::TYPE_NOT_EQUAL,
|
||||
Query::TYPE_LESSER,
|
||||
Query::TYPE_LESSER_EQUAL,
|
||||
Query::TYPE_GREATER,
|
||||
Query::TYPE_GREATER_EQUAL,
|
||||
Query::TYPE_SEARCH,
|
||||
Query::TYPE_NOT_SEARCH,
|
||||
Query::TYPE_IS_NULL,
|
||||
Query::TYPE_IS_NOT_NULL,
|
||||
Query::TYPE_BETWEEN,
|
||||
Query::TYPE_NOT_BETWEEN,
|
||||
Query::TYPE_STARTS_WITH,
|
||||
Query::TYPE_NOT_STARTS_WITH,
|
||||
Query::TYPE_ENDS_WITH,
|
||||
Query::TYPE_NOT_ENDS_WITH,
|
||||
Query::TYPE_CONTAINS,
|
||||
Query::TYPE_NOT_CONTAINS,
|
||||
Query::TYPE_AND,
|
||||
Query::TYPE_OR,
|
||||
Query::TYPE_CROSSES,
|
||||
Query::TYPE_NOT_CROSSES,
|
||||
Query::TYPE_DISTANCE_EQUAL,
|
||||
Query::TYPE_DISTANCE_NOT_EQUAL,
|
||||
Query::TYPE_DISTANCE_GREATER_THAN,
|
||||
Query::TYPE_DISTANCE_LESS_THAN,
|
||||
Query::TYPE_INTERSECTS,
|
||||
Query::TYPE_NOT_INTERSECTS,
|
||||
Query::TYPE_OVERLAPS,
|
||||
Query::TYPE_NOT_OVERLAPS,
|
||||
Query::TYPE_TOUCHES,
|
||||
Query::TYPE_NOT_TOUCHES,
|
||||
Query::TYPE_VECTOR_DOT,
|
||||
Query::TYPE_VECTOR_COSINE,
|
||||
Query::TYPE_VECTOR_EUCLIDEAN,
|
||||
];
|
||||
|
||||
/**
|
||||
* Expression constructor
|
||||
*
|
||||
@@ -36,27 +78,18 @@ class Base extends Queries
|
||||
|
||||
$collection = $collections[$collection];
|
||||
|
||||
$allowedAttributesLookup = [];
|
||||
foreach ($allowedAttributes as $attribute) {
|
||||
$allowedAttributesLookup[$attribute] = true;
|
||||
}
|
||||
$this->collection = new Document([
|
||||
'$id' => $collection['$id'],
|
||||
]);
|
||||
|
||||
$allAttributes = [];
|
||||
$attributes = [];
|
||||
foreach ($collection['attributes'] as $attribute) {
|
||||
$key = $attribute['$id'];
|
||||
|
||||
$attributeDocument = new Document([
|
||||
'key' => $key,
|
||||
$attr = new Document([
|
||||
'key' => $attribute['$id'],
|
||||
'type' => $attribute['type'],
|
||||
'array' => $attribute['array'],
|
||||
]);
|
||||
|
||||
$allAttributes[] = $attributeDocument;
|
||||
|
||||
if (isset($allowedAttributesLookup[$key])) {
|
||||
$attributes[] = $attributeDocument;
|
||||
}
|
||||
$this->collection->setAttribute('attributes', $attr, Document::SET_TYPE_APPEND);
|
||||
}
|
||||
|
||||
$internalAttributes = [
|
||||
@@ -83,23 +116,18 @@ class Base extends Queries
|
||||
];
|
||||
|
||||
foreach ($internalAttributes as $attribute) {
|
||||
$attributes[] = $attribute;
|
||||
$allAttributes[] = $attribute;
|
||||
$this->collection->setAttribute('attributes', $attribute, Document::SET_TYPE_APPEND);
|
||||
$allowedAttributes[] = $attribute['key'];
|
||||
}
|
||||
|
||||
$validators = [
|
||||
new Limit(),
|
||||
new Offset(),
|
||||
new Cursor(),
|
||||
new Filter($attributes, APP_DATABASE_QUERY_MAX_VALUES),
|
||||
new Order($attributes),
|
||||
];
|
||||
|
||||
if ($this->isSelectQueryAllowed()) {
|
||||
$validators[] = new Select($allAttributes);
|
||||
$this->types[] = Query::TYPE_SELECT;
|
||||
}
|
||||
|
||||
parent::__construct($validators);
|
||||
$context = new QueryContext();
|
||||
$context->add($this->collection);
|
||||
|
||||
parent::__construct($this->types, $context, $allowedAttributes);
|
||||
}
|
||||
|
||||
public function isSelectQueryAllowed(): bool
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Queries;
|
||||
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\QueryContext;
|
||||
use Utopia\Database\Validator\Queries\V2 as DocumentsValidator;
|
||||
use Utopia\Validator;
|
||||
|
||||
class Types extends Validator
|
||||
{
|
||||
protected string $message = 'Invalid queries';
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
protected array $types;
|
||||
|
||||
protected ?QueryContext $context = null;
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private array $allowedAttributes;
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
* @param QueryContext|null $context
|
||||
* @param array<string> $allowedAttributes
|
||||
*/
|
||||
public function __construct(array $types = [], ?QueryContext $context = null, array $allowedAttributes = [])
|
||||
{
|
||||
$this->types = $types;
|
||||
|
||||
if (is_null($context)) {
|
||||
$context = new QueryContext();
|
||||
}
|
||||
|
||||
$this->context = $context;
|
||||
$this->allowedAttributes = $allowedAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Description.
|
||||
*
|
||||
* Returns validator description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Query|string> $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($value): bool
|
||||
{
|
||||
try {
|
||||
if (!is_array($value)) {
|
||||
throw new \Exception('Queries must be an array');
|
||||
}
|
||||
|
||||
foreach ($value as $query) {
|
||||
if (!$query instanceof Query) {
|
||||
$query = Query::parse($query);
|
||||
}
|
||||
|
||||
if ($query->isNested()) {
|
||||
if (!$this->isValid($query->getValues())) {
|
||||
throw new \Exception('Invalid queries');
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_array($query->getMethod(), $this->types)) {
|
||||
throw new \Exception("Query method {$query->getMethod()} not allowed");
|
||||
}
|
||||
|
||||
if (
|
||||
$query->getMethod() !== Query::TYPE_SELECT &&
|
||||
!empty($query->getAttribute()) &&
|
||||
!in_array($query->getAttribute(), $this->allowedAttributes)
|
||||
) {
|
||||
throw new \Exception("Invalid query: Attribute not found in schema: {$query->getAttribute()}");
|
||||
}
|
||||
}
|
||||
|
||||
$validator = new DocumentsValidator(
|
||||
$this->context,
|
||||
Database::VAR_INTEGER
|
||||
);
|
||||
|
||||
if (!$validator->isValid($value)) {
|
||||
throw new \Exception($validator->getDescription());
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
$this->message = $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is array
|
||||
*
|
||||
* Function will return true if object is array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isArray(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* Returns validator type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return self::TYPE_OBJECT;
|
||||
}
|
||||
}
|
||||
@@ -242,29 +242,58 @@ class V17 extends Filter
|
||||
case Query::TYPE_ENDS_WITH:
|
||||
$attribute = $parsedParams[0] ?? '';
|
||||
if (count($parsedParams) < 2) {
|
||||
return new Query($method, $attribute);
|
||||
return Query::parseQuery([
|
||||
'method' => $method,
|
||||
'attribute' => $attribute,
|
||||
]);
|
||||
}
|
||||
return new Query($method, $attribute, \is_array($parsedParams[1]) ? $parsedParams[1] : [$parsedParams[1]]);
|
||||
|
||||
return Query::parseQuery([
|
||||
'method' => $method,
|
||||
'attribute' => $attribute,
|
||||
'values' => \is_array($parsedParams[1]) ? $parsedParams[1] : [$parsedParams[1]],
|
||||
]);
|
||||
|
||||
case Query::TYPE_BETWEEN:
|
||||
return new Query($method, $parsedParams[0], [$parsedParams[1], $parsedParams[2]]);
|
||||
return Query::parseQuery([
|
||||
'method' => $method,
|
||||
'attribute' => $parsedParams[0],
|
||||
'values' => [$parsedParams[1], $parsedParams[2]],
|
||||
]);
|
||||
|
||||
|
||||
case Query::TYPE_SELECT:
|
||||
return new Query($method, values: $parsedParams[0]);
|
||||
return Query::parseQuery([
|
||||
'method' => $method,
|
||||
'values' => $parsedParams[0],
|
||||
]);
|
||||
|
||||
case Query::TYPE_ORDER_ASC:
|
||||
case Query::TYPE_ORDER_DESC:
|
||||
return new Query($method, $parsedParams[0] ?? '');
|
||||
return Query::parseQuery([
|
||||
'method' => $method,
|
||||
'attribute' => $parsedParams[0] ?? '',
|
||||
]);
|
||||
|
||||
case Query::TYPE_LIMIT:
|
||||
case Query::TYPE_OFFSET:
|
||||
case Query::TYPE_CURSOR_AFTER:
|
||||
case Query::TYPE_CURSOR_BEFORE:
|
||||
if (count($parsedParams) > 0) {
|
||||
return new Query($method, values: [$parsedParams[0]]);
|
||||
return Query::parseQuery([
|
||||
'method' => $method,
|
||||
'values' => [$parsedParams[0]],
|
||||
]);
|
||||
}
|
||||
return new Query($method);
|
||||
|
||||
return Query::parseQuery([
|
||||
'method' => $method,
|
||||
]);
|
||||
|
||||
default:
|
||||
return new Query($method);
|
||||
return Query::parseQuery([
|
||||
'method' => $method,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,10 @@ class V20 extends Filter
|
||||
);
|
||||
|
||||
// Add wildcard + relationship(s) selects
|
||||
$parsed[] = Query::select($selects);
|
||||
$parsed[] = Query::parseQuery([
|
||||
'method' => Query::TYPE_SELECT,
|
||||
'values' => $selects,
|
||||
]);
|
||||
}
|
||||
|
||||
$resolvedQueries = [];
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Request\Filters;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Request\Filter;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class V22 extends Filter
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private array $internalAttributes = [
|
||||
'$id',
|
||||
'$sequence',
|
||||
'$permissions',
|
||||
'$createdAt',
|
||||
'$updatedAt',
|
||||
];
|
||||
|
||||
public function parse(array $content, string $model): array
|
||||
{
|
||||
if (!isset($content['queries'])) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return $this->convertSelectQueries($content);
|
||||
}
|
||||
|
||||
private function convertSelectQueries(array $content): array
|
||||
{
|
||||
try {
|
||||
$parsed = Query::parseQueries($content['queries']);
|
||||
} catch (QueryException $e) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$queries = [];
|
||||
$selects = [];
|
||||
|
||||
foreach ($parsed as $query) {
|
||||
if ($query->getMethod() === 'select') {
|
||||
foreach ($query->getValues() as $val) {
|
||||
$selects[] = $val;
|
||||
}
|
||||
} else {
|
||||
$queries[] = $query;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($selects)) {
|
||||
$queries = array_merge($queries, $this->expandSelects($selects));
|
||||
}
|
||||
|
||||
// Convert all queries to string
|
||||
$resolvedQueries = [];
|
||||
foreach ($queries as $query) {
|
||||
$resolvedQueries[] = $query->toString();
|
||||
}
|
||||
|
||||
$content['queries'] = $resolvedQueries;
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
private function expandSelects(array $selects): array
|
||||
{
|
||||
$expanded = [];
|
||||
$addedInternalForLevel = [];
|
||||
|
||||
foreach ($selects as $select) {
|
||||
$expanded[] = Query::select($select);
|
||||
|
||||
if ($select === '*') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parts = explode('.', $select);
|
||||
$prefix = implode('.', array_slice($parts, 0, -1)); // empty string for top level
|
||||
|
||||
if (!isset($addedInternalForLevel[$prefix])) {
|
||||
foreach ($this->internalAttributes as $attr) {
|
||||
$expanded[] = Query::select($prefix ? "$prefix.$attr" : $attr);
|
||||
}
|
||||
$addedInternalForLevel[$prefix] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $expanded;
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,11 @@ class ListSelection extends Filter
|
||||
|
||||
$selections = [];
|
||||
foreach ($this->selectQueries as $query) {
|
||||
foreach ($query->getValues() as $value) {
|
||||
if ($value === '*') {
|
||||
return $content;
|
||||
}
|
||||
$selections[$value] = true;
|
||||
if ($query->getAttribute() === '*') {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$selections[$query->getAttribute()] = true;
|
||||
}
|
||||
|
||||
return $this->handleList($content, $this->itemsKey, function (array $item) use ($selections) {
|
||||
|
||||
@@ -83,7 +83,7 @@ class Document extends Any
|
||||
$document->removeAttribute('$collection');
|
||||
$document->removeAttribute('$tenant');
|
||||
|
||||
if (!$document->isEmpty()) {
|
||||
if ($document->offsetExists('$sequence')) {
|
||||
$document->setAttribute('$sequence', (int)$document->getAttribute('$sequence', 0));
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,10 @@ class Row extends Any
|
||||
{
|
||||
$document->removeAttribute('$collection');
|
||||
$document->removeAttribute('$tenant');
|
||||
$document->setAttribute('$sequence', (int)$document->getAttribute('$sequence', 0));
|
||||
|
||||
if ($document->offsetExists('$sequence')) {
|
||||
$document->setAttribute('$sequence', (int)$document->getAttribute('$sequence', 0));
|
||||
}
|
||||
|
||||
foreach ($document->getAttributes() as $column) {
|
||||
if (\is_array($column)) {
|
||||
|
||||
@@ -185,6 +185,14 @@ class Client
|
||||
$responseHeaders = [];
|
||||
$cookies = [];
|
||||
|
||||
if (isset($params['queries'])) {
|
||||
foreach ($params['queries'] as $value) {
|
||||
if (!is_string($value)) {
|
||||
throw new Exception('Queries must be converted to strings');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$query = match ($headers['content-type']) {
|
||||
'application/json' => json_encode($params),
|
||||
'multipart/form-data' => $this->flatten($params),
|
||||
|
||||
@@ -411,7 +411,7 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'queries' => [Query::select(['key'])->toString()],
|
||||
'queries' => [Query::select('key')->toString()],
|
||||
]);
|
||||
$this->assertEquals(Exception::GENERAL_ARGUMENT_INVALID, $response['body']['type']);
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
@@ -1576,7 +1576,7 @@ trait DatabasesBase
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['key'])->toString(),
|
||||
Query::select('key')->toString(),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(Exception::GENERAL_ARGUMENT_INVALID, $response['body']['type']);
|
||||
@@ -1619,6 +1619,7 @@ trait DatabasesBase
|
||||
'title' => 'Spider-Man: Far From Home',
|
||||
'releaseYear' => 2019,
|
||||
'birthDay' => null,
|
||||
'duration' => null,
|
||||
'actors' => [
|
||||
'Tom Holland',
|
||||
'Zendaya Maree Stoermer',
|
||||
@@ -1677,6 +1678,7 @@ trait DatabasesBase
|
||||
$this->assertEquals($databaseId, $document1['body']['$databaseId']);
|
||||
$this->assertEquals($document1['body']['title'], 'Captain America');
|
||||
$this->assertEquals($document1['body']['releaseYear'], 1944);
|
||||
$this->assertArrayNotHasKey('duration', $document1['body']);
|
||||
$this->assertIsArray($document1['body']['$permissions']);
|
||||
$this->assertCount(3, $document1['body']['$permissions']);
|
||||
$this->assertCount(2, $document1['body']['actors']);
|
||||
@@ -1976,7 +1978,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
Query::equal('library', ['library1'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -2014,7 +2017,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
Query::equal('library', ['library1'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -2052,7 +2056,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString()
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(2, $documents['body']['total']);
|
||||
@@ -2211,7 +2216,9 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString()
|
||||
Query::select('$permissions')->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
],
|
||||
]);
|
||||
$this->assertGreaterThanOrEqual(1, $documents['body']['total']);
|
||||
@@ -2422,30 +2429,59 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['title', 'releaseYear', '$id'])->toString(),
|
||||
Query::select('title')->toString(),
|
||||
Query::select('releaseYear')->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('$sequence')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($document['title'], $response['body']['title']);
|
||||
$this->assertEquals($document['releaseYear'], $response['body']['releaseYear']);
|
||||
$this->assertEquals($document['$sequence'], $response['body']['$sequence']);
|
||||
$this->assertArrayNotHasKey('birthDay', $response['body']);
|
||||
$sequence = $response['body']['$sequence'];
|
||||
$this->assertArrayHasKey('$sequence', $response['body']);
|
||||
|
||||
$sequence = (string)$response['body']['$sequence'];
|
||||
|
||||
// Query by sequence
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $document['$collectionId'] . '/documents/' . $document['$id'], array_merge([
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $document['$collectionId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::equal('$sequence', [$sequence])
|
||||
Query::equal('$sequence', [$sequence])->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($document['title'], $response['body']['title']);
|
||||
$this->assertEquals($document['releaseYear'], $response['body']['releaseYear']);
|
||||
$this->assertTrue(array_key_exists('$sequence', $response['body']));
|
||||
$this->assertEquals(1, $response['body']['total']);
|
||||
$this->assertEquals($document['title'], $response['body']['documents'][0]['title']);
|
||||
$this->assertEquals($document['releaseYear'], $response['body']['documents'][0]['releaseYear']);
|
||||
$this->assertEquals($document['$sequence'], $response['body']['documents'][0]['$sequence']);
|
||||
|
||||
/**
|
||||
* Use specific X-Appwrite-Response-Format 1.8.0
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $document['$collectionId'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'X-Appwrite-Response-Format' => '1.8.0',
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
'{"method":"select","values":["title"]}',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertArrayHasKey('title', $response['body']['documents'][0]);
|
||||
$this->assertArrayNotHasKey('birthDay', $response['body']['documents'][0]);
|
||||
$this->assertArrayHasKey('$sequence', $response['body']['documents'][0]);
|
||||
$this->assertArrayHasKey('$id', $response['body']['documents'][0]);
|
||||
$this->assertArrayHasKey('$createdAt', $response['body']['documents'][0]);
|
||||
$this->assertArrayHasKey('$updatedAt', $response['body']['documents'][0]);
|
||||
$this->assertArrayHasKey('$permissions', $response['body']['documents'][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5122,7 +5158,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
Query::equal('library', ['library1'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -5136,7 +5173,7 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['library.*'])->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
Query::equal('library.libraryName', ['Library 1'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -5294,7 +5331,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'libraries.*'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('libraries.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5308,7 +5346,7 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['person_one_to_many.$id'])->toString()
|
||||
Query::select('person_one_to_many.$id')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5462,7 +5500,9 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'artist.name', 'artist.$permissions'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('artist.name')->toString(),
|
||||
Query::select('artist.$permissions')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5478,7 +5518,10 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'albums.$id', 'albums.name', 'albums.$permissions'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('albums.$id')->toString(),
|
||||
Query::select('albums.name')->toString(),
|
||||
Query::select('albums.$permissions')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5623,7 +5666,9 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'players.name', 'players.$permissions'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('players.name')->toString(),
|
||||
Query::select('players.$permissions')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5641,7 +5686,10 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'sports.$id', 'sports.name', 'sports.$permissions'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('sports.$id')->toString(),
|
||||
Query::select('sports.name')->toString(),
|
||||
Query::select('sports.$permissions')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5671,7 +5719,8 @@ trait DatabasesBase
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::isNotNull('$id')->toString(),
|
||||
Query::select(['*', 'libraries.*'])->toString(),
|
||||
Query::select('*')->toString(),
|
||||
Query::select('libraries.*')->toString(),
|
||||
Query::startsWith('fullName', 'Stevie')->toString(),
|
||||
Query::endsWith('fullName', 'Wonder')->toString(),
|
||||
Query::between('$createdAt', '1975-12-06', '2050-12-01')->toString(),
|
||||
@@ -5691,7 +5740,7 @@ trait DatabasesBase
|
||||
'queries' => [
|
||||
Query::isNotNull('$id')->toString(),
|
||||
Query::isNull('fullName')->toString(),
|
||||
Query::select(['fullName'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -5714,7 +5763,7 @@ trait DatabasesBase
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::equal('fullName', ['Stevie Wonder'])->toString(),
|
||||
Query::select(['fullName'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -5728,7 +5777,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['libraries.*', '$id'])->toString(),
|
||||
Query::select('libraries.*')->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
],
|
||||
]);
|
||||
$document = $response['body']['documents'][0];
|
||||
@@ -5742,7 +5792,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', '$id'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -5872,7 +5923,8 @@ trait DatabasesBase
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'queries' => [
|
||||
Query::select(['first_name', 'last_name'])->toString(),
|
||||
Query::select('first_name')->toString(),
|
||||
Query::select('last_name')->toString(),
|
||||
Query::or([
|
||||
Query::equal('first_name', ['Donald']),
|
||||
Query::equal('last_name', ['Bush'])
|
||||
@@ -7355,7 +7407,10 @@ trait DatabasesBase
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [Query::select(['name', 'pointAttr'])->toString()]
|
||||
'queries' => [
|
||||
Query::select('name')->toString(),
|
||||
Query::select('pointAttr')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
@@ -7410,7 +7465,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['name', 'pointAttr'])->toString(),
|
||||
Query::select('name')->toString(),
|
||||
Query::select('pointAttr')->toString(),
|
||||
Query::orderAsc('name')->toString(),
|
||||
Query::limit(1)->toString()
|
||||
]
|
||||
@@ -7559,7 +7615,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['name', 'location.coordinates'])->toString()
|
||||
Query::select('name')->toString(),
|
||||
Query::select('location.coordinates')->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $fetched['headers']['status-code']);
|
||||
@@ -7693,7 +7750,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['point', 'person.$id'])->toString()
|
||||
Query::select('point')->toString(),
|
||||
Query::select('person.$id')->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $visitDoc['headers']['status-code']);
|
||||
@@ -7818,7 +7876,7 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['stores.$id'])->toString()
|
||||
Query::select('stores.$id')->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $city['headers']['status-code']);
|
||||
@@ -7943,7 +8001,7 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['drivers.$id'])->toString()
|
||||
Query::select('drivers.$id')->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $zone['headers']['status-code']);
|
||||
|
||||
@@ -94,6 +94,34 @@ class DatabasesConsoleClientTest extends Scope
|
||||
$this->assertEquals(201, $tvShows['headers']['status-code']);
|
||||
$this->assertEquals($tvShows['body']['name'], 'TvShows');
|
||||
|
||||
/**
|
||||
* Check select queries are disabled in Base class
|
||||
*/
|
||||
$list = $this->client->call(Client::METHOD_GET, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select('name')->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(400, $list['headers']['status-code']);
|
||||
$this->assertEquals('Invalid `queries` param: Query method select not allowed', $list['body']['message']);
|
||||
|
||||
/**
|
||||
* Check allowed attribute filters
|
||||
*/
|
||||
$list = $this->client->call(Client::METHOD_GET, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::equal('enabled', [true])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(400, $list['headers']['status-code']);
|
||||
$this->assertEquals('Invalid `queries` param: Invalid query: Attribute not found in schema: enabled', $list['body']['message']);
|
||||
|
||||
return ['moviesId' => $movies['body']['$id'], 'databaseId' => $databaseId, 'tvShowsId' => $tvShows['body']['$id']];
|
||||
}
|
||||
|
||||
|
||||
@@ -3830,7 +3830,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
Query::select('new_level_2.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -3944,7 +3944,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
Query::select('new_level_2.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -4058,7 +4058,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
Query::select('new_level_2.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -4073,7 +4073,8 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'level1.*'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('level1.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -4176,7 +4177,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
Query::select('new_level_2.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -4191,7 +4192,8 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'level1.*'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('level1.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'queries' => [Query::select(['key'])->toString()],
|
||||
'queries' => [Query::select('key')->toString()],
|
||||
]);
|
||||
$this->assertEquals(Exception::GENERAL_ARGUMENT_INVALID, $response['body']['type']);
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
@@ -1534,7 +1534,7 @@ trait DatabasesBase
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['key'])->toString(),
|
||||
Query::select('key')->toString(),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(Exception::GENERAL_ARGUMENT_INVALID, $response['body']['type']);
|
||||
@@ -1577,6 +1577,7 @@ trait DatabasesBase
|
||||
'title' => 'Spider-Man: Far From Home',
|
||||
'releaseYear' => 2019,
|
||||
'birthDay' => null,
|
||||
'duration' => null,
|
||||
'actors' => [
|
||||
'Tom Holland',
|
||||
'Zendaya Maree Stoermer',
|
||||
@@ -1951,7 +1952,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
Query::equal('library', ['library1'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -1989,7 +1991,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
Query::equal('library', ['library1'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -2027,7 +2030,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString()
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString()
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -2187,7 +2191,9 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString()
|
||||
Query::select('$permissions')->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString()
|
||||
],
|
||||
]);
|
||||
$this->assertGreaterThanOrEqual(1, $rows['body']['total']);
|
||||
@@ -2350,14 +2356,59 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['title', 'releaseYear', '$id'])->toString(),
|
||||
Query::select('title')->toString(),
|
||||
Query::select('releaseYear')->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('$sequence')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($row['title'], $response['body']['title']);
|
||||
$this->assertEquals($row['releaseYear'], $response['body']['releaseYear']);
|
||||
$this->assertEquals($row['$sequence'], $response['body']['$sequence']);
|
||||
$this->assertArrayNotHasKey('birthDay', $response['body']);
|
||||
$this->assertArrayHasKey('$sequence', $response['body']);
|
||||
|
||||
$sequence = (string)$response['body']['$sequence'];
|
||||
|
||||
// Query by sequence
|
||||
$response = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $row['$tableId'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::equal('$sequence', [$sequence])->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(1, $response['body']['total']);
|
||||
$this->assertEquals($row['title'], $response['body']['rows'][0]['title']);
|
||||
$this->assertEquals($row['releaseYear'], $response['body']['rows'][0]['releaseYear']);
|
||||
$this->assertEquals($row['$sequence'], $response['body']['rows'][0]['$sequence']);
|
||||
|
||||
/**
|
||||
* Use specific X-Appwrite-Response-Format 1.8.0
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $row['$tableId'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'X-Appwrite-Response-Format' => '1.8.0',
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
'{"method":"select","values":["title"]}',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertArrayHasKey('title', $response['body']['rows'][0]);
|
||||
$this->assertArrayNotHasKey('birthDay', $response['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$sequence', $response['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$id', $response['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$createdAt', $response['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$updatedAt', $response['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$permissions', $response['body']['rows'][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5038,7 +5089,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
Query::equal('library', ['library1'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -5052,7 +5104,7 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['library.*'])->toString(),
|
||||
Query::select('library.*')->toString(),
|
||||
Query::equal('library.libraryName', ['Library 1'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -5210,7 +5262,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'libraries.*'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('libraries.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5224,7 +5277,7 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['person_one_to_many.$id'])->toString()
|
||||
Query::select('person_one_to_many.$id')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5378,7 +5431,9 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'artist.name', 'artist.$permissions'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('artist.name')->toString(),
|
||||
Query::select('artist.$permissions')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5394,7 +5449,10 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'albums.$id', 'albums.name', 'albums.$permissions'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('albums.$id')->toString(),
|
||||
Query::select('albums.name')->toString(),
|
||||
Query::select('albums.$permissions')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5539,7 +5597,9 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'players.name', 'players.$permissions'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('players.name')->toString(),
|
||||
Query::select('players.$permissions')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5557,7 +5617,10 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'sports.$id', 'sports.name', 'sports.$permissions'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('sports.$id')->toString(),
|
||||
Query::select('sports.name')->toString(),
|
||||
Query::select('sports.$permissions')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -5587,7 +5650,8 @@ trait DatabasesBase
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::isNotNull('$id')->toString(),
|
||||
Query::select(['*', 'libraries.*'])->toString(),
|
||||
Query::select('*')->toString(),
|
||||
Query::select('libraries.*')->toString(),
|
||||
Query::startsWith('fullName', 'Stevie')->toString(),
|
||||
Query::endsWith('fullName', 'Wonder')->toString(),
|
||||
Query::between('$createdAt', '1975-12-06', '2050-12-01')->toString(),
|
||||
@@ -5607,7 +5671,7 @@ trait DatabasesBase
|
||||
'queries' => [
|
||||
Query::isNotNull('$id')->toString(),
|
||||
Query::isNull('fullName')->toString(),
|
||||
Query::select(['fullName'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -5630,7 +5694,7 @@ trait DatabasesBase
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::equal('fullName', ['Stevie Wonder'])->toString(),
|
||||
Query::select(['fullName'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -5644,7 +5708,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['libraries.*', '$id'])->toString(),
|
||||
Query::select('libraries.*')->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
],
|
||||
]);
|
||||
$row = $response['body']['rows'][0];
|
||||
@@ -5658,7 +5723,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', '$id'])->toString(),
|
||||
Query::select('fullName')->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -5788,7 +5854,8 @@ trait DatabasesBase
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'queries' => [
|
||||
Query::select(['first_name', 'last_name'])->toString(),
|
||||
Query::select('first_name')->toString(),
|
||||
Query::select('last_name')->toString(),
|
||||
Query::or([
|
||||
Query::equal('first_name', ['Donald']),
|
||||
Query::equal('last_name', ['Bush'])
|
||||
@@ -5925,7 +5992,8 @@ trait DatabasesBase
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'queries' => [
|
||||
Query::select(['title', 'genre'])->toString(),
|
||||
Query::select('title')->toString(),
|
||||
Query::select('genre')->toString(),
|
||||
Query::notContains('title', ['Spider'])->toString(),
|
||||
Query::limit(999)->toString(),
|
||||
Query::offset(0)->toString()
|
||||
@@ -9065,7 +9133,10 @@ trait DatabasesBase
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [Query::select(['name', 'pointAttr'])->toString()]
|
||||
'queries' => [
|
||||
Query::select('name')->toString(),
|
||||
Query::select('pointAttr')->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(3, $response['body']['rows']);
|
||||
@@ -9115,7 +9186,8 @@ trait DatabasesBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['name', 'pointAttr'])->toString(),
|
||||
Query::select('name')->toString(),
|
||||
Query::select('pointAttr')->toString(),
|
||||
Query::orderAsc('name')->toString(),
|
||||
Query::limit(1)->toString()
|
||||
]
|
||||
|
||||
@@ -16,6 +16,270 @@ class DatabasesConsoleClientTest extends Scope
|
||||
use ProjectCustom;
|
||||
use SideConsole;
|
||||
|
||||
public function testJoins(): void
|
||||
{
|
||||
// todo: Move to Base class
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => 'joins',
|
||||
'name' => 'Joins'
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($database['body']['$id']);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('Joins', $database['body']['name']);
|
||||
$this->assertEquals('tablesdb', $database['body']['type']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$users = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => 'users',
|
||||
'name' => 'users',
|
||||
'rowSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $users['headers']['status-code']);
|
||||
$this->assertEquals($users['body']['name'], 'users');
|
||||
|
||||
$sessions = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => 'sessions',
|
||||
'name' => 'sessions',
|
||||
'rowSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $sessions['headers']['status-code']);
|
||||
$this->assertEquals($sessions['body']['name'], 'sessions');
|
||||
|
||||
/**
|
||||
* Create columns users
|
||||
*/
|
||||
$username = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $users['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'username',
|
||||
'size' => 256,
|
||||
'required' => false,
|
||||
]);
|
||||
$this->assertEquals('username', $username['body']['key']);
|
||||
|
||||
$age = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $users['body']['$id'] . '/columns/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'age',
|
||||
'required' => false,
|
||||
'min' => 0,
|
||||
'max' => 100,
|
||||
]);
|
||||
$this->assertEquals('age', $age['body']['key']);
|
||||
|
||||
/**
|
||||
* Create columns sessions
|
||||
*/
|
||||
$userId = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $sessions['body']['$id'] . '/columns/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'userId',
|
||||
'required' => false,
|
||||
]);
|
||||
$this->assertEquals('userId', $userId['body']['key']);
|
||||
|
||||
sleep(2);
|
||||
|
||||
$abraham = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $users['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'username' => 'Abraham',
|
||||
'age' => 50,
|
||||
],
|
||||
'permissions' => [
|
||||
//Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $abraham['headers']['status-code']);
|
||||
$this->assertEquals('Abraham', $abraham['body']['username']);
|
||||
$this->assertEquals(50, $abraham['body']['age']);
|
||||
$this->assertEquals(1, $abraham['body']['$sequence']);
|
||||
|
||||
$bill = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $users['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'username' => 'Bill',
|
||||
'age' => 40,
|
||||
],
|
||||
'permissions' => [
|
||||
//Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $bill['headers']['status-code']);
|
||||
$this->assertEquals('Bill', $bill['body']['username']);
|
||||
$this->assertEquals(40, $bill['body']['age']);
|
||||
$this->assertEquals(2, $bill['body']['$sequence']);
|
||||
|
||||
$session1 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $sessions['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'userId' => $abraham['body']['$sequence'],
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals($abraham['body']['$sequence'], $session1['body']['userId']);
|
||||
$this->assertEquals(201, $session1['headers']['status-code']);
|
||||
|
||||
$session2 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $sessions['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'userId' => $bill['body']['$sequence'],
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $session2['headers']['status-code']);
|
||||
$this->assertEquals($bill['body']['$sequence'], $session2['body']['userId']);
|
||||
|
||||
/**
|
||||
* Simple join query
|
||||
*/
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $users['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::join($sessions['body']['$id'], 'B', [
|
||||
Query::relationEqual('', '$sequence', 'B', 'userId')
|
||||
])->toString(),
|
||||
Query::orderDesc('username', '')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(2, $rows['body']['total']);
|
||||
$this->assertEquals('Bill', $rows['body']['rows'][0]['username']);
|
||||
$this->assertEquals(40, $rows['body']['rows'][0]['age']);
|
||||
$this->assertEquals('Abraham', $rows['body']['rows'][1]['username']);
|
||||
$this->assertArrayHasKey('$id', $rows['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$sequence', $rows['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$createdAt', $rows['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$updatedAt', $rows['body']['rows'][0]);
|
||||
$this->assertArrayHasKey('$permissions', $rows['body']['rows'][0]);
|
||||
$this->assertArrayNotHasKey('userId', $rows['body']['rows'][0]);
|
||||
|
||||
/**
|
||||
* Simple join query with select queries
|
||||
*/
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $users['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select('username', '')->toString(),
|
||||
Query::select('userId', 'B')->toString(),
|
||||
Query::join($sessions['body']['$id'], 'B', [
|
||||
Query::relationEqual('', '$sequence', 'B', 'userId')
|
||||
])->toString(),
|
||||
Query::orderDesc('username', '')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(2, $rows['body']['total']);
|
||||
$this->assertEquals('Bill', $rows['body']['rows'][0]['username']);
|
||||
$this->assertEquals('Abraham', $rows['body']['rows'][1]['username']);
|
||||
$this->assertEquals($bill['body']['$sequence'], $rows['body']['rows'][0]['userId']);
|
||||
$this->assertEquals($abraham['body']['$sequence'], $rows['body']['rows'][1]['userId']);
|
||||
$this->assertArrayNotHasKey('age', $rows['body']['rows'][0]);
|
||||
$this->assertArrayNotHasKey('$id', $rows['body']['rows'][0]);
|
||||
$this->assertArrayNotHasKey('$sequence', $rows['body']['rows'][0]);
|
||||
$this->assertArrayNotHasKey('$createdAt', $rows['body']['rows'][0]);
|
||||
$this->assertArrayNotHasKey('$updatedAt', $rows['body']['rows'][0]);
|
||||
$this->assertArrayNotHasKey('$permissions', $rows['body']['rows'][0]);
|
||||
|
||||
/**
|
||||
* Join query + equal query
|
||||
*/
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $users['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select('*', 'B')->toString(),
|
||||
Query::equal('userId', [$bill['body']['$sequence']], 'B')->toString(),
|
||||
Query::join($sessions['body']['$id'], 'B', [
|
||||
Query::relationEqual('', '$sequence', 'B', 'userId')
|
||||
])->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(1, $rows['body']['total']);
|
||||
$this->assertEquals($bill['body']['$sequence'], $rows['body']['rows'][0]['userId']);
|
||||
$this->assertArrayNotHasKey('username', $rows['body']['rows'][0]);
|
||||
|
||||
/**
|
||||
* Right join with on equal query in ON clause
|
||||
*/
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $users['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select('username', '')->toString(),
|
||||
Query::select('userId', 'B')->toString(),
|
||||
Query::equal('username', ['dsdsds'])->toString(),
|
||||
Query::rightJoin($sessions['body']['$id'], 'B', [
|
||||
Query::relationEqual('', '$sequence', 'B', 'userId'),
|
||||
Query::equal('userId', [$bill['body']['$sequence']], 'B')
|
||||
])->toString(),
|
||||
Query::orderAsc('userId')
|
||||
],
|
||||
]);
|
||||
var_dump($rows);
|
||||
$this->assertEquals(2, $rows['body']['total']);
|
||||
$this->assertEquals(null, $rows['body']['rows'][0]['username']);
|
||||
$this->assertEquals($abraham['body']['$sequence'], $rows['body']['rows'][0]['userId']);
|
||||
$this->assertEquals('Bill', $rows['body']['rows'][1]['username']);
|
||||
$this->assertEquals($bill['body']['$sequence'], $rows['body']['rows'][1]['userId']);
|
||||
|
||||
|
||||
$this->assertEquals('shmuel123', 'fogel');
|
||||
}
|
||||
|
||||
|
||||
public function testCreateTable(): array
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', array_merge([
|
||||
|
||||
@@ -3759,7 +3759,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
Query::select('new_level_2.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -3873,7 +3873,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
Query::select('new_level_2.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -3987,7 +3987,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
Query::select('new_level_2.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -4002,7 +4002,8 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'level1.*'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('level1.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -4105,7 +4106,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
Query::select('new_level_2.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -4120,7 +4121,8 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'level1.*'])->toString()
|
||||
Query::select('*')->toString(),
|
||||
Query::select('level1.*')->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
@@ -873,7 +873,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
$deployments = $this->listDeployments($functionId, [
|
||||
'queries' => [
|
||||
Query::select(['status'])->toString(),
|
||||
Query::select('status')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -886,7 +886,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
// Extra select query check, for attribute not allowed by filter queries
|
||||
$deployments = $this->listDeployments($functionId, [
|
||||
'queries' => [
|
||||
Query::select(['buildLogs'])->toString(),
|
||||
Query::select('buildLogs')->toString(),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals($deployments['headers']['status-code'], 200);
|
||||
|
||||
@@ -433,6 +433,42 @@ class ProjectsConsoleClientTest extends Scope
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
|
||||
/**
|
||||
* Test old version select queries are failing
|
||||
*/
|
||||
$list = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
'{"method":"select","values":["name", "$createdAt"]}',
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(400, $list['headers']['status-code']);
|
||||
$this->assertEquals('Invalid `queries` param: Invalid query: Select queries requires an attribute', $list['body']['message']);
|
||||
|
||||
/**
|
||||
* Check Filter V22.php is activated
|
||||
*/
|
||||
$list = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-response-format' => '1.8.0', // APP_VERSION_STABLE
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
'{"method":"select","values":["name", "$createdAt"]}',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $list['headers']['status-code']);
|
||||
$this->assertEquals(5, $list['body']['total']);
|
||||
$project = $list['body']['projects'][0];
|
||||
$this->assertEquals('Project Test', $project['name']);
|
||||
$this->assertArrayHasKey('$id', $project);
|
||||
$this->assertArrayHasKey('name', $project);
|
||||
$this->assertArrayNotHasKey('platforms', $project);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -473,7 +509,8 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['$id', 'name'])->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('name')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -502,7 +539,12 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['$id', 'name', 'teamId', 'description', '$createdAt', '$updatedAt'])->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('name')->toString(),
|
||||
Query::select('teamId')->toString(),
|
||||
Query::select('description')->toString(),
|
||||
Query::select('$createdAt')->toString(),
|
||||
Query::select('$updatedAt')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -533,7 +575,9 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['$id', 'name', 'teamId'])->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('name')->toString(),
|
||||
Query::select('teamId')->toString(),
|
||||
Query::equal('name', ['Query Select Test Project'])->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -564,7 +608,8 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['$id', 'name'])->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('name')->toString(),
|
||||
Query::limit(2)->toString(),
|
||||
],
|
||||
]);
|
||||
@@ -594,7 +639,9 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['$id', 'name', 'platforms'])->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('name')->toString(),
|
||||
Query::select('platforms')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -623,7 +670,10 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['$id', 'name', 'webhooks', 'keys'])->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('name')->toString(),
|
||||
Query::select('webhooks')->toString(),
|
||||
Query::select('keys')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -652,7 +702,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*'])->toString(),
|
||||
Query::select('*')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -682,7 +732,8 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['$id', 'invalidAttribute'])->toString(),
|
||||
Query::select('$id')->toString(),
|
||||
Query::select('invalidAttribute')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
@@ -1058,7 +1058,7 @@ class SitesCustomServerTest extends Scope
|
||||
|
||||
$deployments = $this->listDeployments($siteId, [
|
||||
'queries' => [
|
||||
Query::select(['status'])->toString(),
|
||||
Query::select('status')->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
@@ -1071,7 +1071,7 @@ class SitesCustomServerTest extends Scope
|
||||
// Extra select query check, for attribute not allowed by filter queries
|
||||
$deployments = $this->listDeployments($siteId, [
|
||||
'queries' => [
|
||||
Query::select(['buildLogs'])->toString(),
|
||||
Query::select('buildLogs')->toString(),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals($deployments['headers']['status-code'], 200);
|
||||
|
||||
@@ -453,7 +453,7 @@ trait UsersBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['name'])->toString()
|
||||
Query::select('name')->toString()
|
||||
]
|
||||
]);
|
||||
$this->assertEquals($response['headers']['status-code'], 400);
|
||||
|
||||
@@ -638,41 +638,27 @@ class RuntimeQueryTest extends TestCase
|
||||
// TYPE_SELECT tests - select("*") means "listen to all events"
|
||||
public function testSelectAllIsAllowed(): void
|
||||
{
|
||||
$query = Query::select(['*']);
|
||||
$query = Query::select('*');
|
||||
$this->assertTrue(RuntimeQuery::isSelectAll($query));
|
||||
}
|
||||
|
||||
public function testSelectSpecificFieldsNotAllowed(): void
|
||||
{
|
||||
$query = Query::select(['name', 'age']);
|
||||
$this->assertFalse(RuntimeQuery::isSelectAll($query));
|
||||
}
|
||||
|
||||
public function testSelectSingleFieldNotAllowed(): void
|
||||
{
|
||||
$query = Query::select(['name']);
|
||||
$query = Query::select('name');
|
||||
$this->assertFalse(RuntimeQuery::isSelectAll($query));
|
||||
}
|
||||
|
||||
public function testValidateSelectQueryWithWildcard(): void
|
||||
{
|
||||
$query = Query::select(['*']);
|
||||
$query = Query::select('*');
|
||||
// Should not throw
|
||||
RuntimeQuery::validateSelectQuery($query);
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function testValidateSelectQueryWithSpecificFields(): void
|
||||
{
|
||||
$query = Query::select(['name', 'age']);
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Only select("*") is allowed in Realtime queries');
|
||||
RuntimeQuery::validateSelectQuery($query);
|
||||
}
|
||||
|
||||
public function testValidateSelectQueryWithSingleField(): void
|
||||
{
|
||||
$query = Query::select(['name']);
|
||||
$query = Query::select('name');
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Only select("*") is allowed in Realtime queries');
|
||||
RuntimeQuery::validateSelectQuery($query);
|
||||
@@ -700,7 +686,7 @@ class RuntimeQueryTest extends TestCase
|
||||
// Filter tests with select("*")
|
||||
public function testFilterWithSelectAllReturnsPayload(): void
|
||||
{
|
||||
$query = Query::select(['*']);
|
||||
$query = Query::select('*');
|
||||
$payload = ['name' => 'John', 'age' => 30];
|
||||
$result = $this->compileAndFilter([$query], $payload);
|
||||
$this->assertEquals($payload, $result);
|
||||
@@ -710,7 +696,7 @@ class RuntimeQueryTest extends TestCase
|
||||
{
|
||||
// If select("*") is present, it should return payload regardless of other queries
|
||||
$queries = [
|
||||
Query::select(['*']),
|
||||
Query::select('*'),
|
||||
Query::equal('name', ['Jane']), // This would normally fail
|
||||
];
|
||||
$payload = ['name' => 'John', 'age' => 30];
|
||||
@@ -721,7 +707,7 @@ class RuntimeQueryTest extends TestCase
|
||||
|
||||
public function testFilterWithSelectAllOnEmptyPayload(): void
|
||||
{
|
||||
$query = Query::select(['*']);
|
||||
$query = Query::select('*');
|
||||
$payload = [];
|
||||
$result = $this->compileAndFilter([$query], $payload);
|
||||
$this->assertEquals($payload, $result);
|
||||
|
||||
Reference in New Issue
Block a user