Skip to content

Commit

Permalink
Merge pull request #271 from utopia-php/index-length-validation
Browse files Browse the repository at this point in the history
Index validation
  • Loading branch information
abnegate committed Jun 9, 2023
2 parents 8e0d6f1 + e10a336 commit 4909c84
Show file tree
Hide file tree
Showing 11 changed files with 589 additions and 66 deletions.
36 changes: 18 additions & 18 deletions composer.lock

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

5 changes: 5 additions & 0 deletions src/Database/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -636,4 +636,9 @@ public function escapeWildcards(string $value): string
* @throws Exception
*/
abstract public function increaseDocumentAttribute(string $collection, string $id, string $attribute, int|float $value, int|float|null $min = null, int|float|null $max = null): bool;

/**
* @return int
*/
abstract public function getMaxIndexLength(): int;
}
2 changes: 1 addition & 1 deletion src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -1278,7 +1278,7 @@ protected function getSQLType(string $type, int $size, bool $signed = true): str
return 'MEDIUMTEXT';
}

if ($size > 16383) {
if ($size > $this->getMaxVarcharLength()) {
return 'TEXT';
}

Expand Down
8 changes: 8 additions & 0 deletions src/Database/Adapter/Mongo.php
Original file line number Diff line number Diff line change
Expand Up @@ -1650,4 +1650,12 @@ protected function processException(Exception $e): void

throw $e;
}

/**
* @return int
*/
public function getMaxIndexLength(): int
{
return 0;
}
}
5 changes: 1 addition & 4 deletions src/Database/Adapter/MySQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Utopia\Database\Adapter;

use Exception;
use PDOException;
use Utopia\Database\Database;
use Utopia\Database\Exception as DatabaseException;
Expand All @@ -19,9 +18,7 @@ class MySQL extends MariaDB
* @param array<string> $attributes
*
* @return string
* @throws Exception
* @throws Exception
* @throws Exception
* @throws DatabaseException
*/
protected function getSQLIndex(string $collection, string $id, string $type, array $attributes): string
{
Expand Down
2 changes: 1 addition & 1 deletion src/Database/Adapter/Postgres.php
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,7 @@ protected function getSQLType(string $type, int $size, bool $signed = true): str
switch ($type) {
case Database::VAR_STRING:
// $size = $size * 4; // Convert utf8mb4 size to bytes
if ($size > 16383) {
if ($size > $this->getMaxVarcharLength()) {
return 'TEXT';
}

Expand Down
18 changes: 17 additions & 1 deletion src/Database/Adapter/SQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ public function getAttributeWidth(Document $collection): int
$total += 11;
break;

case ($attribute['size'] > 16383):
case ($attribute['size'] > $this->getMaxVarcharLength()):
// 8 bytes length + 2 bytes for TEXT
$total += 10;
break;
Expand Down Expand Up @@ -865,4 +865,20 @@ public static function getPDOAttributes(): array
PDO::ATTR_STRINGIFY_FETCHES => true // Returns all fetched data as Strings
];
}

/**
* @return int
*/
public function getMaxVarcharLength(): int
{
return 16381; // Floor value for Postgres:16383 | MySQL:16381 | MariaDB:16382
}

/**
* @return int
*/
public function getMaxIndexLength(): int
{
return 768;
}
}
48 changes: 32 additions & 16 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class Database
* List of Internal Ids
* @var array<array<string, mixed>>
*/
protected array $attributes = [
protected static array $attributes = [
[
'$id' => '$id',
'type' => self::VAR_STRING,
Expand Down Expand Up @@ -619,9 +619,11 @@ public function delete(string $name): bool
* @param array<Document> $indexes
* @param array<string> $permissions
* @param bool $documentSecurity
*
* @return Document
* @throws DatabaseException
* @throws DuplicateException
* @throws InvalidArgumentException
* @throws LimitException
*/
public function createCollection(string $id, array $attributes = [], array $indexes = [], array $permissions = null, bool $documentSecurity = true): Document
{
Expand All @@ -640,12 +642,6 @@ public function createCollection(string $id, array $attributes = [], array $inde
throw new DuplicateException('Collection ' . $id . ' already exists');
}

$this->adapter->createCollection($id, $attributes, $indexes);

if ($id === self::METADATA) {
return new Document($this->collection);
}

$collection = new Document([
'$id' => ID::custom($id),
'$permissions' => $permissions,
Expand All @@ -655,6 +651,17 @@ public function createCollection(string $id, array $attributes = [], array $inde
'documentSecurity' => $documentSecurity
]);

$validator = new IndexValidator($this->adapter->getMaxIndexLength());
if (!$validator->isValid($collection)) {
throw new DatabaseException($validator->getDescription());
}

$this->adapter->createCollection($id, $attributes, $indexes);

if ($id === self::METADATA) {
return new Document($this->collection);
}

// Check index limits, if given
if ($indexes && $this->adapter->getCountOfIndexes($collection) > $this->adapter->getLimitForIndexes()) {
throw new LimitException('Index limit of ' . $this->adapter->getLimitForIndexes() . ' exceeded. Cannot create collection.');
Expand Down Expand Up @@ -692,7 +699,10 @@ public function createCollection(string $id, array $attributes = [], array $inde
* @param bool $documentSecurity
*
* @return Document
* @throws DuplicateException
* @throws InvalidArgumentException
* @throws ConflictException
* @throws DatabaseException
* @throws InvalidArgumentException
*/
public function updateCollection(string $id, array $permissions, bool $documentSecurity): Document
{
Expand Down Expand Up @@ -1976,6 +1986,7 @@ public function renameIndex(string $collection, string $old, string $new): bool
* @throws DuplicateException
* @throws LimitException
* @throws StructureException
* @throws Exception
*/
public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths = [], array $orders = []): bool
{
Expand All @@ -1985,8 +1996,8 @@ public function createIndex(string $collection, string $id, string $type, array

$collection = $this->silent(fn () => $this->getCollection($collection));

$validator = new IndexValidator($collection);
if (!$validator->isValid(['type' => $type, 'attributes' => $attributes])) {
$validator = new IndexValidator($this->adapter->getMaxIndexLength());
if (!$validator->isValid($collection)) {
throw new DatabaseException($validator->getDescription());
}

Expand Down Expand Up @@ -2018,7 +2029,7 @@ public function createIndex(string $collection, string $id, string $type, array
break;

case self::INDEX_FULLTEXT:
if (!$this->adapter->getSupportForUniqueIndex()) {
if (!$this->adapter->getSupportForFulltextIndex()) {
throw new DatabaseException('Fulltext index is not supported');
}
break;
Expand All @@ -2027,8 +2038,6 @@ public function createIndex(string $collection, string $id, string $type, array
throw new DatabaseException('Unknown index type: ' . $type . '. Must be one of ' . Database::INDEX_KEY . ', ' . Database::INDEX_UNIQUE . ', ' . Database::INDEX_ARRAY . ', ' . Database::INDEX_FULLTEXT);
}

$index = $this->adapter->createIndex($collection->getId(), $id, $type, $attributes, $lengths, $orders);

$collection->setAttribute('indexes', new Document([
'$id' => ID::custom($id),
'key' => $id,
Expand All @@ -2038,6 +2047,13 @@ public function createIndex(string $collection, string $id, string $type, array
'orders' => $orders,
]), Document::SET_TYPE_APPEND);

$validator = new IndexValidator($this->adapter->getMaxIndexLength());
if (!$validator->isValid($collection)) {
throw new DatabaseException($validator->getDescription());
}

$index = $this->adapter->createIndex($collection->getId(), $id, $type, $attributes, $lengths, $orders);

if ($collection->getId() !== self::METADATA) {
$this->silent(fn () => $this->updateDocument(self::METADATA, $collection->getId(), $collection));
}
Expand Down Expand Up @@ -4167,10 +4183,10 @@ public static function addFilter(string $name, callable $encode, callable $decod
* @return array<Document>
* @throws DatabaseException
*/
public function getInternalAttributes(): array
public static function getInternalAttributes(): array
{
$attributes = [];
foreach ($this->attributes as $internal) {
foreach (self::$attributes as $internal) {
$attributes[] = new Document($internal);
}
return $attributes;
Expand Down
Loading

0 comments on commit 4909c84

Please sign in to comment.