Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Select Query #299

Merged
merged 1 commit into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 36 additions & 14 deletions src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -1046,17 +1046,26 @@ public function find(string $collection, array $queries = [], ?int $limit = 25,
$results = $stmt->fetchAll();

foreach ($results as $key => $value) {
$results[$key]['$id'] = $value['_uid'];
$results[$key]['$internalId'] = $value['_id'];
$results[$key]['$createdAt'] = $value['_createdAt'];
$results[$key]['$updatedAt'] = $value['_updatedAt'];
$results[$key]['$permissions'] = json_decode($value['_permissions'] ?? '[]', true);

unset($results[$key]['_uid']);
unset($results[$key]['_id']);
unset($results[$key]['_createdAt']);
unset($results[$key]['_updatedAt']);
unset($results[$key]['_permissions']);
if (isset($value['_uid'])) {
$results[$key]['$id'] = $value['_uid'];
unset($results[$key]['_uid']);
}
if (isset($value['_id'])) {
$results[$key]['$internalId'] = $value['_id'];
unset($results[$key]['_id']);
}
if (isset($value['_createdAt'])) {
$results[$key]['$createdAt'] = $value['_createdAt'];
unset($results[$key]['_createdAt']);
}
if (isset($value['_updatedAt'])) {
$results[$key]['$updatedAt'] = $value['_updatedAt'];
unset($results[$key]['_updatedAt']);
}
if (isset($value['_permissions'])) {
$results[$key]['$permissions'] = json_decode($value['_permissions'] ?? '[]', true);
unset($results[$key]['_permissions']);
}

$results[$key] = new Document($results[$key]);
}
Expand Down Expand Up @@ -1189,12 +1198,25 @@ protected function getAttributeProjection(array $selections, string $prefix = ''
return '*';
}

// Remove $id, $permissions and $collection if present since it is always selected by default
$selections = \array_diff($selections, ['$id', '$permissions', '$collection']);

$selections[] = '_uid';
$selections[] = '_id';
$selections[] = '_createdAt';
$selections[] = '_updatedAt';
$selections[] = '_permissions';

if (\in_array('$internalId', $selections)) {
$selections[] = '_id';
$selections = \array_diff($selections, ['$internalId']);
}
if (\in_array('$createdAt', $selections)) {
$selections[] = '_createdAt';
$selections = \array_diff($selections, ['$createdAt']);
}
if (\in_array('$updatedAt', $selections)) {
$selections[] = '_updatedAt';
$selections = \array_diff($selections, ['$updatedAt']);
}

if (!empty($prefix)) {
foreach ($selections as &$selection) {
$selection = "`{$prefix}`.`{$this->filter($selection)}`";
Expand Down
5 changes: 5 additions & 0 deletions src/Database/Adapter/Mongo.php
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,11 @@ protected function getAttributeProjection(array $selections, string $prefix = ''
$projection = [];

foreach ($selections as $selection) {
// Skip internal attributes since all are selected by default
if (\in_array($selection, Database::INTERNAL_ATTRIBUTES)) {
continue;
}

$projection[$selection] = 1;
}

Expand Down
50 changes: 36 additions & 14 deletions src/Database/Adapter/Postgres.php
Original file line number Diff line number Diff line change
Expand Up @@ -1056,17 +1056,26 @@ public function find(string $collection, array $queries = [], ?int $limit = 25,
$results = $stmt->fetchAll();

foreach ($results as $key => $value) {
$results[$key]['$id'] = $value['_uid'];
$results[$key]['$internalId'] = $value['_id'];
$results[$key]['$createdAt'] = $value['_createdAt'];
$results[$key]['$updatedAt'] = $value['_updatedAt'];
$results[$key]['$permissions'] = json_decode($value['_permissions'] ?? '[]', true);

unset($results[$key]['_uid']);
unset($results[$key]['_id']);
unset($results[$key]['_createdAt']);
unset($results[$key]['_updatedAt']);
unset($results[$key]['_permissions']);
if (isset($value['_uid'])) {
$results[$key]['$id'] = $value['_uid'];
unset($results[$key]['_uid']);
}
if (isset($value['_id'])) {
$results[$key]['$internalId'] = $value['_id'];
unset($results[$key]['_id']);
}
if (isset($value['_createdAt'])) {
$results[$key]['$createdAt'] = $value['_createdAt'];
unset($results[$key]['_createdAt']);
}
if (isset($value['_updatedAt'])) {
$results[$key]['$updatedAt'] = $value['_updatedAt'];
unset($results[$key]['_updatedAt']);
}
if (isset($value['_permissions'])) {
$results[$key]['$permissions'] = json_decode($value['_permissions'] ?? '[]', true);
unset($results[$key]['_permissions']);
}

$results[$key] = new Document($results[$key]);
}
Expand Down Expand Up @@ -1199,12 +1208,25 @@ protected function getAttributeProjection(array $selections, string $prefix = ''
return '*';
}

// Remove $id ,$permissions and $collection from selections if present since they are always selected
$selections = \array_diff($selections, ['$id', '$permissions', '$collection']);

$selections[] = '_uid';
$selections[] = '_id';
$selections[] = '_createdAt';
$selections[] = '_updatedAt';
$selections[] = '_permissions';

if (\in_array('$internalId', $selections)) {
$selections[] = '_id';
$selections = \array_diff($selections, ['$internalId']);
}
if (\in_array('$createdAt', $selections)) {
$selections[] = '_createdAt';
$selections = \array_diff($selections, ['$createdAt']);
}
if (\in_array('$updatedAt', $selections)) {
$selections[] = '_updatedAt';
$selections = \array_diff($selections, ['$updatedAt']);
}

if (!empty($prefix)) {
foreach ($selections as &$selection) {
$selection = "\"{$prefix}\".\"{$this->filter($selection)}\"";
Expand Down
31 changes: 20 additions & 11 deletions src/Database/Adapter/SQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,26 @@ public function getDocument(string $collection, string $id, array $queries = [])
return new Document([]);
}

$document['$id'] = $document['_uid'];
$document['$internalId'] = $document['_id'];
$document['$createdAt'] = $document['_createdAt'];
$document['$updatedAt'] = $document['_updatedAt'];
$document['$permissions'] = json_decode($document['_permissions'] ?? '[]', true);

unset($document['_id']);
unset($document['_uid']);
unset($document['_createdAt']);
unset($document['_updatedAt']);
unset($document['_permissions']);
if (isset($document['_id'])) {
$document['$internalId'] = $document['_id'];
unset($document['_id']);
}
if (isset($document['_uid'])) {
$document['$id'] = $document['_uid'];
unset($document['_uid']);
}
if (isset($document['_createdAt'])) {
$document['$createdAt'] = $document['_createdAt'];
unset($document['_createdAt']);
}
if (isset($document['_updatedAt'])) {
$document['$updatedAt'] = $document['_updatedAt'];
unset($document['_updatedAt']);
}
if (isset($document['_permissions'])) {
$document['$permissions'] = json_decode($document['_permissions'] ?? '[]', true);
unset($document['_permissions']);
}

return new Document($document);
}
Expand Down
60 changes: 59 additions & 1 deletion src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,20 @@ class Database
]
];

/**
* List of Internal Attributes
*
* @var array<string>
*/
public const INTERNAL_ATTRIBUTES = [
'$id',
'$internalId',
'$createdAt',
'$updatedAt',
'$permissions',
'$collection',
];

/**
* Parent Collection
* Defines the structure for both system and custom collections
Expand Down Expand Up @@ -2284,6 +2298,20 @@ public function getDocument(string $collection, string $id, array $queries = [])
$this->cache->save($cacheKey, $document->getArrayCopy());
}

// Remove internal attributes if not queried for select query
// $id, $permissions and $collection are the default selected attributes for (MariaDB, MySQL, SQLite, Postgres)
// All internal attributes are default selected attributes for (MongoDB)
foreach ($queries as $query) {
if ($query->getMethod() === Query::TYPE_SELECT) {
$values = $query->getValues();
foreach (Database::INTERNAL_ATTRIBUTES as $internalAttribute) {
if (!in_array($internalAttribute, $values)) {
$document->removeAttribute($internalAttribute);
}
}
}
}

$this->trigger(self::EVENT_DOCUMENT_READ, $document);

return $document;
Expand Down Expand Up @@ -4015,6 +4043,20 @@ public function find(string $collection, array $queries = [], ?int $timeout = nu

$results = $this->applyNestedQueries($results, $nestedQueries, $relationships);

// Remove internal attributes which are not queried
foreach ($queries as $query) {
if ($query->getMethod() === Query::TYPE_SELECT) {
$values = $query->getValues();
foreach ($results as $result) {
foreach (Database::INTERNAL_ATTRIBUTES as $internalAttribute) {
if (!\in_array($internalAttribute, $values)) {
$result->removeAttribute($internalAttribute);
}
}
}
}
}

$this->trigger(self::EVENT_DOCUMENT_FIND, $results);

return $results;
Expand Down Expand Up @@ -4352,7 +4394,19 @@ public function decode(Document $collection, Document $document, array $selectio
}

if (empty($selections) || \in_array($key, $selections) || \in_array('*', $selections)) {
$document->setAttribute($key, ($array) ? $value : $value[0]);
if (
empty($selections)
|| \in_array($key, $selections)
|| \in_array('*', $selections)
|| \in_array($key, ['$createdAt', '$updatedAt'])
) {
// Prevent null values being set for createdAt and updatedAt
if (\in_array($key, ['$createdAt', '$updatedAt']) && $value[0] === null) {
continue;
} else {
$document->setAttribute($key, ($array) ? $value : $value[0]);
}
}
}
}

Expand Down Expand Up @@ -4504,6 +4558,10 @@ private function validateSelections(Document $collection, array $queries): array
}

$keys = [];

// Allow querying internal attributes
$keys = array_merge($keys, self::INTERNAL_ATTRIBUTES);

foreach ($collection->getAttribute('attributes', []) as $attribute) {
if ($attribute['type'] !== self::VAR_RELATIONSHIP) {
$keys[] = $attribute['key'];
Expand Down
19 changes: 19 additions & 0 deletions src/Database/Validator/Query/Select.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ class Select extends Base
*/
protected array $schema = [];

/**
* List of internal attributes
*
* @var array<string>
*/
protected const INTERNAL_ATTRIBUTES = [
'$id',
'$internalId',
'$createdAt',
'$updatedAt',
'$permissions',
'$collection',
];

/**
* @param array<Document> $attributes
*/
Expand Down Expand Up @@ -54,6 +68,11 @@ public function isValid($value): bool
$attribute = \explode('.', $attribute)[0];
}

// Skip internal attributes
if (\in_array($attribute, self::INTERNAL_ATTRIBUTES)) {
continue;
}

if (!isset($this->schema[$attribute]) && $attribute !== '*') {
$this->message = 'Attribute not found in schema: ' . $attribute;
return false;
Expand Down
Loading