Skip to content
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
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"utopia-php/cache": "^4.0 || ^5.0",
"utopia-php/pools": "^2.0",
"utopia-php/mongo": "^1.5.4",
"utopia-php/query": "^0.7.1",
"utopia-php/query": "^0.7.2",
"utopia-php/async": "^0.2"
},
"require-dev": {
Expand Down
14 changes: 7 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/Database/Adapter/SQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -4507,14 +4507,14 @@ private function assertJoinAliases(array $queries): void
}

$alias = $query->getAlias();
$invalid = JoinValidator::describeInvalidAlias($alias);
$invalid = JoinValidator::describeInvalidAlias($alias, $query->isAliasDefaulted());
if ($invalid !== null) {
throw new QueryException($invalid);
}

$key = \strtolower($alias);
if (isset($declared[$key])) {
throw new QueryException("Join alias \"{$alias}\" is declared more than once");
throw new QueryException(JoinValidator::describeDuplicateAlias($alias, $query->isAliasDefaulted()));
}
$declared[$key] = true;
}
Expand Down
6 changes: 6 additions & 0 deletions src/Database/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class Query extends BaseQuery
public const int SHAPE_MAX_NODES = 10000;

/**
* A join given no alias is read under the collection it joins.
*
* @param array<mixed> $values
*/
public function __construct(Method|string $method, string $attribute = '', array $values = [], string $alias = '')
Expand All @@ -56,6 +58,10 @@ public function __construct(Method|string $method, string $attribute = '', array
$attribute = Document::SEQUENCE;
}

if ($alias === '' && $methodEnum->isJoin()) {
$alias = $attribute;
}

parent::__construct($methodEnum, $attribute, $values, $alias);
}

Expand Down
35 changes: 30 additions & 5 deletions src/Database/Validator/Query/Join.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,24 +122,46 @@ public function resetJoinAliases(): void
/**
* Why a join alias cannot be used, or null when it can. The reserved alias is matched without
* case: SQLite, and MySQL on case-insensitive file systems, treat `x` and `X` as one alias.
* A defaulted alias is the table ID the join names, so the reason says that ID cannot serve as
* the alias and asks for one.
*/
public static function describeInvalidAlias(string $alias): ?string
public static function describeInvalidAlias(string $alias, bool $defaulted = false): ?string
{
if ($alias === '') {
return 'Join alias is required';
}

if (\preg_match(self::ALIAS_PATTERN, $alias) !== 1) {
return 'Join alias must start with a letter or an underscore and contain only letters, digits and underscores';
return $defaulted
? self::describeUnusableTable($alias, 'an alias must start with a letter or an underscore and contain only letters, digits and underscores')
: 'Join alias must start with a letter or an underscore and contain only letters, digits and underscores';
}

if (\strcasecmp($alias, Query::DEFAULT_ALIAS) === 0) {
return "Join alias \"{$alias}\" is reserved for the main collection";
return $defaulted
? self::describeUnusableTable($alias, 'it is reserved for the main collection')
: "Join alias \"{$alias}\" is reserved for the main collection";
}

return null;
}

/**
* Why a join alias another join of the same query set already declared cannot be used. The
* adapters check it, as they read `x` and `X` as one alias.
*/
public static function describeDuplicateAlias(string $alias, bool $defaulted = false): string
{
return $defaulted
? self::describeUnusableTable($alias, 'another join of the query already uses it as its alias')
: "Join alias \"{$alias}\" is declared more than once";
}

private static function describeUnusableTable(string $table, string $reason): string
{
return "Table ID \"{$table}\" cannot be used as the join alias: {$reason}. Pass an alias for the join";
}

/**
* Get the method type this validator handles.
*
Expand Down Expand Up @@ -187,15 +209,18 @@ protected function isValidQuery(Query $query): bool
}

$alias = $query->getAlias();
$invalidAlias = self::describeInvalidAlias($alias);
$defaulted = $query->isAliasDefaulted();
$invalidAlias = self::describeInvalidAlias($alias, $defaulted);
if ($invalidAlias !== null) {
$this->message = $invalidAlias;

return false;
}

if (isset($this->relationships[$alias])) {
$this->message = "Join alias \"{$alias}\" is the key of the relationship attribute \"{$alias}\": give the join another alias";
$this->message = $defaulted
? self::describeUnusableTable($alias, "it is the key of the relationship attribute \"{$alias}\"")
: "Join alias \"{$alias}\" is the key of the relationship attribute \"{$alias}\": give the join another alias";

return false;
}
Expand Down
2 changes: 2 additions & 0 deletions tests/e2e/Adapter/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Tests\E2E\Adapter\Scopes\GeneralTests;
use Tests\E2E\Adapter\Scopes\IndexTests;
use Tests\E2E\Adapter\Scopes\IntegerRoundingTests;
use Tests\E2E\Adapter\Scopes\JoinAliasTests;
use Tests\E2E\Adapter\Scopes\JoinComboTests;
use Tests\E2E\Adapter\Scopes\JoinReadRuleTests;
use Tests\E2E\Adapter\Scopes\JoinRelationshipTests;
Expand Down Expand Up @@ -58,6 +59,7 @@ abstract class Base extends TestCase
use GeneralTests;
use IndexTests;
use IntegerRoundingTests;
use JoinAliasTests;
use JoinComboTests;
use JoinReadRuleTests;
use JoinRelationshipTests;
Expand Down
Loading
Loading