Skip to content

Commit

Permalink
Merge pull request #495 from utopia-php/0.53.x-rename-json-index
Browse files Browse the repository at this point in the history
Dependency Exception
  • Loading branch information
abnegate authored Jan 8, 2025
2 parents d6067ec + e1d5ab5 commit 4587c19
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 34 deletions.
7 changes: 7 additions & 0 deletions src/Database/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,13 @@ abstract public function getSupportForAttributeResizing(): bool;
*/
abstract public function getSupportForGetConnectionId(): bool;

/**
* Is cast index as array supported?
*
* @return bool
*/
abstract public function getSupportForCastIndexArray(): bool;

/**
* Get current attribute count from collection document
*
Expand Down
22 changes: 9 additions & 13 deletions src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ public function deleteAttribute(string $collection, string $id, bool $array = fa
return true;
}

throw $e;
throw $this->processException($e);
}
}

Expand All @@ -462,9 +462,13 @@ public function renameAttribute(string $collection, string $old, string $new): b

$sql = $this->trigger(Database::EVENT_ATTRIBUTE_UPDATE, $sql);

return $this->getPDO()
->prepare($sql)
->execute();
try {
return $this->getPDO()
->prepare($sql)
->execute();
} catch (PDOException $e) {
throw $this->processException($e);
}
}

/**
Expand Down Expand Up @@ -766,7 +770,7 @@ public function createIndex(string $collection, string $id, string $type, array

$attributes[$i] = "`{$attr}`{$length} {$order}";

if (!empty($collectionAttribute['array']) && $this->castIndexArray()) {
if (!empty($collectionAttribute['array']) && $this->getSupportForCastIndexArray()) {
$attributes[$i] = '(CAST(' . $attr . ' AS char(' . Database::ARRAY_INDEX_LENGTH . ') ARRAY))';
}
}
Expand Down Expand Up @@ -798,14 +802,6 @@ public function createIndex(string $collection, string $id, string $type, array
}
}

/**
* @return bool
*/
public function castIndexArray(): bool
{
return false;
}

/**
* Delete Index
*
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 @@ -1797,6 +1797,11 @@ public function getSupportForSchemaAttributes(): bool
return false;
}

public function getSupportForCastIndexArray(): bool
{
return false;
}

/**
* Get current attribute count from collection document
*
Expand Down
11 changes: 7 additions & 4 deletions src/Database/Adapter/MySQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PDOException;
use Utopia\Database\Database;
use Utopia\Database\Exception as DatabaseException;
use Utopia\Database\Exception\Dependency as DependencyException;
use Utopia\Database\Exception\Timeout as TimeoutException;

class MySQL extends MariaDB
Expand Down Expand Up @@ -74,10 +75,7 @@ public function getSizeOfCollectionOnDisk(string $collection): int
return $size;
}

/**
* @return bool
*/
public function castIndexArray(): bool
public function getSupportForCastIndexArray(): bool
{
return true;
}
Expand All @@ -89,6 +87,11 @@ protected function processException(PDOException $e): \Exception
return new TimeoutException($e->getMessage(), $e->getCode(), $e);
}

// Functional index dependency
if ($e->getCode() === 'HY000' && isset($e->errorInfo[1]) && $e->errorInfo[1] === 3837) {
return new DependencyException($e->errorInfo[2], $e->getCode(), $e);
}

return parent::processException($e);
}
}
5 changes: 5 additions & 0 deletions src/Database/Adapter/SQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,11 @@ public function getSupportForQueryContains(): bool
*/
abstract public function getSupportForJSONOverlaps(): bool;

public function getSupportForCastIndexArray(): bool
{
return false;
}

public function getSupportForRelationships(): bool
{
return true;
Expand Down
40 changes: 23 additions & 17 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -2058,34 +2058,40 @@ public function deleteAttribute(string $collection, string $id): bool
public function renameAttribute(string $collection, string $old, string $new): bool
{
$collection = $this->silent(fn () => $this->getCollection($collection));

/**
* @var array<Document> $attributes
*/
$attributes = $collection->getAttribute('attributes', []);
$indexes = $collection->getAttribute('indexes', []);

$attribute = \in_array($old, \array_map(fn ($attribute) => $attribute['$id'], $attributes));
/**
* @var array<Document> $indexes
*/
$indexes = $collection->getAttribute('indexes', []);

if ($attribute === false) {
throw new NotFoundException('Attribute not found');
}
$attribute = new Document();

$attributeNew = \in_array($new, \array_map(fn ($attribute) => $attribute['$id'], $attributes));
foreach ($attributes as $value) {
if ($value->getId() === $old) {
$attribute = $value;
}

if ($attributeNew !== false) {
throw new DuplicateException('Attribute name already used');
if ($value->getId() === $new) {
throw new DuplicateException('Attribute name already used');
}
}

foreach ($attributes as $key => $value) {
if (isset($value['$id']) && $value['$id'] === $old) {
$attributes[$key]['key'] = $new;
$attributes[$key]['$id'] = $new;
$attributeNew = $attributes[$key];
break;
}
if ($attribute->isEmpty()) {
throw new NotFoundException('Attribute not found');
}

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

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

$indexAttributes = \array_map(fn ($attribute) => ($attribute === $old) ? $new : $attribute, $indexAttributes);
$indexAttributes = \array_map(fn ($attr) => ($attr === $old) ? $new : $attr, $indexAttributes);

$index->setAttribute('attributes', $indexAttributes);
}
Expand All @@ -2099,7 +2105,7 @@ public function renameAttribute(string $collection, string $old, string $new): b
$this->silent(fn () => $this->updateDocument(self::METADATA, $collection->getId(), $collection));
}

$this->trigger(self::EVENT_ATTRIBUTE_UPDATE, $attributeNew);
$this->trigger(self::EVENT_ATTRIBUTE_UPDATE, $attribute);

return $renamed;
}
Expand Down
9 changes: 9 additions & 0 deletions src/Database/Exception/Dependency.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Utopia\Database\Exception;

use Utopia\Database\Exception;

class Dependency extends Exception
{
}
36 changes: 36 additions & 0 deletions tests/e2e/Adapter/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,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\Query as QueryException;
Expand Down Expand Up @@ -2766,6 +2767,15 @@ public function testArrayAttribute(): void
array: true
));

$this->assertEquals(true, $database->createAttribute(
$collection,
'cards',
Database::VAR_STRING,
size: 5000,
required: false,
array: true
));

$this->assertEquals(true, $database->createAttribute(
$collection,
'numbers',
Expand Down Expand Up @@ -2889,6 +2899,32 @@ public function testArrayAttribute(): void
$this->assertEquals('Antony', $document->getAttribute('names')[1]);
$this->assertEquals(100, $document->getAttribute('numbers')[1]);

/**
* functional index dependency cannot be dropped or rename
*/
$database->createIndex($collection, 'idx_cards', Database::INDEX_KEY, ['cards'], [100]);

if ($this->getDatabase()->getAdapter()->getSupportForCastIndexArray()) {
try {
$database->deleteAttribute($collection, 'cards');
$this->fail('Failed to throw exception');
} catch (Throwable $e) {
$this->assertInstanceOf(DependencyException::class, $e);
$this->assertEquals("Column 'cards' has a functional index dependency and cannot be dropped or renamed.", $e->getMessage());
}

try {
$database->renameAttribute($collection, 'cards', 'cards_new');
$this->fail('Failed to throw exception');
} catch (Throwable $e) {
$this->assertInstanceOf(DependencyException::class, $e);
$this->assertEquals("Column 'cards' has a functional index dependency and cannot be dropped or renamed.", $e->getMessage());
}
} else {
$this->assertTrue($database->renameAttribute($collection, 'cards', 'cards_new'));
$this->assertTrue($database->deleteAttribute($collection, 'cards_new'));
}

try {
$database->createIndex($collection, 'indx', Database::INDEX_FULLTEXT, ['names']);
$this->fail('Failed to throw exception');
Expand Down

0 comments on commit 4587c19

Please sign in to comment.