Skip to content

Commit fb699e2

Browse files
committed
Merge branch 'main' of github.com:utopia-php/database into index-sequence-attribute
2 parents c60b4d3 + eaae8fd commit fb699e2

4 files changed

Lines changed: 106 additions & 34 deletions

File tree

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"ext-redis": "*",
4141
"utopia-php/validators": "^0.5",
4242
"utopia-php/console": "0.1.*",
43-
"utopia-php/cache": "^4.0.0",
43+
"utopia-php/cache": "^4.0 || ^5.0",
4444
"utopia-php/pools": "2.*",
4545
"utopia-php/mongo": "1.*"
4646
},

composer.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Database/Database.php

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9347,6 +9347,14 @@ public function decode(Document $collection, Document $document, array $selectio
93479347
$attributes[] = $attribute;
93489348
}
93499349

9350+
$hasRelationshipSelections = false;
9351+
foreach ($selections as $selection) {
9352+
if (\str_contains($selection, '.')) {
9353+
$hasRelationshipSelections = true;
9354+
break;
9355+
}
9356+
}
9357+
93509358
foreach ($attributes as $attribute) {
93519359
$key = $attribute['$id'] ?? '';
93529360
$type = $attribute['type'] ?? '';
@@ -9379,34 +9387,26 @@ public function decode(Document $collection, Document $document, array $selectio
93799387
$value = ($array) ? $value : [$value];
93809388
$value = (is_null($value)) ? [] : $value;
93819389

9382-
foreach ($value as $index => $node) {
9383-
foreach (\array_reverse($filters) as $filter) {
9384-
$node = $this->decodeAttribute($filter, $node, $document, $key);
9390+
$selected = empty($selections)
9391+
|| \in_array($key, $selections)
9392+
|| \in_array('*', $selections);
9393+
9394+
if ($selected || $hasRelationshipSelections) {
9395+
foreach ($value as $index => $node) {
9396+
foreach (\array_reverse($filters) as $filter) {
9397+
$node = $this->decodeAttribute($filter, $node, $document, $key);
9398+
}
9399+
$value[$index] = $node;
93859400
}
9386-
$value[$index] = $node;
93879401
}
93889402

93899403
$filteredValue[$key] = ($array) ? $value : $value[0];
93909404

9391-
if (
9392-
empty($selections)
9393-
|| \in_array($key, $selections)
9394-
|| \in_array('*', $selections)
9395-
) {
9405+
if ($selected) {
93969406
$document->setAttribute($key, ($array) ? $value : $value[0]);
93979407
}
93989408
}
93999409

9400-
$hasRelationshipSelections = false;
9401-
if (!empty($selections)) {
9402-
foreach ($selections as $selection) {
9403-
if (\str_contains($selection, '.')) {
9404-
$hasRelationshipSelections = true;
9405-
break;
9406-
}
9407-
}
9408-
}
9409-
94109410
if ($hasRelationshipSelections && !empty($selections) && !\in_array('*', $selections)) {
94119411
foreach ($collection->getAttribute('attributes', []) as $attribute) {
94129412
$key = $attribute['$id'] ?? '';

tests/e2e/Adapter/Scopes/AttributeTests.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,6 +1260,78 @@ function (mixed $value) {
12601260
}
12611261
}
12621262

1263+
/**
1264+
* A filter can build its value by querying rather than transforming the stored one — that is
1265+
* what the subQuery filters in Appwrite do, listing a child collection per document. Reading a
1266+
* document without selecting such an attribute must not run it: the value is dropped anyway,
1267+
* and it is the filter, not the value, that costs the query.
1268+
*/
1269+
public function testFilterNotAppliedWhenAttributeNotSelected(): void
1270+
{
1271+
/** @var Database $database */
1272+
$database = $this->getDatabase();
1273+
1274+
$calls = 0;
1275+
1276+
$database->addFilter(
1277+
'subQueryProbe',
1278+
fn (mixed $value) => null, // stores nothing, like a subQuery filter
1279+
function (mixed $value) use (&$calls) {
1280+
$calls++;
1281+
return ['fanned', 'out'];
1282+
}
1283+
);
1284+
1285+
$database->createCollection('filterSelect');
1286+
$database->createAttribute('filterSelect', 'plain', Database::VAR_STRING, 128, false);
1287+
$database->createAttribute('filterSelect', 'kids', Database::VAR_STRING, 128, false, filters: ['subQueryProbe']);
1288+
1289+
$database->createDocument('filterSelect', new Document([
1290+
'$id' => 'doc1',
1291+
'$permissions' => [
1292+
Permission::read(Role::any()),
1293+
Permission::update(Role::any()),
1294+
Permission::delete(Role::any()),
1295+
],
1296+
'plain' => 'x',
1297+
]));
1298+
1299+
$calls = 0;
1300+
$document = $database->getDocument('filterSelect', 'doc1');
1301+
$this->assertEquals(1, $calls);
1302+
$this->assertEquals(['fanned', 'out'], $document->getAttribute('kids'));
1303+
1304+
$calls = 0;
1305+
$document = $database->getDocument('filterSelect', 'doc1', [Query::select(['$id', 'plain'])]);
1306+
$this->assertEquals(0, $calls);
1307+
$this->assertNull($document->getAttribute('kids'));
1308+
$this->assertEquals('x', $document->getAttribute('plain'));
1309+
1310+
// Selecting it explicitly, and selecting everything, both still decode it.
1311+
$calls = 0;
1312+
$document = $database->getDocument('filterSelect', 'doc1', [Query::select(['$id', 'kids'])]);
1313+
$this->assertEquals(1, $calls);
1314+
$this->assertEquals(['fanned', 'out'], $document->getAttribute('kids'));
1315+
1316+
$calls = 0;
1317+
$document = $database->getDocument('filterSelect', 'doc1', [Query::select(['*'])]);
1318+
$this->assertEquals(1, $calls);
1319+
$this->assertEquals(['fanned', 'out'], $document->getAttribute('kids'));
1320+
1321+
// find() decodes through the same path, once per document returned.
1322+
$calls = 0;
1323+
$documents = $database->find('filterSelect', [Query::select(['$id', 'plain'])]);
1324+
$this->assertCount(1, $documents);
1325+
$this->assertEquals(0, $calls);
1326+
$this->assertNull($documents[0]->getAttribute('kids'));
1327+
1328+
$calls = 0;
1329+
$documents = $database->find('filterSelect');
1330+
$this->assertCount(1, $documents);
1331+
$this->assertEquals(1, $calls);
1332+
$this->assertEquals(['fanned', 'out'], $documents[0]->getAttribute('kids'));
1333+
}
1334+
12631335
public function updateStringAttributeSize(int $size, Document $document): Document
12641336
{
12651337
/** @var Database $database */

0 commit comments

Comments
 (0)