Skip to content

Commit

Permalink
Merge pull request #478 from utopia-php/fix-index-validation
Browse files Browse the repository at this point in the history
Duplicate attributes
  • Loading branch information
abnegate authored Nov 12, 2024
2 parents 562f52c + b0126cc commit e43f8ee
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 34 deletions.
3 changes: 0 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
FROM composer:2.0 AS composer

ARG DEBUG=false
ENV DEBUG=$DEBUG

WORKDIR /usr/local/src/

COPY composer.lock /usr/local/src/
Expand Down
77 changes: 62 additions & 15 deletions composer.lock

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

7 changes: 7 additions & 0 deletions src/Database/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -1015,4 +1015,11 @@ abstract public function increaseDocumentAttribute(string $collection, string $i
* @return string
*/
abstract public function getConnectionId(): string;

/**
* Get List of internal index keys names
*
* @return array<string>
*/
abstract public function getInternalIndexesKeys(): array;
}
5 changes: 5 additions & 0 deletions src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -2425,4 +2425,9 @@ public function getConnectionId(): string
$stmt = $this->getPDO()->query("SELECT CONNECTION_ID();");
return $stmt->fetchColumn();
}

public function getInternalIndexesKeys(): array
{
return ['primary', '_created_at', '_updated_at', '_tenant_id'];
}
}
5 changes: 5 additions & 0 deletions src/Database/Adapter/Mongo.php
Original file line number Diff line number Diff line change
Expand Up @@ -1937,4 +1937,9 @@ public function getConnectionId(): string
{
return '0';
}

public function getInternalIndexesKeys(): array
{
return [];
}
}
4 changes: 4 additions & 0 deletions src/Database/Adapter/SQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -1129,4 +1129,8 @@ public function getLikeOperator(): string
return 'LIKE';
}

public function getInternalIndexesKeys(): array
{
return [];
}
}
36 changes: 30 additions & 6 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ class Database

protected int $maxQueryValues = 100;

protected bool $migrating = false;

/**
* Stack of collection IDs when creating or updating related documents
* @var array<string>
Expand Down Expand Up @@ -933,6 +935,18 @@ public function setPreserveDates(bool $preserve): static
return $this;
}

public function setMigrating(bool $migrating): self
{
$this->migrating = $migrating;

return $this;
}

public function isMigrating(): bool
{
return $this->migrating;
}

public function withPreserveDates(callable $callback): mixed
{
$previous = $this->preserveDates;
Expand Down Expand Up @@ -1167,7 +1181,8 @@ public function createCollection(string $id, array $attributes = [], array $inde
if ($this->validate) {
$validator = new IndexValidator(
$attributes,
$this->adapter->getMaxIndexLength()
$this->adapter->getMaxIndexLength(),
$this->adapter->getInternalIndexesKeys()
);
foreach ($indexes as $index) {
if (!$validator->isValid($index)) {
Expand Down Expand Up @@ -1512,10 +1527,17 @@ public function createAttribute(string $collection, string $id, string $type, in
$this->validateDefaultTypes($type, $default);
}

$created = $this->adapter->createAttribute($collection->getId(), $id, $type, $size, $signed, $array);
try {
$created = $this->adapter->createAttribute($collection->getId(), $id, $type, $size, $signed, $array);

if (!$created) {
throw new DatabaseException('Failed to create attribute');
if (!$created) {
throw new DatabaseException('Failed to create attribute');
}
} catch (DuplicateException $e) {
// HACK: Metadata should still be updated, can be removed when null tenant collections are supported.
if (!$this->adapter->getSharedTables() || !$this->isMigrating()) {
throw $e;
}
}

if ($collection->getId() !== self::METADATA) {
Expand Down Expand Up @@ -2732,7 +2754,8 @@ public function createIndex(string $collection, string $id, string $type, array
if ($this->validate) {
$validator = new IndexValidator(
$collection->getAttribute('attributes', []),
$this->adapter->getMaxIndexLength()
$this->adapter->getMaxIndexLength(),
$this->adapter->getInternalIndexesKeys()
);
if (!$validator->isValid($index)) {
throw new DatabaseException($validator->getDescription());
Expand All @@ -2747,7 +2770,8 @@ public function createIndex(string $collection, string $id, string $type, array
}
} catch (DuplicateException $e) {
// HACK: Metadata should still be updated, can be removed when null tenant collections are supported.
if (!$this->adapter->getSharedTables()) {

if (!$this->adapter->getSharedTables() || !$this->isMigrating()) {
throw $e;
}
}
Expand Down
39 changes: 34 additions & 5 deletions src/Database/Validator/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,21 @@ class Index extends Validator
*/
protected array $attributes;

/**
* @var array<string> $reservedKeys
*/
protected array $reservedKeys;

/**
* @param array<Document> $attributes
* @param int $maxLength
* @param array<string> $reservedKeys
* @throws DatabaseException
*/
public function __construct(array $attributes, int $maxLength)
public function __construct(array $attributes, int $maxLength, array $reservedKeys = [])
{
$this->maxLength = $maxLength;
$this->reservedKeys = $reservedKeys;

foreach ($attributes as $attribute) {
$key = \strtolower($attribute->getAttribute('key', $attribute->getAttribute('$id')));
Expand Down Expand Up @@ -80,15 +87,15 @@ public function checkEmptyIndexAttributes(Document $index): bool
public function checkDuplicatedAttributes(Document $index): bool
{
$attributes = $index->getAttribute('attributes', []);
$orders = $index->getAttribute('orders', []);
$stack = [];
foreach ($attributes as $key => $attribute) {
$direction = $orders[$key] ?? 'ASC';
$value = \strtolower($attribute . '|' . $direction);
foreach ($attributes as $attribute) {
$value = \strtolower($attribute);

if (\in_array($value, $stack)) {
$this->message = 'Duplicate attributes provided';
return false;
}

$stack[] = $value;
}
return true;
Expand Down Expand Up @@ -209,6 +216,24 @@ public function checkIndexLength(Document $index): bool
return true;
}

/**
* @param Document $index
* @return bool
*/
public function checkReservedNames(Document $index): bool
{
$key = $index->getAttribute('key', $index->getAttribute('$id'));

foreach ($this->reservedKeys as $reserved) {
if (\strtolower($key) === \strtolower($reserved)) {
$this->message = 'Index key name is reserved';
return false;
}
}

return true;
}

/**
* Is valid.
*
Expand Down Expand Up @@ -243,6 +268,10 @@ public function isValid($value): bool
return false;
}

if (!$this->checkReservedNames($value)) {
return false;
}

return true;
}

Expand Down
Loading

0 comments on commit e43f8ee

Please sign in to comment.