Skip to content

Commit

Permalink
Merge pull request #507 from utopia-php/calculate-row-size
Browse files Browse the repository at this point in the history
Dependency index validation
  • Loading branch information
abnegate authored Jan 17, 2025
2 parents d854206 + f1bf181 commit b53f701
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 2 deletions.
36 changes: 36 additions & 0 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Utopia\Database\Exception as DatabaseException;
use Utopia\Database\Exception\Authorization as AuthorizationException;
use Utopia\Database\Exception\Conflict as ConflictException;
use Utopia\Database\Exception\Dependency as DependencyException;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Exception\Limit as LimitException;
use Utopia\Database\Exception\NotFound as NotFoundException;
Expand All @@ -20,6 +21,7 @@
use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Index as IndexValidator;
use Utopia\Database\Validator\IndexDependency as IndexDependencyValidator;
use Utopia\Database\Validator\PartialStructure;
use Utopia\Database\Validator\Permissions;
use Utopia\Database\Validator\Queries\Document as DocumentValidator;
Expand Down Expand Up @@ -1898,6 +1900,18 @@ public function updateAttribute(string $collection, string $id, ?string $type =
}, $index['attributes']);
}
}

/**
* Check index dependency if we are changing the key
*/
$validator = new IndexDependencyValidator(
$collectionDoc->getAttribute('indexes', []),
$this->adapter->getSupportForCastIndexArray(),
);

if (! $validator->isValid($attribute)) {
throw new DependencyException($validator->getDescription());
}
}

/**
Expand Down Expand Up @@ -1998,6 +2012,17 @@ public function deleteAttribute(string $collection, string $id): bool
throw new DatabaseException('Cannot delete relationship as an attribute');
}

if ($this->validate) {
$validator = new IndexDependencyValidator(
$collection->getAttribute('indexes', []),
$this->adapter->getSupportForCastIndexArray(),
);

if (! $validator->isValid($attribute)) {
throw new DependencyException($validator->getDescription());
}
}

foreach ($indexes as $indexKey => $index) {
$indexAttributes = $index->getAttribute('attributes', []);

Expand Down Expand Up @@ -2074,6 +2099,17 @@ public function renameAttribute(string $collection, string $old, string $new): b
throw new NotFoundException('Attribute not found');
}

if ($this->validate) {
$validator = new IndexDependencyValidator(
$collection->getAttribute('indexes', []),
$this->adapter->getSupportForCastIndexArray(),
);

if (! $validator->isValid($attribute)) {
throw new DependencyException($validator->getDescription());
}
}

$attribute->setAttribute('$id', $new);
$attribute->setAttribute('key', $new);

Expand Down
85 changes: 85 additions & 0 deletions src/Database/Validator/IndexDependency.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace Utopia\Database\Validator;

use Utopia\Database\Document;
use Utopia\Validator;

class IndexDependency extends Validator
{
protected string $message = "Attribute can't be deleted or renamed because it is used in an index";

protected bool $castIndexSupport;

/**
* @var array<Document>
*/
protected array $indexes;

/**
* @param array<Document> $indexes
* @param bool $castIndexSupport
*/
public function __construct(array $indexes, bool $castIndexSupport)
{
$this->castIndexSupport = $castIndexSupport;
$this->indexes = $indexes;
}

/**
* Returns validator description
*/
public function getDescription(): string
{
return $this->message;
}

/**
* Is valid.
*
* @param Document $value
*/
public function isValid($value): bool
{
if (! $this->castIndexSupport) {
return true;
}

if (! $value->getAttribute('array', false)) {
return true;
}

$key = \strtolower($value->getAttribute('key', $value->getAttribute('$id')));

foreach ($this->indexes as $index) {
$attributes = $index->getAttribute('attributes', []);
foreach ($attributes as $attribute) {
if ($key === \strtolower($attribute)) {
return false;
}
}
}

return true;
}

/**
* Is array
*
* Function will return true if object is array.
*/
public function isArray(): bool
{
return false;
}

/**
* Get Type
*
* Returns validator type.
*/
public function getType(): string
{
return self::TYPE_OBJECT;
}
}
22 changes: 20 additions & 2 deletions tests/e2e/Adapter/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -2958,21 +2958,39 @@ public function testArrayAttribute(): void
$database->createIndex($collection, 'idx_cards', Database::INDEX_KEY, ['cards'], [100]);

if ($this->getDatabase()->getAdapter()->getSupportForCastIndexArray()) {
/**
* Delete attribute
*/
try {
$database->deleteAttribute($collection, 'cards');
$this->fail('Failed to throw exception');
} catch (Throwable $e) {
$this->assertInstanceOf(DependencyException::class, $e);
$this->assertEquals('Attribute cannot be deleted because it is used in an index', $e->getMessage());
$this->assertEquals("Attribute can't be deleted or renamed because it is used in an index", $e->getMessage());
}

/**
* Rename attribute
*/
try {
$database->renameAttribute($collection, 'cards', 'cards_new');
$this->fail('Failed to throw exception');
} catch (Throwable $e) {
$this->assertInstanceOf(DependencyException::class, $e);
$this->assertEquals('Attribute cannot be deleted because it is used in an index', $e->getMessage());
$this->assertEquals("Attribute can't be deleted or renamed because it is used in an index", $e->getMessage());
}

/**
* Update attribute
*/
try {
$database->updateAttribute($collection, id:'cards', newKey: 'cards_new');
$this->fail('Failed to throw exception');
} catch (Throwable $e) {
$this->assertInstanceOf(DependencyException::class, $e);
$this->assertEquals("Attribute can't be deleted or renamed because it is used in an index", $e->getMessage());
}

} else {
$this->assertTrue($database->renameAttribute($collection, 'cards', 'cards_new'));
$this->assertTrue($database->deleteAttribute($collection, 'cards_new'));
Expand Down

0 comments on commit b53f701

Please sign in to comment.