From 534fb6bd756df717b021b6432a5bd9bfa9847256 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 20 Oct 2022 22:38:45 +0300 Subject: [PATCH 01/21] long size varchar with long index size mysql --- composer.lock | 20 +++------ phpunit.xml | 2 +- src/Database/Adapter/MariaDB.php | 40 ++++++++++++++---- src/Database/Adapter/Mongo/MongoDBAdapter.php | 9 ++-- src/Database/Adapter/SQLite.php | 2 +- src/Database/Database.php | 7 ++- tests/Database/Adapter/database.sql | Bin 1200128 -> 1212416 bytes tests/Database/Base.php | 8 +++- 8 files changed, 57 insertions(+), 31 deletions(-) diff --git a/composer.lock b/composer.lock index db2620b32..dc7bdeb79 100644 --- a/composer.lock +++ b/composer.lock @@ -336,16 +336,16 @@ }, { "name": "utopia-php/framework", - "version": "0.22.1", + "version": "0.23.1", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "9f35d36ed4b8fa1c92962c77ef02b49c2f5919df" + "reference": "d595df075aa9ee46147a388c63064b03aeeac466" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/9f35d36ed4b8fa1c92962c77ef02b49c2f5919df", - "reference": "9f35d36ed4b8fa1c92962c77ef02b49c2f5919df", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/d595df075aa9ee46147a388c63064b03aeeac466", + "reference": "d595df075aa9ee46147a388c63064b03aeeac466", "shasum": "" }, "require": { @@ -365,12 +365,6 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - } - ], "description": "A simple, light and advanced PHP framework", "keywords": [ "framework", @@ -379,9 +373,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.22.1" + "source": "https://github.com/utopia-php/framework/tree/0.23.1" }, - "time": "2022-10-07T14:51:40+00:00" + "time": "2022-10-19T10:35:44+00:00" } ], "packages-dev": [ @@ -4114,5 +4108,5 @@ "ext-mongodb": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.2.0" } diff --git a/phpunit.xml b/phpunit.xml index 7bc4228a4..97f6e15b5 100755 --- a/phpunit.xml +++ b/phpunit.xml @@ -7,7 +7,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false"> + stopOnFailure="true"> ./tests/ diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index edf177376..1893e0e4d 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -148,34 +148,48 @@ public function createCollection(string $name, array $attributes = [], array $in $database = $this->getDefaultDatabase(); $namespace = $this->getNamespace(); $id = $this->filter($name); + $collectionAttributes = []; foreach ($attributes as $key => $attribute) { $attrId = $this->filter($attribute->getId()); - $attrType = $this->getSQLType($attribute->getAttribute('type'), $attribute->getAttribute('size', 0), $attribute->getAttribute('signed', true)); + $size = $attribute->getAttribute('size', 0); + $type = $attribute->getAttribute('type'); + $signed = $attribute->getAttribute('signed', false); + $attrType = $this->getSQLType($type, $size, $signed); if ($attribute->getAttribute('array')) { $attrType = 'LONGTEXT'; } $attributes[$key] = "`{$attrId}` {$attrType}, "; + $collectionAttributes[$attrId] = $attribute; } foreach ($indexes as $key => $index) { $indexId = $this->filter($index->getId()); $indexType = $index->getAttribute('type'); - $indexAttributes = $index->getAttribute('attributes'); + foreach ($indexAttributes as $nested => $attribute) { - $indexLength = $index->getAttribute('lengths')[$key] ?? ''; - $indexLength = (empty($indexLength)) ? '' : '(' . (int)$indexLength . ')'; - $indexOrder = $index->getAttribute('orders')[$key] ?? ''; $indexAttribute = $this->filter($attribute); + //$collectionAttributes[$indexAttribute]['size'] = $collectionAttributes[$indexAttribute]['size'] ?? 0; + $size = isset($index['lengths'][$key]) ? $index['lengths'][$key]:0 ; + + if($collectionAttributes[$indexAttribute]['type'] === Database::VAR_STRING){ + if($collectionAttributes[$indexAttribute]['size'] > 700){ + $size = $size === 0 || $size > 700 ? 700 : $size; + } + } + + $length = $size === 0 ? '' : '(' . $size . ')'; + $indexOrder = $index->getAttribute('orders')[$key] ?? ''; + if ($indexType === Database::INDEX_FULLTEXT) { $indexOrder = ''; } - $indexAttributes[$nested] = "`{$indexAttribute}`{$indexLength} {$indexOrder}"; + $indexAttributes[$nested] = "`{$indexAttribute}`{$length} {$indexOrder}"; } $indexes[$key] = "{$indexType} `{$indexId}` (" . \implode(", ", $indexAttributes) . " ),"; @@ -368,7 +382,6 @@ public function deleteAttribute(string $collection, string $id, bool $array = fa * @param array $orders * @return bool * @throws Exception - * @throws PDOException */ public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths, array $orders): bool { @@ -383,6 +396,18 @@ public function createIndex(string $collection, string $id, string $type, array }, $attributes); foreach ($attributes as $key => $attribute) { + +// $size = (int)($lengths[$key] ?? 0); +// foreach ($collectionAttributes as $ca){ +// if($attribute === $ca['key']){ +// if($ca['type'] == Database::VAR_STRING){ +// if($ca['size'] > 700){ +// $size = $size === 0 || $size > 700 ? 700 : $size; +// } +// } +// } +// } + $length = $lengths[$key] ?? ''; $length = (empty($length)) ? '' : '(' . (int)$length . ')'; $order = $orders[$key] ?? ''; @@ -1790,7 +1815,6 @@ protected function getSQLIndex(string $collection, string $id, string $type, ar default: throw new Exception('Unknown Index Type:' . $type); - break; } return "CREATE {$type} `{$id}` ON {$this->getSQLTable($collection)} ( " . implode(', ', $attributes) . " )"; diff --git a/src/Database/Adapter/Mongo/MongoDBAdapter.php b/src/Database/Adapter/Mongo/MongoDBAdapter.php index 9e8fde2c2..b04c7c9df 100644 --- a/src/Database/Adapter/Mongo/MongoDBAdapter.php +++ b/src/Database/Adapter/Mongo/MongoDBAdapter.php @@ -284,18 +284,19 @@ public function renameAttribute(string $collection, string $id, string $name): b /** * Create Index * - * @param string $collection + * @param Document $collection * @param string $id * @param string $type * @param array $attributes * @param array $lengths * @param array $orders - * + * @param array $collation * @return bool + * @throws Exception */ - public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths, array $orders, array $collation = []): bool + public function createIndex(Document $collection, string $id, string $type, array $attributes, array $lengths, array $orders, array $collation = []): bool { - $name = $this->getNamespace() . '_' . $this->filter($collection); + $name = $this->getNamespace() . '_' . $this->filter($collection->getId()); $id = $this->filter($id); $indexes = []; diff --git a/src/Database/Adapter/SQLite.php b/src/Database/Adapter/SQLite.php index 44cc68c68..abda42c8c 100644 --- a/src/Database/Adapter/SQLite.php +++ b/src/Database/Adapter/SQLite.php @@ -254,10 +254,10 @@ public function renameIndex(string $collection, string $old, string $new): bool * @param array $orders * @return bool * @throws Exception - * @throws PDOException */ public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths, array $orders): bool { + // $name = $this->filter($collection->getId()); $name = $this->filter($collection); $id = $this->filter($id); diff --git a/src/Database/Database.php b/src/Database/Database.php index e9e93c3e8..a52708921 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -1176,6 +1176,7 @@ public function renameIndex(string $collection, string $old, string $new): bool * @param array $orders * * @return bool + * @throws Exception */ public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths = [], array $orders = []): bool { @@ -1184,7 +1185,10 @@ public function createIndex(string $collection, string $id, string $type, array } $collection = $this->silent(fn() => $this->getCollection($collection)); - + if($collection->isEmpty()){ + throw new Exception('Not found'); + } + // index IDs are case insensitive $indexes = $collection->getAttribute('indexes', []); /** @var Document[] $indexes */ @@ -1219,7 +1223,6 @@ public function createIndex(string $collection, string $id, string $type, array default: throw new Exception('Unknown index type: ' . $type); - break; } $index = $this->adapter->createIndex($collection->getId(), $id, $type, $attributes, $lengths, $orders); diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index 723f8b62a39202fbfbc750206034d06cefd40bf7..95c67fd2931a0fc8b7fa75838f15b48f17edf99a 100644 GIT binary patch delta 36206 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, static::getDatabase()->createAttribute('indexes', 'integer', Database::VAR_INTEGER, 0, true)); $this->assertEquals(true, static::getDatabase()->createAttribute('indexes', 'float', Database::VAR_FLOAT, 0, true)); $this->assertEquals(true, static::getDatabase()->createAttribute('indexes', 'boolean', Database::VAR_BOOLEAN, 0, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('indexes', 'long_varchar', Database::VAR_STRING, 2048, true)); // Indexes $this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'index1', Database::INDEX_KEY, ['string', 'integer'], [128], [Database::ORDER_ASC])); @@ -291,6 +292,8 @@ public function testCreateDeleteIndex() $this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'index4', Database::INDEX_UNIQUE, ['string'], [128], [Database::ORDER_ASC])); $this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'index5', Database::INDEX_UNIQUE, ['$id', 'string'], [128], [Database::ORDER_ASC])); $this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'order', Database::INDEX_UNIQUE, ['order'], [128], [Database::ORDER_ASC])); + //$this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'long_varchar', Database::INDEX_UNIQUE, ['long_varchar'], [], [Database::ORDER_ASC])); + $collection = static::getDatabase()->getCollection('indexes'); $this->assertCount(6, $collection->getAttribute('indexes')); @@ -302,6 +305,7 @@ public function testCreateDeleteIndex() $this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'index4')); $this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'index5')); $this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'order')); + //$this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'long_varchar')); $collection = static::getDatabase()->getCollection('indexes'); $this->assertCount(0, $collection->getAttribute('indexes')); @@ -315,7 +319,7 @@ public function testCreateCollectionWithSchema() new Document([ '$id' => ID::custom('attribute1'), 'type' => Database::VAR_STRING, - 'size' => 256, + 'size' => 2500, 'required' => false, 'signed' => true, 'array' => false, @@ -346,7 +350,7 @@ public function testCreateCollectionWithSchema() '$id' => ID::custom('index1'), 'type' => Database::INDEX_KEY, 'attributes' => ['attribute1'], - 'lengths' => [256], + 'lengths' => [], 'orders' => ['ASC'], ]), new Document([ From 6dfc74188e24ffa600f2e0edc505a2f168e8cc04 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 20 Oct 2022 22:41:52 +0300 Subject: [PATCH 02/21] mongo revert changes --- src/Database/Adapter/Mongo/MongoDBAdapter.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Database/Adapter/Mongo/MongoDBAdapter.php b/src/Database/Adapter/Mongo/MongoDBAdapter.php index b04c7c9df..9e8fde2c2 100644 --- a/src/Database/Adapter/Mongo/MongoDBAdapter.php +++ b/src/Database/Adapter/Mongo/MongoDBAdapter.php @@ -284,19 +284,18 @@ public function renameAttribute(string $collection, string $id, string $name): b /** * Create Index * - * @param Document $collection + * @param string $collection * @param string $id * @param string $type * @param array $attributes * @param array $lengths * @param array $orders - * @param array $collation + * * @return bool - * @throws Exception */ - public function createIndex(Document $collection, string $id, string $type, array $attributes, array $lengths, array $orders, array $collation = []): bool + public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths, array $orders, array $collation = []): bool { - $name = $this->getNamespace() . '_' . $this->filter($collection->getId()); + $name = $this->getNamespace() . '_' . $this->filter($collection); $id = $this->filter($id); $indexes = []; From fef0691e3d67ffc3c9e1e8e82bf2712cb4ceee46 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 18:20:47 +0300 Subject: [PATCH 03/21] make pr more clear --- src/Database/Adapter/MariaDB.php | 69 ++- src/Database/Database.php | 64 ++- tests/Database/Adapter/MongoDBTest.php | 758 ++++++++++++------------- tests/Database/Adapter/SQLiteTest.php | 158 +++--- tests/Database/Adapter/database.sql | Bin 1212416 -> 1212416 bytes 5 files changed, 553 insertions(+), 496 deletions(-) diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 1893e0e4d..df2c3a6f0 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -148,7 +148,7 @@ public function createCollection(string $name, array $attributes = [], array $in $database = $this->getDefaultDatabase(); $namespace = $this->getNamespace(); $id = $this->filter($name); - $collectionAttributes = []; + $attributesArray = []; foreach ($attributes as $key => $attribute) { $attrId = $this->filter($attribute->getId()); @@ -161,8 +161,7 @@ public function createCollection(string $name, array $attributes = [], array $in $attrType = 'LONGTEXT'; } - $attributes[$key] = "`{$attrId}` {$attrType}, "; - $collectionAttributes[$attrId] = $attribute; + $attributesArray[$key] = "`{$attrId}` {$attrType}, "; } foreach ($indexes as $key => $index) { @@ -172,19 +171,13 @@ public function createCollection(string $name, array $attributes = [], array $in foreach ($indexAttributes as $nested => $attribute) { $indexAttribute = $this->filter($attribute); + $attr = $this->findAttributeInList($indexAttribute, $attributes); - //$collectionAttributes[$indexAttribute]['size'] = $collectionAttributes[$indexAttribute]['size'] ?? 0; - $size = isset($index['lengths'][$key]) ? $index['lengths'][$key]:0 ; - - if($collectionAttributes[$indexAttribute]['type'] === Database::VAR_STRING){ - if($collectionAttributes[$indexAttribute]['size'] > 700){ - $size = $size === 0 || $size > 700 ? 700 : $size; - } - } - + $size = $index['lengths'][$key] ?? 0; + $size = $this->getDefaultIndexSize($size, $attr); $length = $size === 0 ? '' : '(' . $size . ')'; - $indexOrder = $index->getAttribute('orders')[$key] ?? ''; + $indexOrder = $index->getAttribute('orders')[$key] ?? ''; if ($indexType === Database::INDEX_FULLTEXT) { $indexOrder = ''; } @@ -203,7 +196,7 @@ public function createCollection(string $name, array $attributes = [], array $in `_createdAt` datetime(3) DEFAULT NULL, `_updatedAt` datetime(3) DEFAULT NULL, `_permissions` MEDIUMTEXT DEFAULT NULL, - " . \implode(' ', $attributes) . " + " . \implode(' ', $attributesArray) . " PRIMARY KEY (`_id`), " . \implode(' ', $indexes) . " UNIQUE KEY `_uid` (`_uid`), @@ -1915,4 +1908,52 @@ public static function getPDOAttributes(): array PDO::ATTR_STRINGIFY_FETCHES => true // Returns all fetched data as Strings ]; } + + + /** + * Returns attribute from List of Document $attributes[] + * @param string $attributeKey + * @param array $attributes Document[] + * returns Document + * @return Document|null + * @throws Exception + */ + public function findAttributeInList(string $attributeKey, array $attributes): ?Document + { + $attributeKey = $this->filter($attributeKey); + + /** + * @var Document $attribute + */ + + foreach ($attributes as $attribute){ + if($attributeKey === $this->filter($attribute->getId())){ + return $attribute; + } + } + + return null; + } + + + /** + * Return the maximum index length per attribute type + * @param int $size + * @param Document $attribute + * @return int + */ + public function getDefaultIndexSize(int $size, Document $attribute): int + { + $maxIndexLength = 760; + + if($attribute['type'] === Database::VAR_STRING){ + if($attribute['size'] > $maxIndexLength){ + $size = $size === 0 || $size > $maxIndexLength ? $maxIndexLength : $size; + } + } + + return $size; + } + + } diff --git a/src/Database/Database.php b/src/Database/Database.php index a52708921..b34899f68 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -566,12 +566,15 @@ public function createCollection(string $id, array $attributes = [], array $inde * Get Collection * * @param string $id - * * @return Document - * @throws Exception + * @throws Throwable */ public function getCollection(string $id): Document { + if(empty($id)){ + throw new Exception("getCollection requires a parameter"); + } + $collection = $this->silent(fn() => $this->getDocument(self::METADATA, $id)); $this->trigger(self::EVENT_COLLECTION_READ, $collection); return $collection; @@ -1178,15 +1181,15 @@ public function renameIndex(string $collection, string $old, string $new): bool * @return bool * @throws Exception */ - public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths = [], array $orders = []): bool + public function createIndex(string $collectionName, string $id, string $type, array $attributes, array $lengths = [], array $orders = []): bool { if (empty($attributes)) { throw new Exception('Missing attributes'); } - $collection = $this->silent(fn() => $this->getCollection($collection)); + $collection = $this->silent(fn() => $this->getCollection($collectionName)); if($collection->isEmpty()){ - throw new Exception('Not found'); + throw new Exception('Collection ' . $collectionName . ' Not found'); } // index IDs are case insensitive @@ -1251,10 +1254,14 @@ public function createIndex(string $collection, string $id, string $type, array * @param string $id * * @return bool + * @throws Exception */ - public function deleteIndex(string $collection, string $id): bool + public function deleteIndex(string $collectionName, string $id): bool { - $collection = $this->silent(fn() => $this->getCollection($collection)); + $collection = $this->silent(fn() => $this->getCollection($collectionName)); + if($collection->isEmpty()){ + throw new Exception('Collection ' .$collectionName . ' Not found'); + } $indexes = $collection->getAttribute('indexes', []); @@ -1284,21 +1291,19 @@ public function deleteIndex(string $collection, string $id): bool * @param string $id * * @return Document + * @throws Exception|Throwable */ - public function getDocument(string $collection, string $id): Document + public function getDocument(string $collectionName, string $id): Document { - if ($collection === self::METADATA && $id === self::METADATA) { + if ($collectionName === self::METADATA && $id === self::METADATA) { return new Document($this->collection); } - if (empty($collection)) { - throw new Exception('test exception: ' . $collection . ':' . $id); + $collection = $this->silent(fn() => $this->getCollection($collectionName)); + if($collection->isEmpty()){ + throw new Exception('Collection ' .$collectionName . ' Not found'); } - $collection = $this->silent(fn() => $this->getCollection($collection)); - $document = null; - $cache = null; - $validator = new Authorization(self::PERMISSION_READ); // TODO@kodumbeats Check if returned cache id matches request @@ -1345,11 +1350,14 @@ public function getDocument(string $collection, string $id): Document * * @throws AuthorizationException * @throws StructureException - * @throws Exception + * @throws Exception|Throwable */ public function createDocument(string $collection, Document $document): Document { $collection = $this->silent(fn() => $this->getCollection($collection)); + if($collection->isEmpty()){ + throw new Exception('Collection ' .$collection->getId() . ' Not found'); + } $time = DateTime::now(); @@ -1396,6 +1404,9 @@ public function updateDocument(string $collection, string $id, Document $documen $old = Authorization::skip(fn() => $this->silent(fn() => $this->getDocument($collection, $id))); // Skip ensures user does not need read permission for this $collection = $this->silent(fn() => $this->getCollection($collection)); + if($collection->isEmpty()){ + throw new Exception('Collection ' .$collection->getId() . ' Not found'); + } $validator = new Authorization(self::PERMISSION_UPDATE); @@ -1430,6 +1441,7 @@ public function updateDocument(string $collection, string $id, Document $documen * @return bool * * @throws AuthorizationException + * @throws Exception */ public function deleteDocument(string $collection, string $id): bool { @@ -1437,6 +1449,9 @@ public function deleteDocument(string $collection, string $id): bool $document = Authorization::skip(fn() => $this->silent(fn() => $this->getDocument($collection, $id))); // Skip ensures user does not need read permission for this $collection = $this->silent(fn() => $this->getCollection($collection)); + if($collection->isEmpty()){ + throw new Exception('Collection ' .$collection->getId() . ' Not found'); + } if ($collection->getId() !== self::METADATA && !$validator->isValid($document->getDelete())) { @@ -1487,6 +1502,9 @@ public function deleteCachedDocument(string $collection, string $id): bool public function find(string $collection, array $queries = []): array { $collection = $this->silent(fn() => $this->getCollection($collection)); + if($collection->isEmpty()){ + throw new Exception('Collection ' .$collection->getId() . ' Not found'); + } $grouped = Query::groupByType($queries); /** @var Query[] */ $filters = $grouped['filters']; @@ -1555,9 +1573,8 @@ public function findOne(string $collection, array $queries = []): bool|Document public function count(string $collection, array $queries = [], int $max = 0): int { $collection = $this->silent(fn() => $this->getCollection($collection)); - - if ($collection->isEmpty()) { - throw new Exception("Collection not found"); + if($collection->isEmpty()){ + throw new Exception('Collection ' .$collection->getId() . ' Not found'); } $queries = Query::groupByType($queries)['filters']; @@ -1581,12 +1598,11 @@ public function count(string $collection, array $queries = [], int $max = 0): in * @return int|float * @throws Exception */ - public function sum(string $collection, string $attribute, array $queries = [], int $max = 0) + public function sum(string $collectionName, string $attribute, array $queries = [], int $max = 0) { - $collection = $this->silent(fn() => $this->getCollection($collection)); - - if ($collection->isEmpty()) { - throw new Exception("Collection not found"); + $collection = $this->silent(fn() => $this->getCollection($collectionName)); + if($collection->isEmpty()){ + throw new Exception('Collection ' .$collectionName . ' Not found'); } $queries = self::convertQueries($collection, $queries); diff --git a/tests/Database/Adapter/MongoDBTest.php b/tests/Database/Adapter/MongoDBTest.php index 513a9471a..c02882a8e 100644 --- a/tests/Database/Adapter/MongoDBTest.php +++ b/tests/Database/Adapter/MongoDBTest.php @@ -1,380 +1,380 @@ connect('redis', 6379); - $redis->flushAll(); - $cache = new Cache(new RedisAdapter($redis)); - - $options = new MongoClientOptions( - 'utopia_testing', - 'mongo', - 27017, - 'root', - 'example' - ); - - $client = new MongoClient($options, false); - - $database = new Database(new MongoDBAdapter($client), $cache); - $database->setDefaultDatabase('utopiaTests'); - $database->setNamespace('myapp_' . uniqid()); - - - return self::$database = $database; - } - - public function testCreateExistsDelete() - { - $this->assertNotNull(static::getDatabase()->create($this->testDatabase)); - - $this->assertEquals(true, static::getDatabase()->exists($this->testDatabase)); - $this->assertEquals(true, static::getDatabase()->delete($this->testDatabase)); - - // Mongo creates on the fly, so this will never be true, do we want to try to make it pass - // by doing something else? - // $this->assertEquals(false, static::getDatabase()->exists($this->testDatabase)); - // $this->assertEquals(true, static::getDatabase()->create($this->testDatabase)); - // $this->assertEquals(true, static::getDatabase()->setDefaultDatabase($this->testDatabase)); - } - - /** - * @depends testCreateDocument - */ - public function testListDocumentSearch(Document $document) - { - static::getDatabase()->createIndex('documents', 'string', Database::INDEX_FULLTEXT, ['string']); - static::getDatabase()->createDocument('documents', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - 'string' => '*test+alias@email-provider.com', - 'integer' => 0, - 'bigint' => 8589934592, // 2^33 - 'float' => 5.55, - 'boolean' => true, - 'colors' => ['pink', 'green', 'blue'], - 'empty' => [], - ])); - - $documents = static::getDatabase()->find('documents', [ - Query::search('string', '*test+alias@email-provider.com') - ]); - - $this->assertEquals(1, count($documents)); - - return $document; - } - - /** - * @depends testUpdateDocument - */ - public function testFind(Document $document) - { - static::getDatabase()->createCollection('movies'); - - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'name', Database::VAR_STRING, 128, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'director', Database::VAR_STRING, 128, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, null, true, true)); - - static::getDatabase()->createDocument('movies', new Document([ - '$id' => ID::custom('frozen'), - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Frozen', - 'director' => 'Chris Buck & Jennifer Lee', - 'year' => 2013, - 'price' => 39.50, - 'active' => true, - 'generes' => ['animation', 'kids'], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Frozen II', - 'director' => 'Chris Buck & Jennifer Lee', - 'year' => 2019, - 'price' => 39.50, - 'active' => true, - 'generes' => ['animation', 'kids'], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Captain America: The First Avenger', - 'director' => 'Joe Johnston', - 'year' => 2011, - 'price' => 25.94, - 'active' => true, - 'generes' => ['science fiction', 'action', 'comics'], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Captain Marvel', - 'director' => 'Anna Boden & Ryan Fleck', - 'year' => 2019, - 'price' => 25.99, - 'active' => true, - 'generes' => ['science fiction', 'action', 'comics'], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Work in Progress', - 'director' => 'TBD', - 'year' => 2025, - 'price' => 0.0, - 'active' => false, - 'generes' => [], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::user(ID::custom('x'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Work in Progress 2', - 'director' => 'TBD', - 'year' => 2026, - 'price' => 0.0, - 'active' => false, - 'generes' => [], - ])); - - /** - * Check Basic - */ - $documents = static::getDatabase()->count('movies'); - - $this->assertEquals(5, $documents); - } - - /** - * @depends testCreateExistsDelete - */ - public function testCreateListExistsDeleteCollection() - { - $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors')); - - $this->assertCount(1, static::getDatabase()->listCollections()); - $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); - - // Collection names should not be unique - $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors2')); - $this->assertCount(2, static::getDatabase()->listCollections()); - $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors2')); - $collection = static::getDatabase()->getCollection('actors2'); - $collection->setAttribute('name', 'actors'); // change name to one that exists - - $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->updateDocument($collection->getCollection(), $collection->getId(), $collection)); - $this->assertEquals(true, static::getDatabase()->deleteCollection('actors2')); // Delete collection when finished - $this->assertCount(1, static::getDatabase()->listCollections()); - - $this->assertEquals(false, static::getDatabase()->getCollection('actors')->isEmpty()); - $this->assertEquals(true, static::getDatabase()->deleteCollection('actors')); - $this->assertEquals(true, static::getDatabase()->getCollection('actors')->isEmpty()); - - $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); - } - - /** - * @depends testFind - */ - public function testCount() - { - $count = static::getDatabase()->count('movies'); - $this->assertEquals(5, $count); - - $count = static::getDatabase()->count('movies', [new Query(Query::TYPE_EQUAL, 'year', [2019]),]); - $this->assertEquals(2, $count); - - Authorization::unsetRole('userx'); - $count = static::getDatabase()->count('movies'); - $this->assertEquals(5, $count); - - Authorization::disable(); - $count = static::getDatabase()->count('movies'); - $this->assertEquals(6, $count); - Authorization::reset(); - - Authorization::disable(); - $count = static::getDatabase()->count('movies', [], 3); - $this->assertEquals(3, $count); - Authorization::reset(); - - /** - * Test that OR queries are handled correctly - */ - Authorization::disable(); - $count = static::getDatabase()->count('movies', [ - new Query(Query::TYPE_EQUAL, 'director', ['TBD', 'Joe Johnston']), - new Query(Query::TYPE_EQUAL, 'year', [2025]), - ]); - $this->assertEquals(1, $count); - Authorization::reset(); - } - - public function testRenameAttribute() - { - $this->assertTrue(true); - } - - public function testRenameAttributeExisting() - { - $this->assertTrue(true); - } - - public function testUpdateAttributeStructure() - { - $this->assertTrue(true); - } - - /** - * Ensure the collection is removed after use - * - * @depends testIndexCaseInsensitivity - */ - public function testCleanupAttributeTests() - { - $res = static::getDatabase()->deleteCollection('attributes'); - - $this->assertEquals(true, $res); - } -} +// +//namespace Utopia\Tests\Adapter; +// +//use Redis; +//use Utopia\Cache\Cache; +//use Utopia\Cache\Adapter\Redis as RedisAdapter; +//use Utopia\Database\Database; +//use Utopia\Database\Document; +//use Utopia\Database\Adapter\Mongo\MongoClient; +//use Utopia\Database\Adapter\Mongo\MongoClientOptions; +//use Utopia\Database\Adapter\Mongo\MongoDBAdapter; +//use Utopia\Database\ID; +//use Utopia\Database\Permission; +//use Utopia\Database\Query; +//use Utopia\Database\Role; +//use Utopia\Database\Validator\Authorization; +// +//use Utopia\Tests\Base; +// +//class MongoDBTest extends Base +//{ +// static $pool = null; +// +// /** +// * @var Database +// */ +// static $database = null; +// +// +// // TODO@kodumbeats hacky way to identify adapters for tests +// // Remove once all methods are implemented +// /** +// * Return name of adapter +// * +// * @return string +// */ +// static function getAdapterName(): string +// { +// return "mongodb"; +// } +// +// /** +// * Return row limit of adapter +// * +// * @return int +// */ +// static function getAdapterRowLimit(): int +// { +// return 0; +// } +// +// /** +// * @return Database +// */ +// static function getDatabase(): Database +// { +// if (!is_null(self::$database)) { +// return self::$database; +// } +// +// $redis = new Redis(); +// $redis->connect('redis', 6379); +// $redis->flushAll(); +// $cache = new Cache(new RedisAdapter($redis)); +// +// $options = new MongoClientOptions( +// 'utopia_testing', +// 'mongo', +// 27017, +// 'root', +// 'example' +// ); +// +// $client = new MongoClient($options, false); +// +// $database = new Database(new MongoDBAdapter($client), $cache); +// $database->setDefaultDatabase('utopiaTests'); +// $database->setNamespace('myapp_' . uniqid()); +// +// +// return self::$database = $database; +// } +// +// public function testCreateExistsDelete() +// { +// $this->assertNotNull(static::getDatabase()->create($this->testDatabase)); +// +// $this->assertEquals(true, static::getDatabase()->exists($this->testDatabase)); +// $this->assertEquals(true, static::getDatabase()->delete($this->testDatabase)); +// +// // Mongo creates on the fly, so this will never be true, do we want to try to make it pass +// // by doing something else? +// // $this->assertEquals(false, static::getDatabase()->exists($this->testDatabase)); +// // $this->assertEquals(true, static::getDatabase()->create($this->testDatabase)); +// // $this->assertEquals(true, static::getDatabase()->setDefaultDatabase($this->testDatabase)); +// } +// +// /** +// * @depends testCreateDocument +// */ +// public function testListDocumentSearch(Document $document) +// { +// static::getDatabase()->createIndex('documents', 'string', Database::INDEX_FULLTEXT, ['string']); +// static::getDatabase()->createDocument('documents', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::create(Role::any()), +// Permission::update(Role::any()), +// Permission::delete(Role::any()), +// ], +// 'string' => '*test+alias@email-provider.com', +// 'integer' => 0, +// 'bigint' => 8589934592, // 2^33 +// 'float' => 5.55, +// 'boolean' => true, +// 'colors' => ['pink', 'green', 'blue'], +// 'empty' => [], +// ])); +// +// $documents = static::getDatabase()->find('documents', [ +// Query::search('string', '*test+alias@email-provider.com') +// ]); +// +// $this->assertEquals(1, count($documents)); +// +// return $document; +// } +// +// /** +// * @depends testUpdateDocument +// */ +// public function testFind(Document $document) +// { +// static::getDatabase()->createCollection('movies'); +// +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'name', Database::VAR_STRING, 128, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'director', Database::VAR_STRING, 128, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, null, true, true)); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$id' => ID::custom('frozen'), +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Frozen', +// 'director' => 'Chris Buck & Jennifer Lee', +// 'year' => 2013, +// 'price' => 39.50, +// 'active' => true, +// 'generes' => ['animation', 'kids'], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Frozen II', +// 'director' => 'Chris Buck & Jennifer Lee', +// 'year' => 2019, +// 'price' => 39.50, +// 'active' => true, +// 'generes' => ['animation', 'kids'], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Captain America: The First Avenger', +// 'director' => 'Joe Johnston', +// 'year' => 2011, +// 'price' => 25.94, +// 'active' => true, +// 'generes' => ['science fiction', 'action', 'comics'], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Captain Marvel', +// 'director' => 'Anna Boden & Ryan Fleck', +// 'year' => 2019, +// 'price' => 25.99, +// 'active' => true, +// 'generes' => ['science fiction', 'action', 'comics'], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Work in Progress', +// 'director' => 'TBD', +// 'year' => 2025, +// 'price' => 0.0, +// 'active' => false, +// 'generes' => [], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::user(ID::custom('x'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Work in Progress 2', +// 'director' => 'TBD', +// 'year' => 2026, +// 'price' => 0.0, +// 'active' => false, +// 'generes' => [], +// ])); +// +// /** +// * Check Basic +// */ +// $documents = static::getDatabase()->count('movies'); +// +// $this->assertEquals(5, $documents); +// } +// +// /** +// * @depends testCreateExistsDelete +// */ +// public function testCreateListExistsDeleteCollection() +// { +// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors')); +// +// $this->assertCount(1, static::getDatabase()->listCollections()); +// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); +// +// // Collection names should not be unique +// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors2')); +// $this->assertCount(2, static::getDatabase()->listCollections()); +// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors2')); +// $collection = static::getDatabase()->getCollection('actors2'); +// $collection->setAttribute('name', 'actors'); // change name to one that exists +// +// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->updateDocument($collection->getCollection(), $collection->getId(), $collection)); +// $this->assertEquals(true, static::getDatabase()->deleteCollection('actors2')); // Delete collection when finished +// $this->assertCount(1, static::getDatabase()->listCollections()); +// +// $this->assertEquals(false, static::getDatabase()->getCollection('actors')->isEmpty()); +// $this->assertEquals(true, static::getDatabase()->deleteCollection('actors')); +// $this->assertEquals(true, static::getDatabase()->getCollection('actors')->isEmpty()); +// +// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); +// } +// +// /** +// * @depends testFind +// */ +// public function testCount() +// { +// $count = static::getDatabase()->count('movies'); +// $this->assertEquals(5, $count); +// +// $count = static::getDatabase()->count('movies', [new Query(Query::TYPE_EQUAL, 'year', [2019]),]); +// $this->assertEquals(2, $count); +// +// Authorization::unsetRole('userx'); +// $count = static::getDatabase()->count('movies'); +// $this->assertEquals(5, $count); +// +// Authorization::disable(); +// $count = static::getDatabase()->count('movies'); +// $this->assertEquals(6, $count); +// Authorization::reset(); +// +// Authorization::disable(); +// $count = static::getDatabase()->count('movies', [], 3); +// $this->assertEquals(3, $count); +// Authorization::reset(); +// +// /** +// * Test that OR queries are handled correctly +// */ +// Authorization::disable(); +// $count = static::getDatabase()->count('movies', [ +// new Query(Query::TYPE_EQUAL, 'director', ['TBD', 'Joe Johnston']), +// new Query(Query::TYPE_EQUAL, 'year', [2025]), +// ]); +// $this->assertEquals(1, $count); +// Authorization::reset(); +// } +// +// public function testRenameAttribute() +// { +// $this->assertTrue(true); +// } +// +// public function testRenameAttributeExisting() +// { +// $this->assertTrue(true); +// } +// +// public function testUpdateAttributeStructure() +// { +// $this->assertTrue(true); +// } +// +// /** +// * Ensure the collection is removed after use +// * +// * @depends testIndexCaseInsensitivity +// */ +// public function testCleanupAttributeTests() +// { +// $res = static::getDatabase()->deleteCollection('attributes'); +// +// $this->assertEquals(true, $res); +// } +//} diff --git a/tests/Database/Adapter/SQLiteTest.php b/tests/Database/Adapter/SQLiteTest.php index 3d12ef630..668900f5a 100644 --- a/tests/Database/Adapter/SQLiteTest.php +++ b/tests/Database/Adapter/SQLiteTest.php @@ -1,80 +1,80 @@ connect('redis', 6379); - $redis->flushAll(); - - $cache = new Cache(new RedisAdapter($redis)); - - $database = new Database(new SQLite($pdo), $cache); - $database->setDefaultDatabase('utopiaTests'); - $database->setNamespace('myapp_'.uniqid()); - - return self::$database = $database; - } -} \ No newline at end of file +// +//namespace Utopia\Tests\Adapter; +// +//use PDO; +//use Redis; +//use Utopia\Cache\Cache; +//use Utopia\Database\Database; +//use Utopia\Cache\Adapter\Redis as RedisAdapter; +//use Utopia\Database\Adapter\SQLite; +//use Utopia\Tests\Base; +// +//class SQLiteTest extends Base +//{ +// /** +// * @var Database +// */ +// static $database = null; +// +// // TODO@kodumbeats hacky way to identify adapters for tests +// // Remove once all methods are implemented +// /** +// * Return name of adapter +// * +// * @return string +// */ +// static function getAdapterName(): string +// { +// return "sqlite"; +// } +// +// /** +// * Return row limit of adapter +// * +// * @return int +// */ +// static function getAdapterRowLimit(): int +// { +// return SQLite::getRowLimit(); +// } +// +// /** +// * +// * @return int +// */ +// static function getUsedIndexes(): int +// { +// return SQLite::getCountOfDefaultIndexes(); +// } +// +// /** +// * @return Database +// */ +// static function getDatabase(): Database +// { +// if(!is_null(self::$database)) { +// return self::$database; +// } +// +// $sqliteDir = __DIR__."/database.sql"; +// +// if(file_exists($sqliteDir)) { +// unlink($sqliteDir); +// } +// +// $pdo = new PDO("sqlite:".$sqliteDir, null, null, SQLite::getPDOAttributes()); +// +// $redis = new Redis(); +// $redis->connect('redis', 6379); +// $redis->flushAll(); +// +// $cache = new Cache(new RedisAdapter($redis)); +// +// $database = new Database(new SQLite($pdo), $cache); +// $database->setDefaultDatabase('utopiaTests'); +// $database->setNamespace('myapp_'.uniqid()); +// +// return self::$database = $database; +// } +//} \ No newline at end of file diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index 95c67fd2931a0fc8b7fa75838f15b48f17edf99a..332d85f4c24f0120537a417f3a817824b999551c 100644 GIT binary patch delta 32535 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 Pd9(0KNrT}313dm;cu-wR delta 32043 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�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 Zd<_1-@0V`dY2lY1+ZX1420A+z{cqu8%}4+M From fa88dfbb26efec9919d14ebd8fc5cb6e681d6e4b Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 18:22:13 +0300 Subject: [PATCH 04/21] remove test comments --- tests/Database/Adapter/MongoDBTest.php | 758 ++++++++++++------------- tests/Database/Adapter/SQLiteTest.php | 158 +++--- 2 files changed, 458 insertions(+), 458 deletions(-) diff --git a/tests/Database/Adapter/MongoDBTest.php b/tests/Database/Adapter/MongoDBTest.php index c02882a8e..513a9471a 100644 --- a/tests/Database/Adapter/MongoDBTest.php +++ b/tests/Database/Adapter/MongoDBTest.php @@ -1,380 +1,380 @@ connect('redis', 6379); -// $redis->flushAll(); -// $cache = new Cache(new RedisAdapter($redis)); -// -// $options = new MongoClientOptions( -// 'utopia_testing', -// 'mongo', -// 27017, -// 'root', -// 'example' -// ); -// -// $client = new MongoClient($options, false); -// -// $database = new Database(new MongoDBAdapter($client), $cache); -// $database->setDefaultDatabase('utopiaTests'); -// $database->setNamespace('myapp_' . uniqid()); -// -// -// return self::$database = $database; -// } -// -// public function testCreateExistsDelete() -// { -// $this->assertNotNull(static::getDatabase()->create($this->testDatabase)); -// -// $this->assertEquals(true, static::getDatabase()->exists($this->testDatabase)); -// $this->assertEquals(true, static::getDatabase()->delete($this->testDatabase)); -// -// // Mongo creates on the fly, so this will never be true, do we want to try to make it pass -// // by doing something else? -// // $this->assertEquals(false, static::getDatabase()->exists($this->testDatabase)); -// // $this->assertEquals(true, static::getDatabase()->create($this->testDatabase)); -// // $this->assertEquals(true, static::getDatabase()->setDefaultDatabase($this->testDatabase)); -// } -// -// /** -// * @depends testCreateDocument -// */ -// public function testListDocumentSearch(Document $document) -// { -// static::getDatabase()->createIndex('documents', 'string', Database::INDEX_FULLTEXT, ['string']); -// static::getDatabase()->createDocument('documents', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::create(Role::any()), -// Permission::update(Role::any()), -// Permission::delete(Role::any()), -// ], -// 'string' => '*test+alias@email-provider.com', -// 'integer' => 0, -// 'bigint' => 8589934592, // 2^33 -// 'float' => 5.55, -// 'boolean' => true, -// 'colors' => ['pink', 'green', 'blue'], -// 'empty' => [], -// ])); -// -// $documents = static::getDatabase()->find('documents', [ -// Query::search('string', '*test+alias@email-provider.com') -// ]); -// -// $this->assertEquals(1, count($documents)); -// -// return $document; -// } -// -// /** -// * @depends testUpdateDocument -// */ -// public function testFind(Document $document) -// { -// static::getDatabase()->createCollection('movies'); -// -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'name', Database::VAR_STRING, 128, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'director', Database::VAR_STRING, 128, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, null, true, true)); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$id' => ID::custom('frozen'), -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Frozen', -// 'director' => 'Chris Buck & Jennifer Lee', -// 'year' => 2013, -// 'price' => 39.50, -// 'active' => true, -// 'generes' => ['animation', 'kids'], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Frozen II', -// 'director' => 'Chris Buck & Jennifer Lee', -// 'year' => 2019, -// 'price' => 39.50, -// 'active' => true, -// 'generes' => ['animation', 'kids'], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Captain America: The First Avenger', -// 'director' => 'Joe Johnston', -// 'year' => 2011, -// 'price' => 25.94, -// 'active' => true, -// 'generes' => ['science fiction', 'action', 'comics'], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Captain Marvel', -// 'director' => 'Anna Boden & Ryan Fleck', -// 'year' => 2019, -// 'price' => 25.99, -// 'active' => true, -// 'generes' => ['science fiction', 'action', 'comics'], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Work in Progress', -// 'director' => 'TBD', -// 'year' => 2025, -// 'price' => 0.0, -// 'active' => false, -// 'generes' => [], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::user(ID::custom('x'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Work in Progress 2', -// 'director' => 'TBD', -// 'year' => 2026, -// 'price' => 0.0, -// 'active' => false, -// 'generes' => [], -// ])); -// -// /** -// * Check Basic -// */ -// $documents = static::getDatabase()->count('movies'); -// -// $this->assertEquals(5, $documents); -// } -// -// /** -// * @depends testCreateExistsDelete -// */ -// public function testCreateListExistsDeleteCollection() -// { -// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors')); -// -// $this->assertCount(1, static::getDatabase()->listCollections()); -// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); -// -// // Collection names should not be unique -// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors2')); -// $this->assertCount(2, static::getDatabase()->listCollections()); -// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors2')); -// $collection = static::getDatabase()->getCollection('actors2'); -// $collection->setAttribute('name', 'actors'); // change name to one that exists -// -// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->updateDocument($collection->getCollection(), $collection->getId(), $collection)); -// $this->assertEquals(true, static::getDatabase()->deleteCollection('actors2')); // Delete collection when finished -// $this->assertCount(1, static::getDatabase()->listCollections()); -// -// $this->assertEquals(false, static::getDatabase()->getCollection('actors')->isEmpty()); -// $this->assertEquals(true, static::getDatabase()->deleteCollection('actors')); -// $this->assertEquals(true, static::getDatabase()->getCollection('actors')->isEmpty()); -// -// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); -// } -// -// /** -// * @depends testFind -// */ -// public function testCount() -// { -// $count = static::getDatabase()->count('movies'); -// $this->assertEquals(5, $count); -// -// $count = static::getDatabase()->count('movies', [new Query(Query::TYPE_EQUAL, 'year', [2019]),]); -// $this->assertEquals(2, $count); -// -// Authorization::unsetRole('userx'); -// $count = static::getDatabase()->count('movies'); -// $this->assertEquals(5, $count); -// -// Authorization::disable(); -// $count = static::getDatabase()->count('movies'); -// $this->assertEquals(6, $count); -// Authorization::reset(); -// -// Authorization::disable(); -// $count = static::getDatabase()->count('movies', [], 3); -// $this->assertEquals(3, $count); -// Authorization::reset(); -// -// /** -// * Test that OR queries are handled correctly -// */ -// Authorization::disable(); -// $count = static::getDatabase()->count('movies', [ -// new Query(Query::TYPE_EQUAL, 'director', ['TBD', 'Joe Johnston']), -// new Query(Query::TYPE_EQUAL, 'year', [2025]), -// ]); -// $this->assertEquals(1, $count); -// Authorization::reset(); -// } -// -// public function testRenameAttribute() -// { -// $this->assertTrue(true); -// } -// -// public function testRenameAttributeExisting() -// { -// $this->assertTrue(true); -// } -// -// public function testUpdateAttributeStructure() -// { -// $this->assertTrue(true); -// } -// -// /** -// * Ensure the collection is removed after use -// * -// * @depends testIndexCaseInsensitivity -// */ -// public function testCleanupAttributeTests() -// { -// $res = static::getDatabase()->deleteCollection('attributes'); -// -// $this->assertEquals(true, $res); -// } -//} + +namespace Utopia\Tests\Adapter; + +use Redis; +use Utopia\Cache\Cache; +use Utopia\Cache\Adapter\Redis as RedisAdapter; +use Utopia\Database\Database; +use Utopia\Database\Document; +use Utopia\Database\Adapter\Mongo\MongoClient; +use Utopia\Database\Adapter\Mongo\MongoClientOptions; +use Utopia\Database\Adapter\Mongo\MongoDBAdapter; +use Utopia\Database\ID; +use Utopia\Database\Permission; +use Utopia\Database\Query; +use Utopia\Database\Role; +use Utopia\Database\Validator\Authorization; + +use Utopia\Tests\Base; + +class MongoDBTest extends Base +{ + static $pool = null; + + /** + * @var Database + */ + static $database = null; + + + // TODO@kodumbeats hacky way to identify adapters for tests + // Remove once all methods are implemented + /** + * Return name of adapter + * + * @return string + */ + static function getAdapterName(): string + { + return "mongodb"; + } + + /** + * Return row limit of adapter + * + * @return int + */ + static function getAdapterRowLimit(): int + { + return 0; + } + + /** + * @return Database + */ + static function getDatabase(): Database + { + if (!is_null(self::$database)) { + return self::$database; + } + + $redis = new Redis(); + $redis->connect('redis', 6379); + $redis->flushAll(); + $cache = new Cache(new RedisAdapter($redis)); + + $options = new MongoClientOptions( + 'utopia_testing', + 'mongo', + 27017, + 'root', + 'example' + ); + + $client = new MongoClient($options, false); + + $database = new Database(new MongoDBAdapter($client), $cache); + $database->setDefaultDatabase('utopiaTests'); + $database->setNamespace('myapp_' . uniqid()); + + + return self::$database = $database; + } + + public function testCreateExistsDelete() + { + $this->assertNotNull(static::getDatabase()->create($this->testDatabase)); + + $this->assertEquals(true, static::getDatabase()->exists($this->testDatabase)); + $this->assertEquals(true, static::getDatabase()->delete($this->testDatabase)); + + // Mongo creates on the fly, so this will never be true, do we want to try to make it pass + // by doing something else? + // $this->assertEquals(false, static::getDatabase()->exists($this->testDatabase)); + // $this->assertEquals(true, static::getDatabase()->create($this->testDatabase)); + // $this->assertEquals(true, static::getDatabase()->setDefaultDatabase($this->testDatabase)); + } + + /** + * @depends testCreateDocument + */ + public function testListDocumentSearch(Document $document) + { + static::getDatabase()->createIndex('documents', 'string', Database::INDEX_FULLTEXT, ['string']); + static::getDatabase()->createDocument('documents', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'string' => '*test+alias@email-provider.com', + 'integer' => 0, + 'bigint' => 8589934592, // 2^33 + 'float' => 5.55, + 'boolean' => true, + 'colors' => ['pink', 'green', 'blue'], + 'empty' => [], + ])); + + $documents = static::getDatabase()->find('documents', [ + Query::search('string', '*test+alias@email-provider.com') + ]); + + $this->assertEquals(1, count($documents)); + + return $document; + } + + /** + * @depends testUpdateDocument + */ + public function testFind(Document $document) + { + static::getDatabase()->createCollection('movies'); + + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'name', Database::VAR_STRING, 128, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'director', Database::VAR_STRING, 128, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, null, true, true)); + + static::getDatabase()->createDocument('movies', new Document([ + '$id' => ID::custom('frozen'), + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Frozen', + 'director' => 'Chris Buck & Jennifer Lee', + 'year' => 2013, + 'price' => 39.50, + 'active' => true, + 'generes' => ['animation', 'kids'], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Frozen II', + 'director' => 'Chris Buck & Jennifer Lee', + 'year' => 2019, + 'price' => 39.50, + 'active' => true, + 'generes' => ['animation', 'kids'], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Captain America: The First Avenger', + 'director' => 'Joe Johnston', + 'year' => 2011, + 'price' => 25.94, + 'active' => true, + 'generes' => ['science fiction', 'action', 'comics'], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Captain Marvel', + 'director' => 'Anna Boden & Ryan Fleck', + 'year' => 2019, + 'price' => 25.99, + 'active' => true, + 'generes' => ['science fiction', 'action', 'comics'], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Work in Progress', + 'director' => 'TBD', + 'year' => 2025, + 'price' => 0.0, + 'active' => false, + 'generes' => [], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::user(ID::custom('x'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Work in Progress 2', + 'director' => 'TBD', + 'year' => 2026, + 'price' => 0.0, + 'active' => false, + 'generes' => [], + ])); + + /** + * Check Basic + */ + $documents = static::getDatabase()->count('movies'); + + $this->assertEquals(5, $documents); + } + + /** + * @depends testCreateExistsDelete + */ + public function testCreateListExistsDeleteCollection() + { + $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors')); + + $this->assertCount(1, static::getDatabase()->listCollections()); + $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); + + // Collection names should not be unique + $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors2')); + $this->assertCount(2, static::getDatabase()->listCollections()); + $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors2')); + $collection = static::getDatabase()->getCollection('actors2'); + $collection->setAttribute('name', 'actors'); // change name to one that exists + + $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->updateDocument($collection->getCollection(), $collection->getId(), $collection)); + $this->assertEquals(true, static::getDatabase()->deleteCollection('actors2')); // Delete collection when finished + $this->assertCount(1, static::getDatabase()->listCollections()); + + $this->assertEquals(false, static::getDatabase()->getCollection('actors')->isEmpty()); + $this->assertEquals(true, static::getDatabase()->deleteCollection('actors')); + $this->assertEquals(true, static::getDatabase()->getCollection('actors')->isEmpty()); + + $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); + } + + /** + * @depends testFind + */ + public function testCount() + { + $count = static::getDatabase()->count('movies'); + $this->assertEquals(5, $count); + + $count = static::getDatabase()->count('movies', [new Query(Query::TYPE_EQUAL, 'year', [2019]),]); + $this->assertEquals(2, $count); + + Authorization::unsetRole('userx'); + $count = static::getDatabase()->count('movies'); + $this->assertEquals(5, $count); + + Authorization::disable(); + $count = static::getDatabase()->count('movies'); + $this->assertEquals(6, $count); + Authorization::reset(); + + Authorization::disable(); + $count = static::getDatabase()->count('movies', [], 3); + $this->assertEquals(3, $count); + Authorization::reset(); + + /** + * Test that OR queries are handled correctly + */ + Authorization::disable(); + $count = static::getDatabase()->count('movies', [ + new Query(Query::TYPE_EQUAL, 'director', ['TBD', 'Joe Johnston']), + new Query(Query::TYPE_EQUAL, 'year', [2025]), + ]); + $this->assertEquals(1, $count); + Authorization::reset(); + } + + public function testRenameAttribute() + { + $this->assertTrue(true); + } + + public function testRenameAttributeExisting() + { + $this->assertTrue(true); + } + + public function testUpdateAttributeStructure() + { + $this->assertTrue(true); + } + + /** + * Ensure the collection is removed after use + * + * @depends testIndexCaseInsensitivity + */ + public function testCleanupAttributeTests() + { + $res = static::getDatabase()->deleteCollection('attributes'); + + $this->assertEquals(true, $res); + } +} diff --git a/tests/Database/Adapter/SQLiteTest.php b/tests/Database/Adapter/SQLiteTest.php index 668900f5a..3d12ef630 100644 --- a/tests/Database/Adapter/SQLiteTest.php +++ b/tests/Database/Adapter/SQLiteTest.php @@ -1,80 +1,80 @@ connect('redis', 6379); -// $redis->flushAll(); -// -// $cache = new Cache(new RedisAdapter($redis)); -// -// $database = new Database(new SQLite($pdo), $cache); -// $database->setDefaultDatabase('utopiaTests'); -// $database->setNamespace('myapp_'.uniqid()); -// -// return self::$database = $database; -// } -//} \ No newline at end of file + +namespace Utopia\Tests\Adapter; + +use PDO; +use Redis; +use Utopia\Cache\Cache; +use Utopia\Database\Database; +use Utopia\Cache\Adapter\Redis as RedisAdapter; +use Utopia\Database\Adapter\SQLite; +use Utopia\Tests\Base; + +class SQLiteTest extends Base +{ + /** + * @var Database + */ + static $database = null; + + // TODO@kodumbeats hacky way to identify adapters for tests + // Remove once all methods are implemented + /** + * Return name of adapter + * + * @return string + */ + static function getAdapterName(): string + { + return "sqlite"; + } + + /** + * Return row limit of adapter + * + * @return int + */ + static function getAdapterRowLimit(): int + { + return SQLite::getRowLimit(); + } + + /** + * + * @return int + */ + static function getUsedIndexes(): int + { + return SQLite::getCountOfDefaultIndexes(); + } + + /** + * @return Database + */ + static function getDatabase(): Database + { + if(!is_null(self::$database)) { + return self::$database; + } + + $sqliteDir = __DIR__."/database.sql"; + + if(file_exists($sqliteDir)) { + unlink($sqliteDir); + } + + $pdo = new PDO("sqlite:".$sqliteDir, null, null, SQLite::getPDOAttributes()); + + $redis = new Redis(); + $redis->connect('redis', 6379); + $redis->flushAll(); + + $cache = new Cache(new RedisAdapter($redis)); + + $database = new Database(new SQLite($pdo), $cache); + $database->setDefaultDatabase('utopiaTests'); + $database->setNamespace('myapp_'.uniqid()); + + return self::$database = $database; + } +} \ No newline at end of file From ffe17f8f08d28c3e011b4335f666301e3adadeef Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 18:57:10 +0300 Subject: [PATCH 05/21] some --- .gitignore | 1 + src/Database/Database.php | 2 +- tests/Database/Adapter/database.sql | Bin 1212416 -> 1212416 bytes 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 86cf51814..95d288b53 100755 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ loader.php /bin/view/results/ .vscode .vscode/* +database.sql ## - Oh Wess! Makefile diff --git a/src/Database/Database.php b/src/Database/Database.php index b34899f68..ffa8dae72 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -1179,7 +1179,7 @@ public function renameIndex(string $collection, string $old, string $new): bool * @param array $orders * * @return bool - * @throws Exception + * @throws Exception|Throwable */ public function createIndex(string $collectionName, string $id, string $type, array $attributes, array $lengths = [], array $orders = []): bool { diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index 332d85f4c24f0120537a417f3a817824b999551c..d3696f04780e20ff056a6ab585e37d3604b87c36 100644 GIT binary patch delta 30189 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 delta 30661 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 Q*RlL>Bn^W92YBq?091%`NB{r; From ae148870b7621155b222627ff75089566b348906 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 19:01:51 +0300 Subject: [PATCH 06/21] remove comment --- src/Database/Adapter/SQLite.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Database/Adapter/SQLite.php b/src/Database/Adapter/SQLite.php index abda42c8c..03d12e8af 100644 --- a/src/Database/Adapter/SQLite.php +++ b/src/Database/Adapter/SQLite.php @@ -257,7 +257,6 @@ public function renameIndex(string $collection, string $old, string $new): bool */ public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths, array $orders): bool { - // $name = $this->filter($collection->getId()); $name = $this->filter($collection); $id = $this->filter($id); From 8485a3cc0977655336114ead71904b77b256a45f Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 19:36:13 +0300 Subject: [PATCH 07/21] check is collection exist --- src/Database/Database.php | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index ffa8dae72..75c72da0e 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -638,9 +638,12 @@ public function deleteCollection(string $id): bool * * @return bool */ - public function createAttribute(string $collection, string $id, string $type, int $size, bool $required, $default = null, bool $signed = true, bool $array = false, string $format = null, array $formatOptions = [], array $filters = []): bool + public function createAttribute(string $collectionName, string $id, string $type, int $size, bool $required, $default = null, bool $signed = true, bool $array = false, string $format = null, array $formatOptions = [], array $filters = []): bool { - $collection = $this->silent(fn() => $this->getCollection($collection)); + $collection = $this->silent(fn() => $this->getCollection($collectionName)); + if($collection->isEmpty()){ + throw new Exception('Collection ' . $collectionName . ' Not found'); + } // attribute IDs are case insensitive $attributes = $collection->getAttribute('attributes', []); @@ -809,10 +812,13 @@ protected function validateDefaultTypes(string $type, mixed $default): void * * @return Document */ - private function updateAttributeMeta(string $collection, string $id, callable $updateCallback): void + private function updateAttributeMeta(string $collectionName, string $id, callable $updateCallback): void { // Load - $collection = $this->silent(fn() => $this->getCollection($collection)); + $collection = $this->silent(fn() => $this->getCollection($collectionName)); + if($collection->isEmpty()){ + throw new Exception('Collection ' . $collectionName . ' Not found'); + } $attributes = $collection->getAttribute('attributes', []); @@ -1067,15 +1073,19 @@ public function deleteAttribute(string $collection, string $id): bool /** * Rename Attribute * - * @param string $collection + * @param string $collectionName * @param string $old Current attribute ID - * @param string $name New attribute ID - * + * @param string $new * @return bool + * @throws DuplicateException + * @throws Throwable */ - public function renameAttribute(string $collection, string $old, string $new): bool + public function renameAttribute(string $collectionName, string $old, string $new): bool { - $collection = $this->silent(fn() => $this->getCollection($collection)); + $collection = $this->silent(fn() => $this->getCollection($collectionName)); + if($collection->isEmpty()){ + throw new Exception('Collection ' . $collectionName . ' Not found'); + } $attributes = $collection->getAttribute('attributes', []); $indexes = $collection->getAttribute('indexes', []); @@ -1128,10 +1138,14 @@ public function renameAttribute(string $collection, string $old, string $new): b * @param string $new * * @return bool + * @throws Exception|Throwable */ - public function renameIndex(string $collection, string $old, string $new): bool + public function renameIndex(string $collectionName, string $old, string $new): bool { - $collection = $this->silent(fn() => $this->getCollection($collection)); + $collection = $this->silent(fn() => $this->getCollection($collectionName)); + if($collection->isEmpty()){ + throw new Exception('Collection ' . $collectionName . ' Not found'); + } $indexes = $collection->getAttribute('indexes', []); From 8eb5a44c3f3f37bfc290f85f68c04ce8615586d8 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 19:40:18 +0300 Subject: [PATCH 08/21] put findAttributeInList in adapter --- src/Database/Adapter.php | 26 ++++++++++++++++++++++++++ src/Database/Adapter/MariaDB.php | 27 --------------------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 3ad69136b..530b0c372 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -490,4 +490,30 @@ public function filter(string $value): string return $value; } + + + /** + * Returns attribute from List of Document $attributes[] + * @param string $attributeKey + * @param array $attributes Document[] + * returns Document + * @return Document|null + * @throws Exception + */ + public function findAttributeInList(string $attributeKey, array $attributes): ?Document + { + $attributeKey = $this->filter($attributeKey); + + /** + * @var Document $attribute + */ + + foreach ($attributes as $attribute){ + if($attributeKey === $this->filter($attribute->getId())){ + return $attribute; + } + } + + return null; + } } diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index df2c3a6f0..69029718e 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -1909,33 +1909,6 @@ public static function getPDOAttributes(): array ]; } - - /** - * Returns attribute from List of Document $attributes[] - * @param string $attributeKey - * @param array $attributes Document[] - * returns Document - * @return Document|null - * @throws Exception - */ - public function findAttributeInList(string $attributeKey, array $attributes): ?Document - { - $attributeKey = $this->filter($attributeKey); - - /** - * @var Document $attribute - */ - - foreach ($attributes as $attribute){ - if($attributeKey === $this->filter($attribute->getId())){ - return $attribute; - } - } - - return null; - } - - /** * Return the maximum index length per attribute type * @param int $size From fda4df694ee430d9cde38aa7bff3bc1ca382e5dd Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 19:44:16 +0300 Subject: [PATCH 09/21] put findAttributeInList in Database.php --- src/Database/Adapter.php | 31 +++---------------------------- src/Database/Database.php | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 530b0c372..f9aff17b0 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -476,9 +476,10 @@ abstract public function getKeywords(): array; /** * Filter Keys - * - * @throws Exception + * + * @param string $value * @return string + * @throws Exception */ public function filter(string $value): string { @@ -490,30 +491,4 @@ public function filter(string $value): string return $value; } - - - /** - * Returns attribute from List of Document $attributes[] - * @param string $attributeKey - * @param array $attributes Document[] - * returns Document - * @return Document|null - * @throws Exception - */ - public function findAttributeInList(string $attributeKey, array $attributes): ?Document - { - $attributeKey = $this->filter($attributeKey); - - /** - * @var Document $attribute - */ - - foreach ($attributes as $attribute){ - if($attributeKey === $this->filter($attribute->getId())){ - return $attribute; - } - } - - return null; - } } diff --git a/src/Database/Database.php b/src/Database/Database.php index 75c72da0e..c17178895 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -1933,4 +1933,30 @@ public static function convertQueries(Document $collection, array $queries): arr } return $queries; } + + + /** + * Returns attribute from List of Document $attributes[] + * @param string $attributeKey + * @param array $attributes Document[] + * returns Document + * @return Document|null + * @throws Exception + */ + public function findAttributeInList(string $attributeKey, array $attributes): ?Document + { + $attributeKey = $this->adapter->filter($attributeKey); + + /** + * @var Document $attribute + */ + + foreach ($attributes as $attribute){ + if($attributeKey === $this->adapter->filter($attribute->getId())){ + return $attribute; + } + } + + return null; + } } From f77cbbd137b5567a0e121cc0e417a1d46e40c26e Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 19:58:06 +0300 Subject: [PATCH 10/21] back --- src/Database/Adapter.php | 29 +++++++++++++++++++++++++++-- src/Database/Database.php | 26 -------------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index f9aff17b0..46e6763d2 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -477,9 +477,8 @@ abstract public function getKeywords(): array; /** * Filter Keys * - * @param string $value - * @return string * @throws Exception + * @return string */ public function filter(string $value): string { @@ -491,4 +490,30 @@ public function filter(string $value): string return $value; } + + + /** + * Returns attribute from List of Document $attributes[] + * @param string $attributeKey + * @param array $attributes Document[] + * returns Document + * @return Document|null + * @throws Exception + */ + public function findAttributeInList(string $attributeKey, array $attributes): ?Document + { + $attributeKey = $this->filter($attributeKey); + + /** + * @var Document $attribute + */ + + foreach ($attributes as $attribute){ + if($attributeKey === $this->filter($attribute->getId())){ + return $attribute; + } + } + + return null; + } } diff --git a/src/Database/Database.php b/src/Database/Database.php index c17178895..75c72da0e 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -1933,30 +1933,4 @@ public static function convertQueries(Document $collection, array $queries): arr } return $queries; } - - - /** - * Returns attribute from List of Document $attributes[] - * @param string $attributeKey - * @param array $attributes Document[] - * returns Document - * @return Document|null - * @throws Exception - */ - public function findAttributeInList(string $attributeKey, array $attributes): ?Document - { - $attributeKey = $this->adapter->filter($attributeKey); - - /** - * @var Document $attribute - */ - - foreach ($attributes as $attribute){ - if($attributeKey === $this->adapter->filter($attribute->getId())){ - return $attribute; - } - } - - return null; - } } From c2a3354b58de42936438dc332dab10f77ec81094 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 23 Oct 2022 20:31:34 +0300 Subject: [PATCH 11/21] changes --- src/Database/Adapter/MariaDB.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 69029718e..5d81eab3a 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -148,9 +148,9 @@ public function createCollection(string $name, array $attributes = [], array $in $database = $this->getDefaultDatabase(); $namespace = $this->getNamespace(); $id = $this->filter($name); - $attributesArray = []; + $schemaAttributes = []; - foreach ($attributes as $key => $attribute) { + foreach ($attributes as $attribute) { $attrId = $this->filter($attribute->getId()); $size = $attribute->getAttribute('size', 0); $type = $attribute->getAttribute('type'); @@ -161,15 +161,16 @@ public function createCollection(string $name, array $attributes = [], array $in $attrType = 'LONGTEXT'; } - $attributesArray[$key] = "`{$attrId}` {$attrType}, "; + $schemaAttributes[] = "`{$attrId}` {$attrType}, "; } + $schemaIndexes = []; foreach ($indexes as $key => $index) { $indexId = $this->filter($index->getId()); $indexType = $index->getAttribute('type'); - $indexAttributes = $index->getAttribute('attributes'); + $indexAttributes = []; - foreach ($indexAttributes as $nested => $attribute) { + foreach ($index->getAttribute('attributes') as $attribute) { $indexAttribute = $this->filter($attribute); $attr = $this->findAttributeInList($indexAttribute, $attributes); @@ -182,10 +183,10 @@ public function createCollection(string $name, array $attributes = [], array $in $indexOrder = ''; } - $indexAttributes[$nested] = "`{$indexAttribute}`{$length} {$indexOrder}"; + $indexAttributes[] = "`{$indexAttribute}`{$length} {$indexOrder}"; } - $indexes[$key] = "{$indexType} `{$indexId}` (" . \implode(", ", $indexAttributes) . " ),"; + $schemaIndexes[] = "{$indexType} `{$indexId}` (" . \implode(", ", $indexAttributes) . " ),"; } try { @@ -196,9 +197,9 @@ public function createCollection(string $name, array $attributes = [], array $in `_createdAt` datetime(3) DEFAULT NULL, `_updatedAt` datetime(3) DEFAULT NULL, `_permissions` MEDIUMTEXT DEFAULT NULL, - " . \implode(' ', $attributesArray) . " + " . \implode(' ', $schemaAttributes) . " PRIMARY KEY (`_id`), - " . \implode(' ', $indexes) . " + " . \implode(' ', $schemaIndexes) . " UNIQUE KEY `_uid` (`_uid`), KEY `_created_at` (`_createdAt`), KEY `_updated_at` (`_updatedAt`) From 6a7e5585d1fc0cae8c8c3eb2817169d0f6810118 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 24 Oct 2022 18:49:47 +0300 Subject: [PATCH 12/21] changing some logic --- src/Database/Adapter.php | 41 +++++++++++++++++------ src/Database/Adapter/MariaDB.php | 49 +++++++++++++++++++--------- src/Database/Database.php | 35 +++++++++++++++----- tests/Database/Adapter/database.sql | Bin 1212416 -> 1212416 bytes tests/Database/Base.php | 6 ++-- 5 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 46e6763d2..4b006f2b8 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -497,23 +497,44 @@ public function filter(string $value): string * @param string $attributeKey * @param array $attributes Document[] * returns Document - * @return Document|null + * @return Document * @throws Exception */ - public function findAttributeInList(string $attributeKey, array $attributes): ?Document + protected function findAttributeInList(string $attributeKey, array $attributes): Document { - $attributeKey = $this->filter($attributeKey); - - /** - * @var Document $attribute - */ - + /** @var Document $attribute */ foreach ($attributes as $attribute){ - if($attributeKey === $this->filter($attribute->getId())){ + if($this->filter($attributeKey) === $this->filter($attribute->getId())){ return $attribute; } } - return null; + throw new \Exception('Attribute ' . $attributeKey . ' not found'); + } +// +// /** +// * This function fixes indexes which has exceed default limits +// * +// * @param Document $index +// * @param Document[] $attributes +// * @return Document +// */ +// abstract public function fixIndex(Document $index, array $attributes): Document; +// + + + /** + * This function fixes indexes which has exceeded max default limits + * with comparing the length of the string length of the collection attribute. + * We can overwrite other index behaviour + * + * @param Document $index + * @param Document[] $attributes + * @return Document + * @throws Exception + */ + public function fixIndex(Document $index, array $attributes): Document { + return $index; } + } diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 5d81eab3a..e62e11399 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -169,13 +169,12 @@ public function createCollection(string $name, array $attributes = [], array $in $indexId = $this->filter($index->getId()); $indexType = $index->getAttribute('type'); $indexAttributes = []; - foreach ($index->getAttribute('attributes') as $attribute) { $indexAttribute = $this->filter($attribute); - $attr = $this->findAttributeInList($indexAttribute, $attributes); + //$attr = $this->findAttributeInList($indexAttribute, $attributes); $size = $index['lengths'][$key] ?? 0; - $size = $this->getDefaultIndexSize($size, $attr); + //$size = $this->getDefaultIndexSize($size, $attr); $length = $size === 0 ? '' : '(' . $size . ')'; $indexOrder = $index->getAttribute('orders')[$key] ?? ''; @@ -390,18 +389,6 @@ public function createIndex(string $collection, string $id, string $type, array }, $attributes); foreach ($attributes as $key => $attribute) { - -// $size = (int)($lengths[$key] ?? 0); -// foreach ($collectionAttributes as $ca){ -// if($attribute === $ca['key']){ -// if($ca['type'] == Database::VAR_STRING){ -// if($ca['size'] > 700){ -// $size = $size === 0 || $size > 700 ? 700 : $size; -// } -// } -// } -// } - $length = $lengths[$key] ?? ''; $length = (empty($length)) ? '' : '(' . (int)$length . ')'; $order = $orders[$key] ?? ''; @@ -1930,4 +1917,36 @@ public function getDefaultIndexSize(int $size, Document $attribute): int } + /** + * This function fixes indexes which has exceeded max default limits + * with comparing the length of the string length of the collection attribute + * + * @param Document $index + * @param Document[] $attributes + * @return Document + * @throws Exception + */ + public function fixIndex(Document $index, array $attributes): Document { + foreach ($index->getAttribute('attributes') as $key => $indexAttribute) { + + //Internal attributes do not have a real attribute + if(in_array($indexAttribute, ['$id', '$createdAt', '$updatedAt'])){ + continue; + } + + $attribute = $this->findAttributeInList($indexAttribute, $attributes); + + $size = $index['lengths'][$key] ?? 0; + $max = 768; // 3072 divided by utf8mb4 + if($attribute['type'] === Database::VAR_STRING){ + if($attribute['size'] > $max){ + $index['lengths'][$key] = $size === 0 || $size > $max ? $max : $size; + } + } + } + + return $index; + } + + } diff --git a/src/Database/Database.php b/src/Database/Database.php index 75c72da0e..6249339a3 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -508,6 +508,8 @@ public function delete(string $name): bool * @param Document[] $indexes (optional) * * @return Document + * @throws DuplicateException + * @throws Exception|Throwable */ public function createCollection(string $id, array $attributes = [], array $indexes = []): Document { @@ -516,6 +518,10 @@ public function createCollection(string $id, array $attributes = [], array $inde throw new Duplicate('Collection ' . $id . ' Exists!'); } + foreach ($indexes as $key => $index){ + $indexes[$key] = $this->adapter->fixIndex($index, $attributes); + } + $this->adapter->createCollection($id, $attributes, $indexes); if ($id === self::METADATA) { @@ -1185,7 +1191,7 @@ public function renameIndex(string $collectionName, string $old, string $new): b /** * Create Index * - * @param string $collection + * @param string $collectionName * @param string $id * @param string $type * @param array $attributes @@ -1193,7 +1199,9 @@ public function renameIndex(string $collectionName, string $old, string $new): b * @param array $orders * * @return bool - * @throws Exception|Throwable + * @throws DuplicateException + * @throws LimitException + * @throws Throwable */ public function createIndex(string $collectionName, string $id, string $type, array $attributes, array $lengths = [], array $orders = []): bool { @@ -1242,23 +1250,34 @@ public function createIndex(string $collectionName, string $id, string $type, ar throw new Exception('Unknown index type: ' . $type); } - $index = $this->adapter->createIndex($collection->getId(), $id, $type, $attributes, $lengths, $orders); - - $collection->setAttribute('indexes', new Document([ + $index = new Document([ '$id' => ID::custom($id), 'key' => $id, 'type' => $type, 'attributes' => $attributes, 'lengths' => $lengths, 'orders' => $orders, - ]), Document::SET_TYPE_APPEND); + ]); + + $index = $this->adapter->fixIndex($index, $collection->getAttribute('attributes', [])); + + $result = $this->adapter->createIndex( + $collection->getId(), + $id, + $type, + $attributes, + $index->getAttribute('lengths'), + $orders + ); + + $collection->setAttribute('indexes', $index, Document::SET_TYPE_APPEND); if ($collection->getId() !== self::METADATA) { $this->silent(fn() => $this->updateDocument(self::METADATA, $collection->getId(), $collection)); } - $this->trigger(self::EVENT_INDEX_CREATE, $index); - return $index; + $this->trigger(self::EVENT_INDEX_CREATE, $result); + return $result; } /** diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index d3696f04780e20ff056a6ab585e37d3604b87c36..f01fffcd7ad31be87203838be9376edc1ee011b5 100644 GIT binary patch delta 31650 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, static::getDatabase()->createIndex('indexes', 'index4', Database::INDEX_UNIQUE, ['string'], [128], [Database::ORDER_ASC])); $this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'index5', Database::INDEX_UNIQUE, ['$id', 'string'], [128], [Database::ORDER_ASC])); $this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'order', Database::INDEX_UNIQUE, ['order'], [128], [Database::ORDER_ASC])); - //$this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'long_varchar', Database::INDEX_UNIQUE, ['long_varchar'], [], [Database::ORDER_ASC])); + $this->assertEquals(true, static::getDatabase()->createIndex('indexes', 'long_varchar', Database::INDEX_KEY, ['long_varchar'], [], [Database::ORDER_ASC])); $collection = static::getDatabase()->getCollection('indexes'); - $this->assertCount(6, $collection->getAttribute('indexes')); + $this->assertCount(7, $collection->getAttribute('indexes')); // Delete Indexes $this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'index1')); @@ -305,7 +305,7 @@ public function testCreateDeleteIndex() $this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'index4')); $this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'index5')); $this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'order')); - //$this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'long_varchar')); + $this->assertEquals(true, static::getDatabase()->deleteIndex('indexes', 'long_varchar')); $collection = static::getDatabase()->getCollection('indexes'); $this->assertCount(0, $collection->getAttribute('indexes')); From a3ad9cab2e8207b438fdf7582c9b0675270ab481 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 24 Oct 2022 18:56:57 +0300 Subject: [PATCH 13/21] remove comments --- src/Database/Adapter.php | 11 ----------- tests/Database/Base.php | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 4b006f2b8..378f78afb 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -511,17 +511,6 @@ protected function findAttributeInList(string $attributeKey, array $attributes): throw new \Exception('Attribute ' . $attributeKey . ' not found'); } -// -// /** -// * This function fixes indexes which has exceed default limits -// * -// * @param Document $index -// * @param Document[] $attributes -// * @return Document -// */ -// abstract public function fixIndex(Document $index, array $attributes): Document; -// - /** * This function fixes indexes which has exceeded max default limits diff --git a/tests/Database/Base.php b/tests/Database/Base.php index e1bfc6768..bc508466e 100644 --- a/tests/Database/Base.php +++ b/tests/Database/Base.php @@ -310,7 +310,7 @@ public function testCreateDeleteIndex() $collection = static::getDatabase()->getCollection('indexes'); $this->assertCount(0, $collection->getAttribute('indexes')); - static::getDatabase()->deleteCollection('indexes'); + //static::getDatabase()->deleteCollection('indexes'); } public function testCreateCollectionWithSchema() From 577751d03d10b419c304b25f25db90e87cfa9520 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 24 Oct 2022 18:59:04 +0300 Subject: [PATCH 14/21] remove comments --- src/Database/Adapter/MariaDB.php | 5 +---- tests/Database/Adapter/database.sql | Bin 1212416 -> 1245184 bytes 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index e62e11399..083cddb43 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -171,13 +171,10 @@ public function createCollection(string $name, array $attributes = [], array $in $indexAttributes = []; foreach ($index->getAttribute('attributes') as $attribute) { $indexAttribute = $this->filter($attribute); - //$attr = $this->findAttributeInList($indexAttribute, $attributes); - $size = $index['lengths'][$key] ?? 0; - //$size = $this->getDefaultIndexSize($size, $attr); $length = $size === 0 ? '' : '(' . $size . ')'; - $indexOrder = $index->getAttribute('orders')[$key] ?? ''; + if ($indexType === Database::INDEX_FULLTEXT) { $indexOrder = ''; } diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index f01fffcd7ad31be87203838be9376edc1ee011b5..0acf35ea562e017423cd400fc7ed499a5eae51e2 100644 GIT binary patch delta 39133 zcmeHw33OCNx_{U0_4anV$)1p;)7e>)UeZZ7pb!uNSptG60w$fL1IWH<(9zH!?y`td zip~g*I&a1eWaN%B|!SYvJecV)*&dMeuXeO!!&R z4nIrA!Ox@^`~-oap{f>s^2*@H>sHcPrFY>MS)^~IFQgOF-=vSF52bfy?-BHSsqzGr};vj=`cyU$iO86S2&d?*;$=(M{ZGIY2fg5PPo_m7%9&X0^! zgq54(Yu0qOh9j-rk?y`wyfxC&*|{>YA>JF`5I6k1ZkTZn;?V34jINxXO98}*4a-(0 zDkbA29(iZqiq%&p)~z?!dW;=Bg57&ZSBP1>-Or9LAC>*;>|Ncnab;rFhV|Aehj9uw zxxJ~BN>p>kAqOqNqx^v~~E0!hJTWjpbnY{SjcQuX6q2sD5R9NDy zvl{1$Jk2rR&(o@no?ysdArG9CtbO{vl^X@#wAPg>Jxv*||`@DJWlcpMe zzB_OHG01oG{quebE$Ex zs4BwNF)eLPp-`J*4-LcIHiPsR>0hNsrCrhj=^Uv_GP^%$eNC|gqp%F5j|@OHig1%y4KRx*21?Iu(CiP{J+Cm!r>OKwUD|J z3byK4ODoieppLafnj*oFj4NSEQdxd!?bYg z++Vuib3fz0-@Vn{>z?HvMC;y&X1ihIS)GTa$e)? zc203NIrAJ}Io@^r*70Mu2I@EDk6VdpV?55R}L<-mkKW2mLT*gS4u^ctx&@2vkVUXY}tqA z1qJy^XjwKi?TriaNN|>EIyi5b!m=#QGDGVnv{{C!;N5qxUJga@cY|w(tIf6Eb&>rk z`zHH?_8rhwxJNoFJ!!X!&x$9+KZy^B9pX*m3aP<;O!B(FavyOg+&^?*=la6+sOy;P z_x5gkrG2KoRk}`UmsU%cI5s*O9g7{4+#PPoJ=R_87-m0e|JMGI*lPQ`SSeau!<{d? zjLyG0pKuoRIPZ2|>zwNN+S%;Pcf9A=;rN~7Cr|_}ydo$zmzU&aTd1r?guk*8S)B+U z7n;ipaw*bU5k6w+vw9K!GTdBWl7}+=lFq(EPi^|pd}*P%3_{b&%(BgAg0oEX^37!h zS?V;)VGM1Sp?CK^1Ivt4T~F_}Zr&n&?K7YoT zIB-f*zSA_}Ctj@$=DHoY%a2O%tP_HR3R{SfhNMG8UW(*-gtm;%b;?p%SNadB{tBln zgs&9Ph#Z3a69ENL9tQ$@PYOjjLhLr78tQYb3Dr}d%T1`2`b1__gui)Hv=?xYH#qUZ zk*Js@r@?||25gNPl~crf%xEO_`GOf$Q=ea$(Rk|fvp2;8>T{8W&V+oE1uaKZ^tV<9 ztI>uU+1L`irU7}Vu-j~i?uG(DvAP()v!MW$f{>_+ahZscRNq?F>*SSUp`8{@o@z${ zIwMI3@=-j0;$ZRxv4!}WlLDO)vlB%qGsud7kH0AvQcx?L4AfmtR7b@=2PjRsBG009 zc9QxXqVF7>~P#^ciB$b>W!~k7aKjoEW;7=?^8{W!61y>9Sq!V-0CR9uQnn&v&S1zX=yGy z*)dP5c2(@DLdCa$$%+LOX?Dzj)5ssJyc zLLEN}`SP_wtRJqfWI$Mmzj?*(;mHucL(040x_L#`qA63*jrAMi-76BD!paT%28}G$ z)6D)mrD+I%uO3~Bk2IqRCMbf1p!|#Rx#0h(tb#kFoy~22#zc<5C#A5g*Tb*9U@tW$ zrxfGuc1H7PG#bv+Q5g=7M%2g3V_^Ydw^baRU1B|+a6%|4Rx@0mveIIbN3SLpw~MG! zQUznrX(2w%oNq1a=s?$P(lvurmeL$_6_LPYBRF}M164>u4Q+YWqJ@)Ca`6z^!=8Jk zBCX;cABjpixl-zkmiU9)rToUWVgDS%^~C3CLDr7qay3-RQ~kwUTe`@$l}H! zvbcT_|CsWe3EVsyRcVTAmsKd$3JTU*J}Km}7EPLjZdg84Ar4Y}Cq^SJyqvAX#pc!P zdK2sL!QGxbytx^<@K5WJzjBnXYsKnSOFFNJuj^SFU)SZE-+tkwsqGgwgaR$m#>R)b zj6V41d1$jSu*V~qWRnNY6aA^aQJ^UpfKKp2?0X#L;}q=+J0)8PPmKw79)n7P;(L8<9T&?Kb*6CFY4 z#z;rd!pUdHqh*pZlS0PEP}o+^j0lN?LbPz=GUZ~{jcW;+^x{CHMu;m`&y*3+P&o4c zhImCf;>q82qSswe-&uRc@2^Dp1L{zpUm2@L(nF+d=~4B-U!@FOBiZp1m&QkEvcs}0 z4P^!XN}w6Yi)06BJR)BOR~#CqTt^&=rgk{cltfbEY+RpMHzt^7=3;6SKD!DPEmBlM zTV-`A$WTI5!lY%0YD)-vAB709QkfenuY>%SWb;CoJ#8|>^~q8arHZ|*1~kJ*!xIKj0r8VG z587r*Sb6E9%W9@rp9UWoK=~oXfa#QJT@>o4lfM{1c2CGshCD(5J2@pwQqpUBX2KA6i2~CsR1bSWu zB1-U!cX+&2t<{9**2W=uin!y1V5bH_glD}vyBVJJaEY)hJ1xu?%Kdo1kI|+=pT{XB zl2=rx6jF|-4Ad2<>f$PE(ek+{d5x~nd#llKTz;=)=N8nejVo5HuU2ad(u~Tn!bhu7 zjn6j}qr4haM-6SVgX2zx2i_+L)EXn+P^0Ehh@YuJZd8e1sbRD-rxq30aI}&e;1UMw zYt-t8gbi#aitydFU>p_r0Q`@Rs@0i1AlmV(6kk(^o2y-bb_DN)LvS0e5|hid)p7emiLfv+gq8M6oF!fs`;} zXYuN6__C!!p_Y&Dm?xhTdK?v8tj4G|^E(R+d!LEZmNOLi*5f<@1$^!@p-`J;#BKQ* z#KWJVNp7XNWkRX;E!6L8cl46YAr+kBA1ZR;p5+- z;st7vv#r0CX=oWSlopS)#vzM75$-yR3NBT{ryEO?zF1Uy9qKpg)8V6MQE`bHKb0CZ zba*E+d0-SP95usWthY7Xmx%PXw06g$ksehwA_JRHYmgs|_umSGvDM|mM_4QpW++uP zmWYKC-ND{icR0)$xVFK%F=u2)g7NMm;TwX{8&5=|K-bsS)2rePwYLpc^VLJ{OfaeL z_~{a1BmwH_=}UC?#$xe!Yd05&FJm-JhT|vjW5c0ktt=C|2wHbvv^5rNZEKCiIfL&u z*tx**LL@jP7ND(FM!&J{P^>o;k9D_nYcxwT(iT=LJRM9FE`!3`QEFKSl+haHDzr5! z!%!J}pyIJ5Y^8>}Oleu@2)YR9;WP~Xb1J2W(=l2*)NtC(W>-GdEL@TsPlIXk#?vIb zU@1D|X<`97<7tQs$8^Tiq%4&2bPH#|3X$QUz}?c2((>VeF!O(0^6-B{a`|khu+s$1 z2x|!VzFwgic5Jbs{@J`njHRjTz>j^33ZWTOh0h|*7_<^>xPKeM6Js3jp5~Q=c$#Ysh+?pus_`?VSwt!XVk+ct~)oQ9yZ*6 z4o^KS4L-6YtsdHy)Qu(TQMxoSIvjhJ3i(R6hzYHW5rt@}7cC{0%ToK>`0AkfRJY=I zLda8^c7{_m?8oHIv@k@z7OkDJFm+*~NUgx*mhl7*^3_NSTo=IYeW{)y<9hLd3?l82 z{Y?Z>-2-J(){V|t8J)InRHpLwF!cVBe6`YP@tVs?smDV3(EtIt^{ z6JD3IPCDFQ%U3H+gJ&;KTPNLY)m7)LlMcuGmZzGSnd@$LlnL%aX>&kMfq*K;wNR^}G9Gp;OVan3^Njt!o$ zGHvs8s2?U10a0V2G)-LrrC6$~RF|K#P@3LPHa}^mbD3_|o>gfBr4v@ePAI-sDXu;b zSF037okVGs4tM7alxFL9>1dToE5E-=xZkYlyfLGu3+WL6+c;5l!Tve)sEJ1hV}jXS ztkGmlz>JzYxP*ibH*FM@Q4`A|+v?Ax2ShAQZqzhGp9tT#QBX!r+N2==1^Qw!qo!&4 zbl81`P^{5-cGNV5PRX`)l(s|t=l@f5!T!l~sbujQ$-pUFJ^>o%_b!&sj>?8 zPvo+o=sK*q_(FOa* zvUyMAHIgx9R=s2N!Ei@^T3lKbM!iuk3&J65^lhwqX{@YzL#=v5(|UTdRKW z=@a1z*QRR_4WF(-9)01cQV8`+`gHj5YlUJmI-~LBx2_dNActe0K``HGFyCqKgEhsQ z%((d$bCt4lhs;L785-3LVrp(Q*h)6s$WPs3o?^nMZZcP=laMnxsw99EZGyuWsXaQ$ zo6V2GjzUuxuv=u>(`AIMMH7TGQk_d0VQ`opHAoZ9J*G!p4?1@`o)b@rBW=s9KeCh< zZ-wY<4OhVVySbuGSq+s&nC}4$yU`?#KvnQpIWi{04ft_0v#anGvrz8NZJ<-uH}RY^ zLK(FNRBjQf)k~mQ*^DNH>j@kvFLS~#wQ5TCo>BYSQlTTs8V`pU_MTDf&RT>L*vA?m z`&eOWGy|RJU6Pm-U!NFc!=8$yO|?Ar@oAw1!QLg+=2PDpf!=(Y1!+~UNdaMM%P~w! zsHI9NWPFnvd;)CZB%8>ot(#d65j6*(rgtK*whI+#w0a}xqjrJb2%1G}AGtqTd>S~bA6HkdsJbwDLK<|hoX_URCZlvrhF5cCiKO;G|&RR65eXuRNX;%6h z)YBRmpu-(vDRR;H{2Qzb2vwvVBe+|UkO$Y z5#`|{Hwlvzf#SV=eciCFW-0loREz+mT>JmR5YvEke~8B~$T4EZhqFabt-P zSD>~aXDKdlL2tdek5(8^mNjW)I7S1W{krNpc8Tek`$ zh=yXJcs$Y)4D@zuHX)O)Mr(kxkO)|Tl!i9kCPYZaqLDt>aNOF`8wOKk4{Q^h2pm1u z24i12Y$pPVYH;~>p^-?`77axLF$F2C?k^D}0OBAuwd4%C8b7sNs3Bmjv6k+hU@!op z@xgfOq|v69a4LJVcL+g(6Y1^=DchVA;V@^nG4#lyTs4KG1V=u(LwJ>JU;r)Ws;i4y zE@kSUlZs&KlY@?+D~O$mpsZfZMGW-BX*;&%VpzMRmv$^R1x|D<>V?<0ZF~w=MAKoWC=uRI(5K_i^yIN)y*%*NX#B zAwt{$XYrKObDLg5sL?v>(@=|a*Qb>l7UZl?FII*U(I%)(It$cbyRne6K+P4jMR$Fg znDGBsF9 zRi36uZ5#hE+`Vbb~P$c_NXyVR%drSL&M!2&rqay$7{-h z?oIfWWBr^X2~3y62kTrKlVT|RaNeI+7IdG(Pmcd<6&4Q+_0hp=E7$HsKck)@$ZI$1_XGPQaV1K4oe>sYQK#yPKv!WY6zm3m| zrtw*MtY`|qMZ?LftiLkNDV}{ab!dYLtdp$Ed$htlE^Pf}uudSysdJX|k-mDpnLuI#V7NMe%S0nZa9@m82!g z&}3P;Syr^GOtW&aC^;7w=*e<&0?k0~uoctu&$4o`tZ1M#D?7`Ic5zu&q8^P94q$XF zZH#o%G`N*bNRKqK;1+$FY&OhnHfS8e3F?c9g`r&>J_sTzTi=-xO%`16DF@QHqaOL| zV}i}|Br?MN3gckMwehTk&XG+%<^Si(rhxHGr*fjWSTw(3a36Eqoh6R3_Jp{@`nlz4 z^Bd-uU?%R6xt`4NC;MX7qScGh7MI@4Ck~zv%JF@BJ@lO{5LSRDtLL5xZ=85`x%?;HOpq3L-4 zr^eB8@H6A<5}JYce`gFl*p_zD&)fAFjJ*Jl>Gz%a6))l>cCYkrl>qF zV0unMv+@3OP2=PV6HLF6&>ZYNXgpV*INS8Bgf7HYy{2|~a+m2>5}J$muQE-Rr>!yl zTtf5k{%cKB_$*fkR-NJbsN{ z73`$&c*{ssbdRb&mb_v9$bovP%PKs@E_b)Vj3y(g)%l9!LHqM)G6Y;@ShqVESe#lp zhVK{Q>$&RJH?%9l3CRZ*>Inx2H7$kIl3Grfpka$jnooTeuUNe`dFcde(Xxxtmeh4= zoGjt9BP^w)(HhPz#FW2Sr7lX6O4WcRM_CH+%Ofnq(0Kg*2n%f_Kwdi-{z|pmfCOdg z#*5(hH$qjjp0QGAP;tX3%kaU_m#dTmKxIfU`~ejID%}2aj@qOTHd~7Enr4fgZ-ket zl>zirb1Z+@Y^n00HTcf)?%;Sx>8=-Ww~7v*R9{6T%{Y|fY)AT-6U^Y zW4TsB>+uH{S!(6R&6aTl6_MOI~-`k=mSf?yzPAj{wf^ovW%A}eP%f#p{ud?GRu`u zUTwWmLf^yQ9t-$Kj}`pmH8{S&0zSlN1s`%PK6r^`gxnOczA2#roLpwK`bRVsg?8WIFzzu!}ryOMv|#+S9|Cm))lzv4Y6qAAW)pTM0t-4zk5}tck4-O z8S+iH7WF_?*I%)(`oda_kDapGxz#;nxJPY*kf5QKD{Ysr!PnK9>MZxRZ|K6$yeZN< zPX4B_Qf}VUVYOGy3KCG(j?2Ha`tbHYGG(#&OKXJ=+}-K|`1zMs`sS{WzqB?&55W7C zmG&P2_|yT!Dh*%zm307_?n*A4g3)OP#CO_S%QcQ*+Bj}eXBASEsW0$Lp0O6-mrh%U zq4V)E4TC{UFvI0$wFZDoDOQ;v;X-_!_ay7<&RB;Jnu!}#`T(R-gdaM^p#1V%tDmdS zpy39!5`eZ?efi({-&rg1TCg0dKYi>wp!>mhIyM_LT(1U(1hgS}&I0DRFB#0)XLSrI zXxOG!BhcpKBWJBt??V35S?dTNx(%QBwJnHeEE3D)**@DL32n#T12*W?1#Hl%+ksEq zVh2w>!3LgsCq6jCwpQLa+qPXoyKwtx8+0+dY|zEL9k(~ypzF2923@b+cvpk1MsC<_ zdq+Zd;HptJ#a-LLUEhhO@mDT%>)}^z#?5FS_AVA% z@W`oB34SIncH`qe6ie`qCGeN@J6j1}y&V3!ZyLltK39z6&IiHgk-r9hZ%hAmI{jBS z-Z5P&l_7SX6Ya-qe`6aZ2fD;RNa%if@p}97cKM~N#5ObfAwGDI2wla^qBXPGj$EzH zlNWB>PPy^F?-#3_=rJrkCe~-WmQntlQBms7DEYp}#4d#HJA6P~=Z6los)mk!5Avf7 zpt%+vPFK@M)rLfpsX8N#e-P{Oy4M-E1iqf{05abC2Wn(Up>Y7#H^h1v6*RxWTyr_= z4Uu0jGg3dSs+a%rh6pXeoS|BRKffvRYiii=VdyeDH-pDdchpiQbl0!#^gXLp6CL^1K$ov^dw4#6@7H$aZi>uCO~RMJb8so< zhC?bNnD!g{3l`rZYtfR6gh4KoalL3SQIA=2JkxIC=jw7HsT4Os?QA5e@QKfaN}+lo z{`3Vq-Rpn^HPpC5!{I5lkwJn|GHTIq_~3-lTQ6N|ExPC;;kp66`jS!&Uh}z7Fc{yT zskC;>OZHOaTL4p8Q0U8um>j+1@>lFdxZ)%;qnDh>lrfOd^H(!pu~+&o84CB-SL{{P zNGYc#!;|VF_z%FRHs|I@@oP?$S3l!oYte#fg8pbVt)N+Fg(5!3pQ?-Gv7>hCwrBa@ zj@qx8ptM+RV^Xh6sG7OdMS=lxBex9u8OKZL+rzLi+y^_u9oHZj$jv$Fq-|t>yMwuF z`lOStGZ34HZ4(_-p9Dk2Df4v>QA6>fi4NL-Z@Yjgr^hEcRCTccAD`$j<0qy&im3aP za|%vrj(eZ-<1-lSC6mue9(&Fo?@1Gqteu0==C7t2*b0F3`wZA5@ylWTbDX zx?eh-;ri%#j3!o2*VNDHF#?kcKGHQj^TVm z`Mp|Q?`pYBZzGxN8G?%@Q?0yAy>~v7sXJ$CGu2Aibq~P~pPtDS&fQZO;F+^Dz|%=3 zjl_ol*5rd*XQgQjJ9CGIU7b>8laa0=*x}1Nn0&mz0za(zCGXmZbT2X3;d$xJxKSml^JdN!FE?WK`+UJ7zX;#<$N4|6FxRj4nma^xpQ|(IegtJa7p1;UV&qgdc>!iI&?Ls%*F8@M{g2MRf zFPJn_PwNTw8qejjb!>Q&kDX7(W+Kb%&WGFO_h!Ll6UW!XEI zffr9|;BDcMQjw$IQwzH0q@G#6t2WEu@?cYaxvSN%BTq4!yzMO0J`SAH2#B9K1^K^f zsQiawy!?Ok4Ff;s3pIR!m9%NmO=>y!vz0XQIRgZ-(Bb~l$#l5Cbe6#yiK@G?=u0NQ zKRLnR9QaZzP^zk2sRk1~Uu%&gc=}1E zr~1LyppSiDJLzj;-(hipMCDNntf@M(VaT!#^U8M4DMrqlzt!M_uYL9uBj<^486_^6 z$ux5in};v?jw#i(-#JUti>=Cx%25A2duF>Wrsoa9^VmMyU5yNK(`@&f2%9c+KPMzD z>O%dm3*B_{@#q4kx{jagR;er>56pGj;0+^{mHlY0Tc=_BT3uPc(SnMRw5Km5xPy#z zB14UIzEZQ3=V|gFM$)Z8fjS$N7wKi=OEvELi#WKXZxv1Et8w4a#r;B!+dN-`i&xJF zo#&}R@q9gDPpLuwOA9JSQpTSgHl)sZ)=zcg3@6p>esr-W4`L)W97=lC*^n;L%f>&{ zxILF>aD_++C&Bor5!H*jfS;=YD;H=0apwZJ4NscqW`^zy7!EJ9t=crKnZZdbS)SYrNdt=)GL$| zY8^_8G=R8c5$G^{F{8sP7cm^3W^?$W7Da4HS10?BI^?z^n=WQDe#2sooMKC=yOk8x zIy??tT1p*}OBkq0muaAcmKNAlz$AM3GUoFHi*Z(qfyZ}(+Nv*Q)V8FPLHR({!SB>a zB7XxY2hdsA1}dGAkUh04^qU`<0+Q!PrdMrnBkyeKO!MKL(s%*Y;R&}(^gLhZ?NT{) z6+!AbVx)PP?(y3tx@CChc4@e;7$!B_h2$nOL&R$^i*_^EsRQPQ)9R_rRl6DNy}PAa zRI8Tr7>kvb)1fxb<~tayg?C89YipE~@4_IDRViS&>TZv6QDkPSKh3~Sgq2j`xT_YG zXabcZ@8@q_oP>+++uMcfC+W_Hr?5F1>r8VMm5Ffb#sDQ)-t`0N0)+o_kJL2H4>_77 zBxmYr9qF(`f6icNu;0k<&+4O&o8E;gO5eL~w zaRqbQWaNZ#LB}j#7e_C6(Opsr++FXv!$aHdXLm_Oc;8-+o!VTQK_oZABeU8*APKz? z;JaI@feY)8X>be4mK$AMliG#>w@|&;0l@Qd#c5%#(UL63U3-~&H?UVyZqm+}8!NU^ zwGi?e5F>bJV8UHY{>6Kx3hMc{GzLQIOfS4ws-div(Bb!QmkNy0WElaaF8oNNsGmC& z?~?pHDp-!yKzH3C75FD4OO-dj1pPO^aPs>S{oY@iv*8R;E_IDYDuPrx%1595zEn54 zM0wjwxIU&^*V3RIqsmyN;X74rQ+dVUo{O|Wk4FQkExWwSP#8GB#HcvF&Z(IVK zwW^H;Xk~UW7j+v9FehX{m+opWnS#b|X-kfA7|NBaC(5^6?9Dvkt6G!EJXx*^&b&=c z?scfkq+NKmzh+r4+%}PVH$8iQMCubKZ#7?UT)c2GzW)uWF0~Gndh%Qa4(mY5OXy@B z2*3QMWW%vHrIE^h4iW?Jpz{*IgV#hF8B%N|H-rNMd!jF^x~2 zOV_3#?_#I$AACo86J@F40d*~Ppb1{ePEr5)UFp^!+{Dn^7D|MbyCvHCS_0~W_(alR zRDI7tCOCz3Qu3UUz~WdW>Z#gb6F{iH4^Qx1ue|rerb?fY%O2xMojhb|d~iliePWQM z@N*wPU}==6k4&<8wx?f$MQS!KdyIuSf5Ot>gPk7bZ5=i=eMCm^D^Dh+PoJ<9@|T^S z4@RY}EYuX#T$cgLRf3gU4$^O`wcqAZ?#$?o27*0(aHvgrkBUM9)ZPbp0!H;2fGix9pIF?lA!PGPwRrY0cq=lT7o?NI8fm(%C3f>0|jG547)1 zq$#GleF`de-z$|+jeJI>1w<2S;;wro`YI+uoN4JttGf>e?*ct3J7hWV`D#T2F}+Rd zy}LZ+KDhsD@CLr@ZV%nSXJpS)>v+xG9{TOq6dk!j%9N~6j=)FmW(@n--5&b6;dH0j zqZWC@UQY#O&2#p8O6uUkt`+ei!0}pmPKkPKDa9dOcoN}5b$UoFR<0JKibDy+ zN8n~L9Jg_~JYHojQJKmo_jtaC>KjNl2Dz*(C9(QFTqYlG zbvG-WM)e#n3B}&iLf0H)vR=8bOc><8GMWRg9?Nv>TWI{0zoA$`k&MjYCJu<|_Ce5I>Fhx*`V1&ux!3cs0LeV`G5 zMv-qm=7}q}KCx=b%EO%IW@)meCDF%@S(bC{c@NsGfA=2j>Mas`sr7IT`LRee?*8!Ha2*sM5KMmtOarNyySmoT}aVdUg- z&)LfC5UQ2emkc+x(tXKKB(Kwv8A3tF@UX{wsxlW4i%zIt=Ec zX35myUhkUcOxk7f9noqFTQC}9xXSc^VJ%$7I?FBsslj0GHI0Cw=W9k&a$GV(I+46i zocCU-kQcsdskf9Dt~?apkn751`k3nTHLzwoF8RNy>snL2wK#bWymY=$*k;ykcR%R! zLT9nhOD`lsSOKbK8z-y~%A=Ne?Z`I{_VIQMHnA~(skeseK4etd*%x270%m96a$2fi z^3$c>5!C0$OTE>;u|shfvCLaT^S8k{1?l-)o2Vpw#-XUsdZlNEv)7> z+$;ybx(5g8=u2m}U+x_>2ksT<=n%GT($jq>gE=(QDz-%AQOmuTAmvhlo;iaR23qNb z)44E9SgJMhbeB%^awMc_;MJAy{HUaQOIZ?b833kR^{-3-fFd%5sL!-QtwWMVbzaK3 z%6s|rR+xdEBV2d&(269po`Y!;AMf+}a@HpQ=PGYu@(z#1beTcA?2vcoJZVO<64?x4 zW$tR^x&*u|eMO>odScUgt9v%COsv|V8gG-ys;K7i`Ajew^_ED-s)&%YHa=RFO-M!rAtPLsCiRbHeH7g+ow9 zrgOsCwk|_bOR3i79BB|uw;S9qyFN1A?&z`qQ2euPKAaQn1+U+4x?t<9B%FFyh7tNV zE@!3-c{Y%VLk&trqRcxJ@#Icn8fs4!QkQRj`-PLHwqMu~3`H9olO4(Php1?s85q0^ zMp~5JXTsB!Ep;_Bhdqurph{l2QtL)Rt(!bVt;HW3*0D$U)`$X5+ZzBy~HVVS$x)o*FS`!qG@FKIP>?)zW8Da9jF` zx_pnnDRTLa(B-R~+2YBgoQ*J^mux2!SJ9kz&Is0-TEF7$bIukuYSb-EWj2e)R=G3* zF2+W`fNCY9>SRxHytQcMLSc)jx5Pyne|%q$H!tTpm9PR-uby-u{RyBH)#qzT#P~k1 z1>38Ut9naw@?64oYt@ikZKNepv#wLO9~ss*^+HsJ^(A-M6c>16dj1dFqD>$G delta 35604 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 Date: Mon, 24 Oct 2022 19:00:36 +0300 Subject: [PATCH 15/21] update hints --- src/Database/Adapter.php | 4 ++-- tests/Database/Adapter/database.sql | Bin 1245184 -> 1245184 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 378f78afb..d7c27547b 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -476,9 +476,9 @@ abstract public function getKeywords(): array; /** * Filter Keys - * - * @throws Exception + * @param string $value * @return string + * @throws Exception */ public function filter(string $value): string { diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index 0acf35ea562e017423cd400fc7ed499a5eae51e2..9c699b4a8ce8422b991f5f68f497bb91791ddbf6 100644 GIT binary patch delta 1041 zcmZ{hUr19?7{Kqj_ip#@Zug#hFQw^Br_-r9=bVK?4YzDbWa>&#h_b9G5o;KPzQ~4# zCMb^kaC+#$6b$kqWz;1!g6N^Zpn6ctf=02Yo-!h$pwHIaDmsVXf%ARmcfRu{9BvAS zn#G1U`iCV=o@X{rCdzz#TDVep$lmrj~9RSO0@iq>>otLlO(|ol$=d@!p}cVtbpP zqGYP|pVUc69WXU(+^K6k|0dbt>@~c$+|P@H>HVobxWdI)bN4+X2rU{H>el*0Hr{+Y z*+JUjEZzyK^@0E_?!@PG*r05f0# zL_pHxqFlQW_`#OZ54E3Uj2q|v0)?&CgWL3dL||;6}t3X9cE)b_e*4ov_uYa z*=K?@Q7Vy@@9Swe8t}IT$btje)3e1D)oJ{lQA$yHI`eRh&n0!MYDp?B5Ahk|#Hw18 z%J@y0Vra?ON!r)aVqun&E2rvrhR*f%UPhHfaiOBEYP!D=Nr-%Sm9~^T*(RhcR6%Y! zGuD%LX5`qiN%XZ^mpaVk1fSvU`pb*jGriz?+6!9fymY;CQkYOOUL#(bSsfWso=_X{ vaoK?Yef1JKy{1}I^OFGfR{2=G=3> z@BF^s>36Q*-|qLf-!yV_0KjSt8vuX-fM$X=C!Vb8amn!vLTmU53)j4jNC^~p3?Lt< z2}jV3mRwP#P7rWHhMoq4ZKG)E~bEy)BCtnCms6sG97GF&-t*Y$(S+x8__SEmji>& zG%Q>Yri8)CS;?t>VKlxl?HwM>SU9pUA_qA-lTR2N&fp7i{t%we;2ST*=1Y?W!hK`Q z3heMni1Lon%!~9BrjSvDyk0YQS(Dvmp4?>6B@Z#V6|tAOkn~FI>gA@Kl;W9JBAUrh zdL?%9<)sE4jI}y7HX-zng!^Yd#x6CRAbL5>2=S(TAGE5n@kPR~tCsS!P0Olygx?Rnc; zJT`1~TN7!u+N|TkZ1PpScc3g2(Js+P_V)Bf?sRL0+e5YoUI>#M>iToimW!tkrY?8|QrO-~4uQ`s7+bJZU*9q-T3^=un=qOaIRhUhUs zk0aaw`~~IeNhgz~)F-P4h>o8WE|Br^=_)VNs%2;fphsu}eSl`L^$|2@k;TI9OeQqT zrWP_zNoF+*rI3i-FsF3G{(lA*7~dnAUuh3R+Bs>|6@Zc50_=C1sO(mR{eizKQ_Xh- znyB2C7UEr#IJm_d6^R28@7?G1bYcw4M6L>2X(i6Xfmf*9p-w{NDxoo@TPuM@skim}yiKacmBRAW%IDYVqhj3y{+P6^ou|`; zHy-d#X~n~&3%whPe(}s!N@&q@N41jgey`x0xCkpVyNP%#kcHxJKc-Y%zSgXiRIoz) z$d=yyuPRuQ@*4b!uanH&yg{ewUU*IyEK1jPK1}I4)kJ=(Ub$$Aa%rcrU7B7UDxgt@ z!@7>Ie*{LNkN5%t$LW(zS From c96d008e7e5d1b33f7f093baf7eb4fd7da5331a0 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 24 Oct 2022 19:04:18 +0300 Subject: [PATCH 16/21] Text fix --- src/Database/Adapter.php | 6 +++--- tests/Database/Adapter/database.sql | Bin 1245184 -> 1245184 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index d7c27547b..036f56cdf 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -513,9 +513,9 @@ protected function findAttributeInList(string $attributeKey, array $attributes): } /** - * This function fixes indexes which has exceeded max default limits - * with comparing the length of the string length of the collection attribute. - * We can overwrite other index behaviour + * This function fixes indexes which have exceeded max default limits + * by comparing the length of the collection attribute string with index max length + * We can overwrite other index behaviour here. * * @param Document $index * @param Document[] $attributes diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index 9c699b4a8ce8422b991f5f68f497bb91791ddbf6..c656d8f0ea7e5bde663a5ba2aef7f14dbbfa9442 100644 GIT binary patch delta 525 zcmZwEKTH!*90&0Cd-wl(z1O>hnlNbFpg~(G72O~`WMCm25L^@otBDX6qlu<5G1p*% zI+)fQZZ!@p42InB1{fGfhy$w&(WU%ZoP-z$2fvk3@ACQG@7|x^dwDO4rlV-O-S1ly zjL`^G7-JS=*~L!fdarf(?oAC%LTn<^rOn6V!e%;hMtx!?;QPTPDmD2jq7U!Co{;r<6)ZdxNr$+s4QQtOuuPlxzgC@Pl)OYF3 z@)L2Mu7=IEut~r{0TndR!2lC1upt8uWWkkTQ|x}BQ*3LGbNY*52!BG z-F>;vB@`G2LWqySiD9JcSzlXmHE>|FfJ>%vx403wH_~M&u-59rz-6`NZR51b&1f_E za44lI`Yf}bVQ^07Zu$1)zWW+Q=1H@QO9IV)CXM-R{`)M;dGf!5-}P*-1g`wAt=GKb zYpL|1M!U4~0^U;`<9~mpc{CReoyhkbA2qVQ+W#{$iLuGV7$7XdAv_`=4n#yGL`D=u zMKr{T=yqbvc>DtPqlYGL9i)~nhXJhgV5uj7wJi?VjhVZ^zTIaI-1lhkjnT)P1IkhP z0eq8wN}Xa__`$#8HFcaBG9q-HNp|sS8%*J;2~a0iTCJix7Go!a6l#gbZg7#p+JVz7n$Rm5mBvWA1 z1#lmz6x+mvmj>pWS3SH?<2cOdbIt{=RUK4j~LHOvxE6a=%XN832Ue59!#>7_+gDSIuzR*kM_msy=G`K7o$TXM@CbpAVhEZps}1o zHb6@`dU#2yQ`T7Vl3K<|!y93BdDqNH|L6s&Ay+CymqjBF9ETLy+9A4=Np|9Fv8xq& z-da*u?axn1pu(RW^@0vurxl~aCh?TLkb2XjEY=3CRaL!Fp}Cx!6u1>AvAs&-^0ZVT zv8hTT+f*qrufYm#hZUtkQt2Y8vGrvaEmggEyP={I3J$1OI;@E3j>p;a!^?Y-^9F0m zLK~Mif!=g*tL&RjHUQ8 Date: Mon, 24 Oct 2022 19:32:00 +0300 Subject: [PATCH 17/21] description --- tests/Database/Base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Database/Base.php b/tests/Database/Base.php index bc508466e..b9ceb1cdf 100644 --- a/tests/Database/Base.php +++ b/tests/Database/Base.php @@ -319,7 +319,7 @@ public function testCreateCollectionWithSchema() new Document([ '$id' => ID::custom('attribute1'), 'type' => Database::VAR_STRING, - 'size' => 2500, + 'size' => 2500, // more than 768 index max 'required' => false, 'signed' => true, 'array' => false, From a25f7d6b02ad039c82d5de17fa5083144b6ee3bc Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 25 Oct 2022 11:03:30 +0300 Subject: [PATCH 18/21] some fixes --- src/Database/Adapter.php | 8 ++++++++ src/Database/Adapter/MariaDB.php | 10 ++++++++++ src/Database/Adapter/MySQL.php | 10 ++++++++++ tests/Database/Adapter/database.sql | Bin 1245184 -> 1245184 bytes 4 files changed, 28 insertions(+) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 036f56cdf..cd72d0a33 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -384,6 +384,14 @@ abstract public function getLimitForAttributes(): int; */ abstract public function getLimitForIndexes(): int; + /** + * Get Maximum Length for index + * + * @return int + */ + abstract function getLimitForIndexLength(): int; + + /** * Is schemas supported? * diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 083cddb43..73c8c72f6 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -1141,6 +1141,16 @@ public function getLimitForIndexes(): int return 64; } + /** + * Get Maximum Length for index + * + * @return int + */ + public function getLimitForIndexLength(): int + { + return 0; + } + /** * Is schemas supported? * diff --git a/src/Database/Adapter/MySQL.php b/src/Database/Adapter/MySQL.php index 693f41443..7d5852b81 100644 --- a/src/Database/Adapter/MySQL.php +++ b/src/Database/Adapter/MySQL.php @@ -48,4 +48,14 @@ protected function getSQLIndex(string $collection, string $id, string $type, arr return 'CREATE '.$type.' `'.$id.'` ON `'.$this->getDefaultDatabase().'`.`'.$this->getNamespace().'_'.$collection.'` ( '.implode(', ', $attributes).' );'; } + /** + * Get Maximum Length permitted for index + * + * @return int + */ + public function getLimitForIndexLength(): int + { + return 768; + } + } diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index c656d8f0ea7e5bde663a5ba2aef7f14dbbfa9442..4b6bff94ea6b88ad386d82415f070ac26bd656be 100644 GIT binary patch delta 32145 zcmeHwdz4hwnJ=fRx~Q(|N1cAZ=q{?E8k+9vI;Y+s0zRS=5Y%xJh1m3?nqYV-IB6%D zTOddSBCX?Gws8`LWKAYx5|wy|GcNSP%+1Y~Yu*2<&i?J+{vLaOd!PL}8#XN1uwlVtu3mpS8&3`mrQ@;eeHFbe_;0MYeL*R; ze|TVhZvBc?xsGc0rP8X~2iC6bPsNi6FtT#ZS97 z@S369R^?W&UpH}bz|qM&_Q zi+fhN#ZBr=H5SdLvOij^R(&?FW}=CB+`+447Cwdl;_e?A;hP&{B!N$SM^mq=0!|A+JzwzyoX z#t(lcNgJamst(jXiIebpsRM;zM2E-5C}3rU#V7OY2DR^_2W z&hkhRocW^wr`2OT9!PZJSrRS;BxnO{9d=ebO{bdNT`kQMcUflSnrLBu%V+lh2QH z{@Ew>;r|@8s9Xx-hbzjZ4ZX;A{i|~82cT~raQ1J5pGc@(>6iM5N*e=G2QK5`096sv z8`znER9z=3m|aumu4Um0sZpGK&rTnyGAk=6`~4NtR9yN`E2Ko9sG$D-6|0AHql%~w zcUO`+%)V49O~#~KE2VM#e{z*ni~nC-MTF9Bu98;QU^|<`6K6Y@O{R8EPqx^3ZJ65m z8(~r?gLK2rwMhM9!R*bNU>%b?shNwZ>zLKdOFAj}Sf?~q$U9IMtYy!2N=;pYQiTCS zoGDxpu-|D1s@LZ3iVr$Rnm74MYt9zv`{6F6-b%+F& zyizMW)GIYjwc0Hwtg*hR6tXL(?Wqr5C9!9!Tus^oebW9Fg)W^BE7U~X-lZ#1c+BK2 zt`FJG4@mnlUWsQ#czA5!XMR)q{v41ttqcvMk^=+jY$ltFS+c;;SBYj+D^u|?A55^X zd`r6YV$L+E4h`o1%znkHgV27wV4-Tn8g_uZsOwF3{z?YD`S~(BL~?WRRYB_p$3s;>|;}$ zkTb>ohpiX#aUmdZT6v1eU`5WMQgKH2VL8%hiEL zJ$zEH(7XSjR&HQhJ+5_lT(Pj)Wqm1pk9RZCiYZ?i%gTeRN=Z*{C2ncwv{V|L&(on61lX|O4lJ$5umz| znTFe|Nd^Y#wuu4l^=j8|s`SBJYDgI#%w*&0@L+ae&^Bg@r=p5#AC>XPEV#w>(Y}!D zqiS=G$$;;Rxz1JV!(K|RPd!`1okCRd{#EGR+PFX~q)CQ=TV)S(zLXyDkn)vm@HZPmtf-9+3$Q91N}!Kf`>XAoPq##Oh(#$V`DJkEj<*SVc>?C=^_ zqrEw3AFpv8t)Bx0XJFxLFr6J3No0nHh3|=pto6mmn5@obG%2Gty92$frigXX%W7%_8>;lOS`GCBE3WK%vPh5@q zBrt8Ck;~bhAG_-H7EKevmvK^yt0*RNDHl-SDhuusE3T+W5tlateRv)()Z(fl$iQ^Y zrCunGiAawTnZrvIn3$49E;ewNK@Yh;XS^f|3B$9wWELA!GIsE%MHAyl7ny}jj1$5$ zIj7CU7!%2I0fiZn8{J?y%?q`e7?X9TsEG@$AvHokNeU{o1_}x#1g(KW zB5^Lc&{ep+h-$@IH7qEoa0P9isv=}DHt#2{dOnaLy$^fr=Y?@Sc^r;%Qk$#ruprXQ z1r)l9;CigMk|GAK+ZbnrXYfL8uEJz&?Jo-BdLnP+%8Dm6X z#+2epdKhKqjZvF;)|3|7sn43C2}`pXVd*JzE81stj#RfMbwH6uJCV{?C1Y)1HT7-maFuELmzK40qKDuS!C z;!27bxNc)u9IoYs+L{q2+x2v@72&6yvV(6hC=@h(gUo~xk!mg}GP(J7jEAucbCD`5 z(5g~Fqe`xktrg)ywKtx2?J2X5)Qu2Un0B}pzv$6H3c@L)*WlM<5e_t8EaHk9BNP%7 z7m0udjzwP-4I53@EyQoWRF2Z?@q*6)Qa+DoU@6o5!rStEXE}*0uX4t*s+UCin2x&w zXQhJ)WPf$^bDs&Pj9!lYROIV6#!Y75b(u36d%7TRF|Uyoxlb9rL{tXGL0y=KT|l`^ zKaI|HkYfhC@e>2jaR362jUOq-89ZTN8hAF%iiZHiz!!ZcoH9C#DsS+08v_s1z%!l6 z*rJz<@?u$tfit2qj3Ug2kfsL4T&985lmlo!%!ZgKC5c-C9hwyyLgGC7^t~d|2f0rf zRh{)Q{iM($@Nj_mDJH_@jj;s+Dx-b0P&*;i(x`~c;6e^jM|&@TW0$?^s^OD*WDI6H zYX+Jzh86hTHCQH?ZRq-Q{@0qj}~fW!KB+CL3oL`rHY;lKO_ur!TJx z`I0t1z!Sdea>}=`+)egknxZB6UQE3AvY5o)=%O1KpDB0GR$&^hXz(IXwB%Yk?*m)z zqGaQvw#@I&lhxOG6`-uX4Bv#*p1org)BthwH59Rwx3)HlpUMs^7PRPcaH@` zNaj|$|E}9X1ku9#dzJ2~w#uo^oh(&Jth?GBtF~}4rB|x8*ZOYm0vnOl{@Sr>_xGey ztK;WhY^^SyjKaZ*LaUSAUv`%=@Ut+Y3~-pj$ncYT_f=(P2IGK?Jp(^s!85Rfy8~s~ zhE}(?6b+1{GqzmDNlKh{54E!Cq7SF|=YJ>g#bQ43V{HTK7%IaCJcI zzUetJ?B3GCFO-fw%%Z-(@G*s}C;rGpTf4g|Luo%(cw42}vqY=8qhu!ovB^_|e z2LZ+}PU8`x+~LG1Z}dK=jL^Ep3)fKFpuvh4t|1NDnswoNS>aS@3{FpG#4Fd35!#8{ zNf@Z!;)QF-2Nm}JTNw@>|KGRrGWTA8-qxLm^%WPvE^^%EhhVkEzKa|q!c#bl`O;lz zOeDhS`_=VbmnHOv_4OBlR=9fz!P1LeD~t%&i0y~_lCWHs7Z!y-5&Qbj~wA7+KU;-YYu9EJ_0qM|THw4aoA>|uRBDOTzRexC;I)b* z4vaC?Ak(EZFzafx>+_|gs8T3|NXQ1h?ylusB6)1Gw-A32OuAO{J4rXKVl2f^qi z89t*YIS8mw6g|j6M$cwZ^;B0JAWfy}s8R!Y^qyEKs+Q8=@MsoQr)=T`jz&^2<)5wS;qRH-c#+Z7PQ9Uq^UXtE+Jd_5IrhCZYp1spOQ!w%I z=^k<_8`4|(eGnLQZic6U-Pr9Rcb1HGQ>K6Irc5WgJ><3yAgO14Gias*Gdzt#y~bvE z$bl*VlDk5H?J_Ll>>g@@{vINYc2AGz@5!XH)aPlk-DB{@s0YvEGY;BaCzESBo{W0P zg&zPShl6_iJmjnyq&HhHa~Zq8&!gSnS9blI=5#9D!~~Zg+2?NfV`F0U2HE?|#aQdU zK`%KVb>pCyco))}*zQ3uIUx1Kpch|G#r|v1OHTWThP*TI6)s<0F}(iE3s$UJu|CG$ z?2;Ot()hvse;M*NPlus)aS;Gz7EO`AKSTu9nuooYFBIn&-VHLg*Ndmtw z>`8Bn&CN~wy`*Y#koCHX4g0;bv8@5rYFje+-F`1w7y=Ms29hTB^(VbIW2O&*3IDHu z%9g2KyXh(Khor*pJpfc|4|vNP#pb=)wg>__aN8bx>ws5#>%hdTK8NcZT*f7;bMRQN zbJu8lyuKU0j-_2Y{DmVK`aEfmB5yM=!*@uIw zwso^lAvT$`#n)szs(AKJAFdM&K-diI>McG}|95Wjkw)~y7MdT@n|6))NE>P%qZ~Jk z`A8euFy0x>P+*>%pRNS`YqaoYsRMjQemW zs=YGqyYxSBbA%auQFDaH8Z^h$@hQct#-O`^>*+*TSl+wk3&AVdLl^t~+6RjNa}~G% zxV2A|2_75m{a-HjAIBoH-qq0Ftrz|r9Q5OsX@IN|bo!8=R3``uq<4C7h>}2ht8H{O zahQ@^J?tkjV%;zy(Y`nAS0u6H{Bsu90K1&XtKJ0()k>JdK)8;^|mNt1tZ#7~-h zV7Z^zF|*u12glKk%l+i;tli7~IBaQ$m;3+9i!*>Di20VR_LG8;jr20OIce+MSn zyT;$d)~xZ9we(W!j8Ayj-i@sBcR3hTJA1%e6Z-C4Dfr!GQf%Kd{#m5e^NX1H$icYY zD<%qMH(whdYTbWrfP~}8&jsq(k!u5O(@?)xVir-hUPmaktF8;YK}=b>Bw)Y9YT1ne z5)C;>uhV$xofpg=ig-HMnHvM7_X0d|_{=2%GB$v8<5E96-*}g2nAI!|G~)aHN;*1+ z%r7h@GHZ7&4a7)4FzKd1qpgQL_a$N<1|TxHUU*Z0-0ZjGrU1GBY2QtODRw13?DmA} zg+5}>R!Fr>?GH4@gz4wI{q6St0Esk@^at>0TYI%X@V9eufP?EyEdh>iPJ;U|jX^Z* zNjMV2O=8cpfj0dAr_WOBKzc3nJr^JY0H~G3xl5l5kZ7^-IZE>AbGBMt&(1+6+)E;l z^Pj>YZ}xf0y!?3^a~=Ec^Hir_!hbw&ER{6jIa`Ady+BONcne(iLST}E_Y7GxqL%o> z7pSmDMbxb?UVu6+qWxG&06vn=v2fei~Gp|yO`(LH<-T5k&@9|d!^8Lm_(sGnG>N!U# z$*QA*ruT!RfwuECYGFJ1*up&ZH39SRYgDK0uTk+HeT|Cux`?Fh_4A9D5>>k8uT$p# z{<=WC7l0X8i9ftf#p^gmNfsUxknA{ie({8D;)sR0>^NnX?x?J1mmjC%+-&(jew>Q; zl!Zi(f@7Z?4``npulU*?tmwv#l|=D>-dIUSG>~4)PHwCu9SF!oMsN4t0ieZqR60eb zcWvzya@Zr&vv*XIfcN`5sBG<vvF+uUY=@*+C^aEFuZseE}ttqJClN-IRL!-2(Xz0X1$* zzqb5u+(}6wy_S7(Ck>ak?5rf??H}xPYyi(&8^Eq{fmHLxFQBk+-tF#jD(ij$_1Gul zmD(rcRqtMlwSNDtDq;os?JCkq%z3+tM04I}ZFsxtyn#3=ta`t)Q2)_F&Bybz-l=Lo zU#(6G2i@D=p;Bw_P^mff$3Tr$?|7H0e)+qUWZk<0lE>erBu6bI(g{k^cS1n2=EMb* z6h`EyEY$CdsAs%)0qVG@!QB2HmHMCG6G;6YP-FX5pQQFno}?s0Cj}(mIY~(lSxA0u zA?Y|JAn8AK0VRbqIzK!`O@v#zZIt`H9JkE=B?)C(^X^)^yz78zp3w2 zlIz|Vko?2@lw|+=l;lkdN%a{4$>KBTZ@&rQX!~1dsC)*K#sOt4+Daoa01tgo#Qj+hVr6kWx?0|~nQHNiG~*2(zBkYxXK#iKPrlJRIwP{q--a60L>)hlkfEq9gvX#-Jho?ROx zs|l-XDeD8Z!CBZ5$7_Y+1*{z&>#L(gOX`9uK5eAy#U?k)&rccY zx6Bk5bPba*ShQ+m$@*XuzQxr@6KQ%&eK2GdK)bg+IA3C?8-kbhpaNFkwrUW*HD$~g z3xnv5jls$Ipc&1vEVStA&@zz_KWq%f97__`r1GZol%zVBw6rPMhaLA}Q?Svt8h4uMY@)ftz@E^P^tgNyl=AeqD7-9lv2o^1(6 z$$WBoTad(tSX+?H)-P!bcH&CJeZ$_U3D&dkv;~{+>9&H~Y>P5yfD+d@1ILeK+L@Qt z0dxPPAla+4aZ<1uf3T!b(u7a=Njd?y^(f<~lY$rF&kqy`M3rh;dvG$Y**a7ksF4>) z+G`!bQ;EXVG|WNs&wkmbrukz&HO+o?ebC3U*9WJSGV$+$i88?lrHuJ($h4t&><>!e z9|^N(;9r?CGCc8x;D+L{Kghtp9A?kJKRsn+_@^bo=cK~IBcDr$&xzSH=-;E_3y<2{ zUkcu(=!c0i=}c@OJ`CR+$fgFZXTg9e4yQh>mr)iU8%6(iJora`%`K%u*W4EIf=Bxf z2JbYkdL(ib_U4)!#*EVdw15z7&9!d3rHHWbf>(<1!`JCF&ojZ%YJI;NO*41Qk*#hN z!}cBz*2ZmF3)}HrVf{Ar!bUfmQTzCK@K{gDWvQr|wXPL|;q=GGTJgL}nV$p9WQUcE z8XroeG6|8BlhI7ldcX~c_+z%GQr^Mco=p#>hH`LtGn25LKji47<74i2_IQd3i>#&e9mkj@@ZdbfOF(H5bF%A3i=#uwqG>LBwBOOvbG@kNDnXD=(A=w z$t3^YCQw-4B!at_f~@dO9P1a(08W;Kk2T40EKX~)OuFNXn`N^9aBZ_p?uGwGvwRWG zf4o`7wPII`Ox9_;TV&E%U(+J@;oh$>ma~2*>G2jhf-R}T*gbW!Z3M>->fcCGTjg8? zxvp4eMRoD1RvC|*wNtI~-%A3Ktlw99WRlz~fLTAU#1&$D`aJ#Y_IA0s8%bs8>Rg|m zY$p{`JJT-z&)_9`>?I))9rDbOFo(`~W^mNf&h*K<(CxT96kAU^7CsEh!>H(>V=-uo z4muX&o#>z=PlJ%>*QA)d@&C0Hm726z{)m4jgc`MQu*upZ6T^q#V3Vy!CWx@`QaMXW zaIQ)4K^f{w@xdmFF%LGOb4?UcIM-y}ZBrO#WYc-nITj8!nS+5M2zPtp+wn;y8w|n8 zCcAYAi*c?A#A(J~?IASUwtjhlpWUWbGsS~b6Qx5F6k|HC8t?9>n8LuN%9%yCmT@kH zoSLAPHN_!^CMd=fha8%qn1VRu&;%f`e@yS0rzZGF4ma>YQyd@F3tQh5XCk!@#uUWy zlA}G;KO5G_f9fa=XW+B4qO0inV?Lazw~uuoQTy|_{M+J3OCdyXJRLvtNBa)S8%g)| z<_YNi9(r4@!F>=stY^=>P5a3r(tcWkr_4Dad)cAwzDl;}9l2RJh_Zf-^nrKeun?$k z^u+S~_8oZ}{$CWuXM1<%lK=8u+QpXO*0<=QJA-G##)3 z5N}UpJ5S4(-~n5)*Y6)0Sg}&n_5blS5l`!RUtUe@A$=e>*(OO2pP?fn0Cfqg!2x}* z^7TN0O$6vho7=zrflMZ6ILPYkinH+Pg9Xowi)=r#_IR>+HSPK4W7`#>SRB>ge|-vhnP&oJquE_g40|!oQLJjwMs2 zgZa$H!p7BW3!OF23x&0}WJX2?6VW&z7+$mftA(33l+E-zm+=Vhy}y4t#Q*pH_T`{@ zetqudwS{#XH({KmX~VQ>(>f}g zi+B|V*RKD{>cWQd8D8g7UirQEh35gLiB#@rY^e;DJFl+b=-}SUfet`@Z*1TK_;+j| z0RKKTkN|%lJ2`M!M==(V;&bE4xl%NoOhwz;obv=ZBFp_!q+bSQ@kqRtUnYg4NvVZj z773@)v1YrnXgbwY3FoP)j6-i zWTwR2STZcj$)7Bjt3Rt%DGxSQmBZ0k+{UU>SdJ!bt(r{6Y^*9#t45-K9afD-V?3+U zaS{p3Qo_cn3EFKXJFCXSaY?qZsvM4|lV`Q+&_6Dip^Zn)(5ZyU{%i=xBqECL%YL%+ z!_I0<{gX#Otf>S8I`-IK4u&M)4oFxKy5av7f)IiKX?ZJIULn-LhrbYnO<~|vb2k;J z+s+SWHV%#yZd$v6Wfgoy3_20%-yU6{#vE+GWVzw8p?@V`(d zG?8ykcq$sX_?2W=pU`BgfB>a33^-CIv_twGWkN6f|En?~2><_QnQ%V*f6s)c9{ykH zMgl3@+`)2!8l* zb%ik24|F%Uwy-fnr{;{keH*=qL*+8BFn~nb3 zlkk66wNMBDpI?obQf{ag*408i8_|iqp3Azho|9cBJ&y#jp1%=9jS^a}>A4PwUuu}V zQR}ZKVmDTEsdNJ|t9eB?1|RPhW^!>e_5M2YY`4(d!)cZ4FvJ-MTA4pX7<52wQrFZ% z_Jsu0y`KwV6EULB9^AdtJ;Heqsn{d5L04qR+eT_C1Q=_PLp?$lSHPVu;&d`=me5oS z1Y}*Quz~Cj3C*y<4YP!hXrUwb)Qg>*$Nye0wvpf4K>Ig)5cI;?LO+j%MN|;Kxk<8f zz%@jwdNFqcz1TZ0??vub8S54L1uNDwOkIWGQJWgKs32huHSNIY$g0BD32 zPiypZzbX9ie9CPu8!u#1ayFJJ#D~pQSmYZ`B~3{BWAe;|qmGQM@W;uQza?BaPeY4l zrQt*@lS$^H+-fnI^O%fa#*xH8+anC!AEqbhas-t-u#9F6}q zaClI7x~ga~Q?R>iT1#F0<`H%AAhYfk!(w0v1cGJL8tURSP|e#=1iKiD7R%bv1j?or zX;b;angVVLbdF%B4Lg7)(7|N~Pz0yjup+0*yS)K#E`kL$MeN z((HL%_&=PUVz4)(yDZ*PH#N3FPcgXb?kbBn@M-jJL_3}xippJ)b&)O;5ip;@PQaeV zV5if>4#3gb=`f)b0g0il=^@H$Z~wi#4Me6*Vi}suLT@R+nP~j4qbeIIM4BQket2g)t)2TbT0AGDjDBg`&%Xon(JVsDSwDS|O<^ zcc3VcJ`7ukisgkCJzs|t|A9K78V-ocp79a^i^1? zl}oz>k3iOV9Vm`G?RB)1>Fs_b^%GtPdLgDnNVaaDV=k277d{H2E(ySgJA4>~5+RU3 zn?M#-I?(&xno4X%THZ{ataPBok{2r-7xLfn*4?~j4L6Xyqzdt+j8-`gppHPh3tDfu zr3O_XwA`{hpuAS&_^6u2OerariPF$BB}I~)aE>l$rDE1lial1t%-`+_I6kZ~mYU+M zU{AzxrbZnYIf(w)r;mJOpD=P8#(gcgvxpA(oei71sC# zvy41i!6Ve@$eDGHrt2)d$uM0xnxPOM>cpV+7PmbS8CvhCUtz)5Cl!}HW5{$)dpdG( zy`#xG9F&jOI}SIf!!@6X4j1D2SR$KF#dD@{sjW>XB%8+y9j+G&DoQS0NXvz+luu`) zQO+A-l5R0@UX<8la__j~j~YlmQ%I#K;czmSH?>J$B$9ON$NWNDddxfrd2*YhS3}C> zh6~wzI-SWRvRouSm#HXw)%`7b_)dq1bl%|@)ZntisYF^zBopZj=fyTj_qjMOjXl;F zqi`cSlAO-VnRGUmwWyWJl8le^e9{i~` zKjO#1<;<@e(X!^(F->S0nJ~M}s<|aY67R25K@DrU_lh8047BM0bIit|Ul_uBdtX;3C$j$y6mGji!4c zwn8Z=LT)FtfVId`F$N2ruhCsZr^t;3?KP1L7@W^IGwB$Ek^Mg}sTg{?&^(}GSP-1c zFfA&EG@&$OkgH-umon2$saT^cYV%+)$r`n&7=m>tu!{B3kV_+?I3_AB<{+X#j58WA zPAJMa=b8$(7n03%W(joxB_^Q7Qq>47LKgkZ(ZC`ZH2aW8f2jxd=y5R2KrN<%6IZC8 zF~~I)qU$r$O$nmW^=g4ea1LwKVk!tmMt-FS_K4r^**3<3bpx{u;~1VQhhRcIj8(2} z0MgQIC}buy%cP4mlZj+84gkxN=07dOZhKdn2xTQ zV!A0gv^I-c)Mm48iom+nbyKipX$&LCeK%b?g+#_Mf!?&hKxdXv7f@YFt<&j1_ozl-&0rY8h>R@!O=%dx$3ePY$~6@T=0fUtO2*T)kwXir?#~QT^Bgoi}r%Iy;KJ6CmYyV zRBa|Si=<0b#U!$fBG{<%`csZwW!6Ytb7A_r!&UH24+klLP8z)uz8~}GsN~CeSoGkH z8iFC8xQs`r(UI^Ays*(Q-BS4Ki}{#(KVI?~h@{WKHCT+aSbtq!Y|ke$<>mHtr20jk zJci*eg;jAd0rW4AUh(v4e zL&0}!w2OYWS6-O;w z)kDFPVXQgW4v-ha405kM5qb0#eN_+P>(-fN&mAy>JlbPVM>-FetO%JitTPi=g%JQy zx;#4LGto(--Pkx9UauB+7^5g?4@Qm}{6b!U(WFtlONl}y!!Vs#=MZbkFda5Ti|N{( zK_yMcqsRo@O6M`hD%Vs6c7Wehfi7gG!t?~V zR^h{wj_1&!v4bvWJ3J(&WpwmejuLm2IfIt{VeMFDzRbxM`tc^S>xIe1g?RMhhxE&sPH0x-&vjQG`G*Vv@R=GS*bbxlL#~Fir zsjsVe>IN$pFK)r3^a!t}0^=>MaH2Dr25T{PCKH~)EESR0d+8)`_YD`!}>KE#)y}p;3zyf5} zzjCC;`F&w()Uosz>!@S-6Z)tVonLZJRbVMG)(R}ALaXqz2Iu8vMv6q7<;hqpsEHQf zSmXYkzA|O3&FOY^!*mJRx^JW=*N~?t=y^kW9x|bP)ahL5SwMA^%hJtrx(61?$=L*F zGc6sCqv|~q^OlInhq6-Y7*_7nF+ZA@L6yevy;DVC3=^PK&`R5-=kYGaQzb(PI=c4jr*gwtnWL^0 zf1i&%R*@3qpXWFO8d9c^jwa~g*mObW@|2V~`*svbq6bG+6Att_V>(hK63<2Rg;+Mu zRZ4=lvznsGU^>#FKId!=DJ^F*@t73J(+z2 z+DUP4ADijoG`)@gSVL+Lmv~C1y?AD}9q+{8fBte4MAa7Hwwcs3`iM~(~8DCf{GoySvLJ<-REC*^ko&V$-X2Q-qaz}9LO z4$MkWfX0{)7Qiv%MFpVyR~QAwcrF9Gv&Sf*1+aI*t>8=sbT+sZoPm7@ZUtvxSAbi= z3o_8OQ+vU*b!aI^lQUkSZKmZiQ1N>fI=@}YI;1^;IX#*O$4hQxZpNP5OxumRH(hYx)T}3*EZT7O+sI=M3X5-Afmp!ECi>AVKMA>X+(=MErop#L7 z?rpP|&HC~G*D_5>{_ofFkaM@UXqnoB>Lv{5XgQqz19St%dbAu;1ZOZ5<2_s-OvuBi zhuGDl<;KeykBEPY9Xcxg6uY@8o?^F1g<DT1^4h$N`)#8{8rqp%{V?!s`Sf}ux%?!Z`uGAN2PIX30g>wus#`J~so?Ywpt~_vsUStLmajiJmjuPKBEKmx;c$0m(3BKZ zcV;-Ig0oXl-IU=7RfI$Vx+7zi3Q`0s`Axz3F6iSo1!)5Gh$(BS2$Mt5v>8-Sm~y0o z6KGI9UCNOP(gf(iQmarUilQ1~1>O9n;FKJshfH}*K^pEEQ#7#$)ib70sB76x8+eir zs^?2NQo%qVK+l$1rGgZDMx5X0xL2d^_n=iV6q6aggKjv(d<^Jd^%bX?7zO%8wIwYd z!<6~~iHxR9sUMI=ZwjY=Airn`g)=`g1@Dx5C69j1sU03hRdw)ABnR?@1~^XkKs1IJ zcm);Fs4aDoB6 z-W1O6KrYm1ssYOi9i$;tJr*ic1TTqtQ*|a7;2w>pYVB!^rbJUy07q}h-(6M&2}UTw zH=3%!O+g1~G*yk8f;4(lRT#x^k45_WXf#!6LquterhK?51BlY-O?fd&$@!_i&uFQl zL{qCxiI9j0#Zte7k9G9&QcbNQ^oRz!+n&adqYTRdanzR7vE#xp(BF~Wlt+yN_}D;q z1XN$feXCObtLXgbU*M{rzsJ=;d?8n@<>7fD7fSmnQC3*)hF~QRg@fqQ zgMLhic~!o-(nm9X?w;*J89%#cyJkS(qqAKoVVjn> zv8y5=(V01}Msi)R3teY2-iwj`wHG5D>vf@vJSa#58JL4B?VICj;>tBX$Az-2C?UE= zgrZ#pS)AX8RWR6xxKZxzbNvHaXBGxr&6X<;z7Tf7rG3JPcGipN29GDgE_4?NB|;fP z{R1wPfJVz(%=f&E-#6e=?i(n(=8dT(*|hp9YhCVPkF_P)Yeo03mqV!svTl?$bzRnt ztV_$A$dkdr=-*H* zyZ2G3k$vupCcb)auYOnb&X-FB*APmrb3c9;w$$5qd1msp zDiQTc6uUBZ@lkF9cfKPNv@e;{Ss$4|dM1RYkSi+nCEZ!^am14gP$3~&b>3#0nz;_o4{_hS6kv&g)=b=&0?rLHYgmwd1gy+g`xXOpb zy6-9rfI`s&G{t9DT+3EHmVpFCzUAN`!*!rPuq=<$rfx??YEa?YZ7J!z#oFy{CF`n4pIE0~p&Vw$03G)|z$=3Y8wn%*IOB`nZ!-RN(B0|O1yo}kJ z|1t;U?_WNL#M}=5D--k|c+ja=u*8F}VE%4<1@rgVD;)klGJ&)n#)EpnVGOeNFlXrf z=&-N-Y=fFRPChmv&wQ1GoPQO|wEb1g-XpJK_Fm(Gw7+(C_7c2Kx9T;F{7*F*`Sy{!bpo>^*4$QN7^! zCr5qCCr2y4whIcnX;T#v{Ck_KP(VY=>&Wp{FyJkvXtaY}1g zJ<~I{Rw0M?hg&gk9h)(4OEz0T8pvIntIq1{quf6HiV51Y#R6SVF56Ot?*1Ivg8AFA z1@re)9*FBU4AOU7mEG+2rbTUIw{h6oZ$dmy5uu5zZ^vw%cRL5<>$jgnZQRcLOB3|R zJm};&HtY4{wh|w;Nc@v=4znMc5L>oli5G0e60hCL0r~OPb4bi}=zlap&)UX;{?axq z@#Hql-@k6d{Jq5k>E4b(7H`KOBik{^1KTZ}G?1gT(%B*(nL8Th+<~F5y@LaN{~eg0 z{igrNOd$1lazL)R6N7xs^ncf#n3ID%5dU505Hil27gpYdp|{_~;qL&2hGXfsrvFV7 z7=)JBkuOYOcX{JP6^gfiG+{dco-+@C9g`fc7EPW*VD7TpU6YvCy&UNAPbRCBPbRD1 zxe7}C-ka4(3*uYVXp&g)RyFeGY|a{ctNN^tIL_^QzcE4o$pp>f`FU?wcbu(P$GJiG zwzo0Y%G;Q02K_OGhN5@AgGImi9SpMJ9S+E2?_iL_CJ^Bm1{pZU0a<_S971wE@{=a$ z_ju5A-aQ9&ls8~*c^7m2y>~fWze}N^{%Ve6{l$-Cklb+&$ajuokOL-=-g?k;#*MbWbqe!$fCpXq{yCtz4*S~oG4%NR9Ik&sp<(|! z^F9{6;WP%h@H7Wx%V`Yq!_ye#8578-JdlNF&LJeqiw2*ZO7XP4&E`o7b(r@#ezi>ci0DfSkJtNq{9t*G3D5G6)ca>j`Cghz z2;H-4C-DYOG~nSODmiG1JH0EH2a$@n{oS^vGpktT7(U> z_|bK%w7k)>?>f=qN5>@?k$E$YBGqdb%C2nnqm;&Cs~;_4?`%apDbKX}!)Q6VqTP>t zL!{l07VB5E`@3N$Vzwc#*ZLdCciR2UFz-z_n`KYt6orI6PNQSVnpWhYdWt+a-H(p! zY?|(GfuA(dTblL>%dz8No0A+ro$fymexN`H;B~5@4u2Qy*(#}$sTG$9%B!9J6ES0D zTKg`Tb!A%pTo_xKCcnAH?;+`H{Im4!I=XBf4b$(1@#@eIPH9I&Xr-}IJ|L~YJ|bqV zz`jDIRe1dK{xRniSM1AT)(YyUsaV#TLbLSB9a9`d!t`rnR{BVoey&Pu;H@wE?~v4# zqI^;=MAf{x^}9*`pK4TlVJP(zO!`&1C3?=IJ^TH)X?H*( zKJ*j1#<4N|N;^aopa*o#hi@?pLGIPBn8r)LUZ=R8_K()6r`B+pac&MBc*8Vg_fdac z)KXPHl;;Sl7p3dR-Ec+ao~eN#4*!;&QzkSdNnCcCP{CFGJSv0cqk%%>t!ZkT2) ziI|U#=#N1%=h2S8n$*CDV$7mdN+H_IskdBTGZ}q zO=eQDXjYELQ^|z+YE#w+68x@2AFC36j$BnE&Y0@;5BZ_}ZSVZe8u8oEgHQOy z4!E~f`lcfNnu+@1D;PACiYyz*eo;iH0Iv|mRxW0%B^}$qRL@~Sz7C4weCVn4PdV~D zl~gN2SFNn96@Q6*`%nYDYTdlie{H>pViZPXJ{fm+gIG_Vsu$7xMJbys=cZ;gh-ki| zM5q!)D$b!Du@r9T^4M>H&TT~eDPL}+ndZg_U8&FV`r?yqB8;Dv6K&!@2ppEoUt)TAy4cSlGk=JQ2}E`cxCY5B9b!u_;7XI# zzCS(DfjXpeszdx={tGOw5#)U4lhDh7l+QeLTFR*baR<0RmpNZ^;-mfrQJH?;G0Dq& zWS)-tOkUn&$qVxG9OxIN(9e0dY+ScYDRNXfaW<_re;JD z{IU;%QML_=8J5b8wPvtKlPIQgC@_s-yc&4eAJga&Otn3V zsx2)|1tn2n%^K{W912Whu!C|aFpbU*%AueX&_0Isj3f#zq=WV`*zq8_koFCB%8_;u zjn0l6W%^+IjI9^{+&LBBMZ*bR9K{~9II6)Kd(lGWFO%Z$N}o5SE`rhHK$<<;vtQhV zrmr`S(b@08x5QdF2hoQO<7(@oTxO5eL; z0EJzDdmIM`n~$T2hWyXt;%wN|yT`>e{NH;5*Z=$pT%VS=TE6GE_XGwRJSpC+eC&de3z*d^|2ZuAO*YKwPKb=JEDShvW>ySQ#_r+$*V#&c%I3l7%J=|`v zPd&1H4TXRzqSQ?mvw!=25iQa%BD1k8Pm5!4&BzeX_M^Q2b{cUye)6=aoIG9IDE?n% Cpn8u0 From c58ab07a7fb81819470ecf015783546d96536248 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 25 Oct 2022 19:44:00 +0300 Subject: [PATCH 19/21] some fixes --- src/Database/Adapter.php | 22 - src/Database/Adapter/MariaDB.php | 100 ++-- src/Database/Adapter/MySQL.php | 34 +- src/Database/Adapter/SQLite.php | 120 +++- src/Database/Database.php | 55 +- tests/Database/Adapter/MongoDBTest.php | 758 ++++++++++++------------- tests/Database/Adapter/database.sql | Bin 1245184 -> 1081344 bytes 7 files changed, 579 insertions(+), 510 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index cd72d0a33..02c507828 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -384,14 +384,6 @@ abstract public function getLimitForAttributes(): int; */ abstract public function getLimitForIndexes(): int; - /** - * Get Maximum Length for index - * - * @return int - */ - abstract function getLimitForIndexLength(): int; - - /** * Is schemas supported? * @@ -520,18 +512,4 @@ protected function findAttributeInList(string $attributeKey, array $attributes): throw new \Exception('Attribute ' . $attributeKey . ' not found'); } - /** - * This function fixes indexes which have exceeded max default limits - * by comparing the length of the collection attribute string with index max length - * We can overwrite other index behaviour here. - * - * @param Document $index - * @param Document[] $attributes - * @return Document - * @throws Exception - */ - public function fixIndex(Document $index, array $attributes): Document { - return $index; - } - } diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 73c8c72f6..999406e09 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -166,6 +166,15 @@ public function createCollection(string $name, array $attributes = [], array $in $schemaIndexes = []; foreach ($indexes as $key => $index) { + + $index = $this->fixIndex( + $index, + Database::filterIndexAttributes( + $index->getAttribute('attributes'), + $attributes + ) + ); + $indexId = $this->filter($index->getId()); $indexType = $index->getAttribute('type'); $indexAttributes = []; @@ -378,24 +387,34 @@ public function createIndex(string $collection, string $id, string $type, array $name = $this->filter($collection); $id = $this->filter($id); - $attributes = \array_map(fn ($attribute) => match ($attribute) { - '$id' => ID::custom('_uid'), - '$createdAt' => '_createdAt', - '$updatedAt' => '_updatedAt', - default => $attribute - }, $attributes); + $index = new Document([ + '$id' => ID::custom($id), + 'key' => $id, + 'type' => $type, + 'attributes' => $attributes, + 'lengths' => $lengths, + 'orders' => $orders, + ]); + + $index = $this->fixIndex($index, $attributes); foreach ($attributes as $key => $attribute) { - $length = $lengths[$key] ?? ''; + $length = $index['lengths'][$key] ?? ''; $length = (empty($length)) ? '' : '(' . (int)$length . ')'; - $order = $orders[$key] ?? ''; - $attribute = $this->filter($attribute); + $order = $index['orders'][$key] ?? ''; + + $attributeName = $attribute->getId(); + if($attributeName === '$id')$attributeName = '_uid'; + if($attributeName === '$createdAt')$attributeName = '_createdAt'; + if($attributeName === '$updatedAt')$attributeName = '_updatedAt'; + + $attributeName = $this->filter($attributeName); if (Database::INDEX_FULLTEXT === $type) { $order = ''; } - $attributes[$key] = "`{$attribute}`{$length} {$order}"; + $attributes[$key] = "`{$attributeName}`{$length} {$order}"; } return $this->getPDO() @@ -1861,23 +1880,12 @@ protected function getSQLTable(string $name): string */ protected function getPDOType(mixed $value): int { - switch (gettype($value)) { - case 'double': - case 'string': - return PDO::PARAM_STR; - - case 'integer': - case 'boolean': - return PDO::PARAM_INT; - - //case 'float': // (for historical reasons "double" is returned in case of a float, and not simply "float") - - case 'NULL': - return PDO::PARAM_NULL; - - default: - throw new Exception('Unknown PDO Type for ' . gettype($value)); - } + return match (gettype($value)) { + 'double', 'string' => PDO::PARAM_STR, + 'integer', 'boolean' => PDO::PARAM_INT, + 'NULL' => PDO::PARAM_NULL, + default => throw new Exception('Unknown PDO Type for ' . gettype($value)), + }; } /** @@ -1904,26 +1912,6 @@ public static function getPDOAttributes(): array ]; } - /** - * Return the maximum index length per attribute type - * @param int $size - * @param Document $attribute - * @return int - */ - public function getDefaultIndexSize(int $size, Document $attribute): int - { - $maxIndexLength = 760; - - if($attribute['type'] === Database::VAR_STRING){ - if($attribute['size'] > $maxIndexLength){ - $size = $size === 0 || $size > $maxIndexLength ? $maxIndexLength : $size; - } - } - - return $size; - } - - /** * This function fixes indexes which has exceeded max default limits * with comparing the length of the string length of the collection attribute @@ -1934,24 +1922,6 @@ public function getDefaultIndexSize(int $size, Document $attribute): int * @throws Exception */ public function fixIndex(Document $index, array $attributes): Document { - foreach ($index->getAttribute('attributes') as $key => $indexAttribute) { - - //Internal attributes do not have a real attribute - if(in_array($indexAttribute, ['$id', '$createdAt', '$updatedAt'])){ - continue; - } - - $attribute = $this->findAttributeInList($indexAttribute, $attributes); - - $size = $index['lengths'][$key] ?? 0; - $max = 768; // 3072 divided by utf8mb4 - if($attribute['type'] === Database::VAR_STRING){ - if($attribute['size'] > $max){ - $index['lengths'][$key] = $size === 0 || $size > $max ? $max : $size; - } - } - } - return $index; } diff --git a/src/Database/Adapter/MySQL.php b/src/Database/Adapter/MySQL.php index 7d5852b81..d84874a5f 100644 --- a/src/Database/Adapter/MySQL.php +++ b/src/Database/Adapter/MySQL.php @@ -4,6 +4,7 @@ use Exception; use Utopia\Database\Database; +use Utopia\Database\Document; class MySQL extends MariaDB { @@ -49,13 +50,36 @@ protected function getSQLIndex(string $collection, string $id, string $type, arr } /** - * Get Maximum Length permitted for index + * This function fixes indexes which has exceeded max default limits + * with comparing the length of the string length of the collection attribute * - * @return int + * @param Document $index + * @param Document[] $attributes + * @return Document + * @throws Exception */ - public function getLimitForIndexLength(): int - { - return 768; + public function fixIndex(Document $index, array $attributes): Document { + + $max = 768; // 3072 divided by utf8mb4 + + foreach ($attributes as $key => $attribute){ + + //Internal attributes do not have a real attribute +// if(in_array($attribute->getId(), ['$id', '$createdAt', '$updatedAt'])){ +// continue; +// } + + $size = $index['lengths'][$key] ?? 0; + + if($attribute['type'] === Database::VAR_STRING){ + if($attribute['size'] > $max){ + $index['lengths'][$key] = $size === 0 || $size > $max ? $max : $size; + } + } + + } + + return $index; } } diff --git a/src/Database/Adapter/SQLite.php b/src/Database/Adapter/SQLite.php index 03d12e8af..e4c88c625 100644 --- a/src/Database/Adapter/SQLite.php +++ b/src/Database/Adapter/SQLite.php @@ -26,6 +26,43 @@ */ class SQLite extends MySQL { + + /** + * List of permission attributes + * @var array + */ + + + protected static array $permissionAttributes = [ + [ + '$id' => '_document', + 'type' => Database::VAR_STRING, + 'size' => 12, + 'required' => true, + 'signed' => true, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => '_type', + 'type' => Database::VAR_STRING, + 'size' => Database::LENGTH_KEY, + 'required' => true, + 'signed' => true, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => '_permission', + 'type' => Database::VAR_STRING, + 'size' => Database::LENGTH_KEY, + 'required' => true, + 'signed' => true, + 'array' => false, + 'filters' => [], + ] + ]; + /** * Check if Database exists * Optionally check if collection exists in Database @@ -99,8 +136,9 @@ public function createCollection(string $name, array $attributes = [], array $in $id = $this->filter($name); $this->getPDO()->beginTransaction(); + $schemaAttributes = []; - foreach ($attributes as $key => $attribute) { + foreach ($attributes as $attribute) { $attrId = $this->filter($attribute->getId()); $attrType = $this->getSQLType($attribute->getAttribute('type'), $attribute->getAttribute('size', 0), $attribute->getAttribute('signed', true)); @@ -108,7 +146,7 @@ public function createCollection(string $name, array $attributes = [], array $in $attrType = 'LONGTEXT'; } - $attributes[$key] = "`{$attrId}` {$attrType}, "; + $schemaAttributes[] = "`{$attrId}` {$attrType}, "; } $this->getPDO() @@ -117,19 +155,24 @@ public function createCollection(string $name, array $attributes = [], array $in `_uid` CHAR(255) NOT NULL, `_createdAt` datetime(3) DEFAULT NULL, `_updatedAt` datetime(3) DEFAULT NULL, - `_permissions` MEDIUMTEXT DEFAULT NULL".((!empty($attributes)) ? ',' : '')." - " . substr(\implode(' ', $attributes), 0, -2) . " + `_permissions` MEDIUMTEXT DEFAULT NULL".((!empty($schemaAttributes)) ? ',' : '')." + " . substr(\implode(' ', $schemaAttributes), 0, -2) . " )") ->execute(); - $this->createIndex($id, '_index1', Database::INDEX_UNIQUE, ['_uid'], [], []); - $this->createIndex($id, '_created_at', Database::INDEX_KEY, ['_createdAt'], [], []); - $this->createIndex($id, '_updated_at', Database::INDEX_KEY, ['_updatedAt'], [], []); + $this->createIndex($id, '_index1', Database::INDEX_UNIQUE, Database::filterIndexAttributes(['$id'], $attributes), [], []); + $this->createIndex($id, '_created_at', Database::INDEX_KEY, Database::filterIndexAttributes(['$createdAt'], $attributes), [], []); + $this->createIndex($id, '_updated_at', Database::INDEX_KEY, Database::filterIndexAttributes(['$updatedAt'], $attributes), [], []); - foreach ($indexes as $key => $index) { + foreach ($indexes as $index) { $indexId = $this->filter($index->getId()); $indexType = $index->getAttribute('type'); - $indexAttributes = $index->getAttribute('attributes', []); + + $indexAttributes = Database::filterIndexAttributes( + $index->getAttribute('attributes'), + $attributes + ); + $indexLengths = $index->getAttribute('lengths', []); $indexOrders = $index->getAttribute('orders', []); @@ -148,9 +191,17 @@ public function createCollection(string $name, array $attributes = [], array $in } catch (\Throwable $th) { var_dump($th->getMessage()); } - - $this->createIndex("{$id}_perms", '_index_1', Database::INDEX_UNIQUE, ['_document', '_type', '_permission'], [], []); - $this->createIndex("{$id}_perms", '_index_2', Database::INDEX_KEY, ['_permission'], [], []); + + $permissionAttributes = array_map( + fn ($attribute) => new Document($attribute), + self::$permissionAttributes + ); + + $attributes = Database::filterIndexAttributes(['_document', '_type', '_permission'], $permissionAttributes); + $this->createIndex("{$id}_perms", '_index_1', Database::INDEX_UNIQUE, $attributes, [], []); + + $attributes = Database::filterIndexAttributes(['_permission'], $permissionAttributes); + $this->createIndex("{$id}_perms", '_index_2', Database::INDEX_KEY, $attributes, [], []); $this->getPDO()->commit(); @@ -212,9 +263,17 @@ public function updateAttribute(string $collection, string $id, string $type, in * @throws Exception * @throws PDOException */ - public function renameIndex(string $collection, string $old, string $new): bool + public function renameIndex(string $collectionName, string $old, string $new): bool { - $collection = $this->filter($collection); + $collection = $this->getCollection($collectionName); + if($collection->isEmpty()){ + throw new Exception('Collection ' . $collectionName . ' Not found'); + } + + // attribute IDs are case insensitive + $attributes = $collection->getAttribute('attributes', []); + + $collectionDocument = $this->getDocument(Database::METADATA, $collection); $old = $this->filter($old); $new = $this->filter($new); @@ -228,12 +287,17 @@ public function renameIndex(string $collection, string $old, string $new): bool } } + $attributes = Database::filterIndexAttributes( + $index['attributes'], + $collection->getAttribute('attributes', []) + ); + if ($index && $this->deleteIndex($collection, $old) && $this->createIndex( $collection, $new, $index['type'], - $index['attributes'], + $attributes, $index['lengths'], $index['orders'], )) { @@ -638,23 +702,25 @@ protected function getSQLIndex(string $collection, string $id, string $type, ar default: throw new Exception('Unknown Index Type:' . $type); - break; } - $attributes = \array_map(fn ($attribute) => match ($attribute) { - '$id' => ID::custom('_uid'), - '$createdAt' => '_createdAt', - '$updatedAt' => '_updatedAt', - default => $attribute - }, $attributes); - foreach ($attributes as $key => $attribute) { - $length = $lengths[$key] ?? ''; + $length = $index['lengths'][$key] ?? ''; $length = (empty($length)) ? '' : '(' . (int)$length . ')'; - $order = $orders[$key] ?? ''; - $attribute = $this->filter($attribute); + $order = $index['orders'][$key] ?? ''; + + $attributeName = $attribute->getId(); + if($attributeName === '$id')$attributeName = '_uid'; + if($attributeName === '$createdAt')$attributeName = '_createdAt'; + if($attributeName === '$updatedAt')$attributeName = '_updatedAt'; + + $attributeName = $this->filter($attributeName); + + if (Database::INDEX_FULLTEXT === $type) { + $order = ''; + } - $attributes[$key] = "`{$attribute}`{$postfix} {$order}"; + $attributes[$key] = "`{$attributeName}`{$postfix} {$order}"; } return "CREATE {$type} `{$this->getNamespace()}_{$collection}_{$id}` ON `{$this->getNamespace()}_{$collection}` ( " . implode(', ', $attributes) . ")"; diff --git a/src/Database/Database.php b/src/Database/Database.php index 6249339a3..b9e61d545 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5,10 +5,10 @@ use Exception; use Throwable; use Utopia\Database\Exception\Duplicate; +use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Structure; use Utopia\Database\Exception\Authorization as AuthorizationException; -use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\Structure as StructureException; use Utopia\Cache\Cache; @@ -118,7 +118,7 @@ class Database * List of Internal Ids * @var array */ - protected array $attributes = [ + protected static array $attributes = [ [ '$id' => '$id', 'type' => self::VAR_STRING, @@ -431,6 +431,7 @@ public function ping(): bool * @param string $name * * @return bool + * @throws Exception|Throwable */ public function create(string $name): bool { @@ -439,7 +440,6 @@ public function create(string $name): bool /** * Create array of attribute documents - * @var Document[] $attributes */ $attributes = array_map(function ($attribute) { return new Document([ @@ -518,9 +518,9 @@ public function createCollection(string $id, array $attributes = [], array $inde throw new Duplicate('Collection ' . $id . ' Exists!'); } - foreach ($indexes as $key => $index){ - $indexes[$key] = $this->adapter->fixIndex($index, $attributes); - } +// foreach ($indexes as $key => $index){ +// $indexes[$key] = $this->adapter->fixIndex($index, $attributes); +// } $this->adapter->createCollection($id, $attributes, $indexes); @@ -630,19 +630,22 @@ public function deleteCollection(string $id): bool /** * Create Attribute * - * @param string $collection + * @param string $collectionName * @param string $id * @param string $type * @param int $size utf8mb4 chars length * @param bool $required - * @param array|bool|callable|int|float|object|resource|string|null $default + * @param null $default * @param bool $signed * @param bool $array - * @param string $format optional validation format of attribute - * @param string $formatOptions assoc array with custom options that can be passed for the format validation + * @param string|null $format optional validation format of attribute + * @param array $formatOptions assoc array with custom options that can be passed for the format validation * @param array $filters * * @return bool + * @throws DuplicateException + * @throws LimitException + * @throws Throwable */ public function createAttribute(string $collectionName, string $id, string $type, int $size, bool $required, $default = null, bool $signed = true, bool $array = false, string $format = null, array $formatOptions = [], array $filters = []): bool { @@ -1259,7 +1262,10 @@ public function createIndex(string $collectionName, string $id, string $type, ar 'orders' => $orders, ]); - $index = $this->adapter->fixIndex($index, $collection->getAttribute('attributes', [])); + $attributes = $this->filterIndexAttributes( + $attributes, + $collection->getAttribute('attributes', []) + ); $result = $this->adapter->createIndex( $collection->getId(), @@ -1280,6 +1286,31 @@ public function createIndex(string $collectionName, string $id, string $type, ar return $result; } + + /** + * Filter collection attributes by index attributes names + * + * @param array $indexAttributes + * @param array $attributes Documents[] + * @return array + * @throws Exception + */ + public static function filterIndexAttributes(array $indexAttributes, array $attributes): array + { + $internals = array_map( + fn ($attribute) => new Document($attribute), + self::$attributes + ); + + $attributes = array_filter( + array_merge($internals, $attributes), + fn ($attribute) => in_array($attribute->getId(), $indexAttributes) + ); + + return array_values($attributes); + } + + /** * Delete Index * @@ -1668,7 +1699,7 @@ static public function addFilter(string $name, callable $encode, callable $decod public function getInternalAttributes(): array { $attributes = []; - foreach ($this->attributes as $internal){ + foreach (self::$attributes as $internal){ $attributes[] = new Document($internal); } return $attributes; diff --git a/tests/Database/Adapter/MongoDBTest.php b/tests/Database/Adapter/MongoDBTest.php index 513a9471a..c02882a8e 100644 --- a/tests/Database/Adapter/MongoDBTest.php +++ b/tests/Database/Adapter/MongoDBTest.php @@ -1,380 +1,380 @@ connect('redis', 6379); - $redis->flushAll(); - $cache = new Cache(new RedisAdapter($redis)); - - $options = new MongoClientOptions( - 'utopia_testing', - 'mongo', - 27017, - 'root', - 'example' - ); - - $client = new MongoClient($options, false); - - $database = new Database(new MongoDBAdapter($client), $cache); - $database->setDefaultDatabase('utopiaTests'); - $database->setNamespace('myapp_' . uniqid()); - - - return self::$database = $database; - } - - public function testCreateExistsDelete() - { - $this->assertNotNull(static::getDatabase()->create($this->testDatabase)); - - $this->assertEquals(true, static::getDatabase()->exists($this->testDatabase)); - $this->assertEquals(true, static::getDatabase()->delete($this->testDatabase)); - - // Mongo creates on the fly, so this will never be true, do we want to try to make it pass - // by doing something else? - // $this->assertEquals(false, static::getDatabase()->exists($this->testDatabase)); - // $this->assertEquals(true, static::getDatabase()->create($this->testDatabase)); - // $this->assertEquals(true, static::getDatabase()->setDefaultDatabase($this->testDatabase)); - } - - /** - * @depends testCreateDocument - */ - public function testListDocumentSearch(Document $document) - { - static::getDatabase()->createIndex('documents', 'string', Database::INDEX_FULLTEXT, ['string']); - static::getDatabase()->createDocument('documents', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - 'string' => '*test+alias@email-provider.com', - 'integer' => 0, - 'bigint' => 8589934592, // 2^33 - 'float' => 5.55, - 'boolean' => true, - 'colors' => ['pink', 'green', 'blue'], - 'empty' => [], - ])); - - $documents = static::getDatabase()->find('documents', [ - Query::search('string', '*test+alias@email-provider.com') - ]); - - $this->assertEquals(1, count($documents)); - - return $document; - } - - /** - * @depends testUpdateDocument - */ - public function testFind(Document $document) - { - static::getDatabase()->createCollection('movies'); - - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'name', Database::VAR_STRING, 128, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'director', Database::VAR_STRING, 128, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true)); - $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, null, true, true)); - - static::getDatabase()->createDocument('movies', new Document([ - '$id' => ID::custom('frozen'), - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Frozen', - 'director' => 'Chris Buck & Jennifer Lee', - 'year' => 2013, - 'price' => 39.50, - 'active' => true, - 'generes' => ['animation', 'kids'], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Frozen II', - 'director' => 'Chris Buck & Jennifer Lee', - 'year' => 2019, - 'price' => 39.50, - 'active' => true, - 'generes' => ['animation', 'kids'], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Captain America: The First Avenger', - 'director' => 'Joe Johnston', - 'year' => 2011, - 'price' => 25.94, - 'active' => true, - 'generes' => ['science fiction', 'action', 'comics'], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Captain Marvel', - 'director' => 'Anna Boden & Ryan Fleck', - 'year' => 2019, - 'price' => 25.99, - 'active' => true, - 'generes' => ['science fiction', 'action', 'comics'], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::any()), - Permission::read(Role::user(ID::custom('1'))), - Permission::read(Role::user(ID::custom('2'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Work in Progress', - 'director' => 'TBD', - 'year' => 2025, - 'price' => 0.0, - 'active' => false, - 'generes' => [], - ])); - - static::getDatabase()->createDocument('movies', new Document([ - '$permissions' => [ - Permission::read(Role::user(ID::custom('x'))), - Permission::create(Role::any()), - Permission::create(Role::user(ID::custom('1x'))), - Permission::create(Role::user(ID::custom('2x'))), - Permission::update(Role::any()), - Permission::update(Role::user(ID::custom('1x'))), - Permission::update(Role::user(ID::custom('2x'))), - Permission::delete(Role::any()), - Permission::delete(Role::user(ID::custom('1x'))), - Permission::delete(Role::user(ID::custom('2x'))), - ], - 'name' => 'Work in Progress 2', - 'director' => 'TBD', - 'year' => 2026, - 'price' => 0.0, - 'active' => false, - 'generes' => [], - ])); - - /** - * Check Basic - */ - $documents = static::getDatabase()->count('movies'); - - $this->assertEquals(5, $documents); - } - - /** - * @depends testCreateExistsDelete - */ - public function testCreateListExistsDeleteCollection() - { - $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors')); - - $this->assertCount(1, static::getDatabase()->listCollections()); - $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); - - // Collection names should not be unique - $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors2')); - $this->assertCount(2, static::getDatabase()->listCollections()); - $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors2')); - $collection = static::getDatabase()->getCollection('actors2'); - $collection->setAttribute('name', 'actors'); // change name to one that exists - - $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->updateDocument($collection->getCollection(), $collection->getId(), $collection)); - $this->assertEquals(true, static::getDatabase()->deleteCollection('actors2')); // Delete collection when finished - $this->assertCount(1, static::getDatabase()->listCollections()); - - $this->assertEquals(false, static::getDatabase()->getCollection('actors')->isEmpty()); - $this->assertEquals(true, static::getDatabase()->deleteCollection('actors')); - $this->assertEquals(true, static::getDatabase()->getCollection('actors')->isEmpty()); - - $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); - } - - /** - * @depends testFind - */ - public function testCount() - { - $count = static::getDatabase()->count('movies'); - $this->assertEquals(5, $count); - - $count = static::getDatabase()->count('movies', [new Query(Query::TYPE_EQUAL, 'year', [2019]),]); - $this->assertEquals(2, $count); - - Authorization::unsetRole('userx'); - $count = static::getDatabase()->count('movies'); - $this->assertEquals(5, $count); - - Authorization::disable(); - $count = static::getDatabase()->count('movies'); - $this->assertEquals(6, $count); - Authorization::reset(); - - Authorization::disable(); - $count = static::getDatabase()->count('movies', [], 3); - $this->assertEquals(3, $count); - Authorization::reset(); - - /** - * Test that OR queries are handled correctly - */ - Authorization::disable(); - $count = static::getDatabase()->count('movies', [ - new Query(Query::TYPE_EQUAL, 'director', ['TBD', 'Joe Johnston']), - new Query(Query::TYPE_EQUAL, 'year', [2025]), - ]); - $this->assertEquals(1, $count); - Authorization::reset(); - } - - public function testRenameAttribute() - { - $this->assertTrue(true); - } - - public function testRenameAttributeExisting() - { - $this->assertTrue(true); - } - - public function testUpdateAttributeStructure() - { - $this->assertTrue(true); - } - - /** - * Ensure the collection is removed after use - * - * @depends testIndexCaseInsensitivity - */ - public function testCleanupAttributeTests() - { - $res = static::getDatabase()->deleteCollection('attributes'); - - $this->assertEquals(true, $res); - } -} +// +//namespace Utopia\Tests\Adapter; +// +//use Redis; +//use Utopia\Cache\Cache; +//use Utopia\Cache\Adapter\Redis as RedisAdapter; +//use Utopia\Database\Database; +//use Utopia\Database\Document; +//use Utopia\Database\Adapter\Mongo\MongoClient; +//use Utopia\Database\Adapter\Mongo\MongoClientOptions; +//use Utopia\Database\Adapter\Mongo\MongoDBAdapter; +//use Utopia\Database\ID; +//use Utopia\Database\Permission; +//use Utopia\Database\Query; +//use Utopia\Database\Role; +//use Utopia\Database\Validator\Authorization; +// +//use Utopia\Tests\Base; +// +//class MongoDBTest extends Base +//{ +// static $pool = null; +// +// /** +// * @var Database +// */ +// static $database = null; +// +// +// // TODO@kodumbeats hacky way to identify adapters for tests +// // Remove once all methods are implemented +// /** +// * Return name of adapter +// * +// * @return string +// */ +// static function getAdapterName(): string +// { +// return "mongodb"; +// } +// +// /** +// * Return row limit of adapter +// * +// * @return int +// */ +// static function getAdapterRowLimit(): int +// { +// return 0; +// } +// +// /** +// * @return Database +// */ +// static function getDatabase(): Database +// { +// if (!is_null(self::$database)) { +// return self::$database; +// } +// +// $redis = new Redis(); +// $redis->connect('redis', 6379); +// $redis->flushAll(); +// $cache = new Cache(new RedisAdapter($redis)); +// +// $options = new MongoClientOptions( +// 'utopia_testing', +// 'mongo', +// 27017, +// 'root', +// 'example' +// ); +// +// $client = new MongoClient($options, false); +// +// $database = new Database(new MongoDBAdapter($client), $cache); +// $database->setDefaultDatabase('utopiaTests'); +// $database->setNamespace('myapp_' . uniqid()); +// +// +// return self::$database = $database; +// } +// +// public function testCreateExistsDelete() +// { +// $this->assertNotNull(static::getDatabase()->create($this->testDatabase)); +// +// $this->assertEquals(true, static::getDatabase()->exists($this->testDatabase)); +// $this->assertEquals(true, static::getDatabase()->delete($this->testDatabase)); +// +// // Mongo creates on the fly, so this will never be true, do we want to try to make it pass +// // by doing something else? +// // $this->assertEquals(false, static::getDatabase()->exists($this->testDatabase)); +// // $this->assertEquals(true, static::getDatabase()->create($this->testDatabase)); +// // $this->assertEquals(true, static::getDatabase()->setDefaultDatabase($this->testDatabase)); +// } +// +// /** +// * @depends testCreateDocument +// */ +// public function testListDocumentSearch(Document $document) +// { +// static::getDatabase()->createIndex('documents', 'string', Database::INDEX_FULLTEXT, ['string']); +// static::getDatabase()->createDocument('documents', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::create(Role::any()), +// Permission::update(Role::any()), +// Permission::delete(Role::any()), +// ], +// 'string' => '*test+alias@email-provider.com', +// 'integer' => 0, +// 'bigint' => 8589934592, // 2^33 +// 'float' => 5.55, +// 'boolean' => true, +// 'colors' => ['pink', 'green', 'blue'], +// 'empty' => [], +// ])); +// +// $documents = static::getDatabase()->find('documents', [ +// Query::search('string', '*test+alias@email-provider.com') +// ]); +// +// $this->assertEquals(1, count($documents)); +// +// return $document; +// } +// +// /** +// * @depends testUpdateDocument +// */ +// public function testFind(Document $document) +// { +// static::getDatabase()->createCollection('movies'); +// +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'name', Database::VAR_STRING, 128, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'director', Database::VAR_STRING, 128, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true)); +// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, null, true, true)); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$id' => ID::custom('frozen'), +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Frozen', +// 'director' => 'Chris Buck & Jennifer Lee', +// 'year' => 2013, +// 'price' => 39.50, +// 'active' => true, +// 'generes' => ['animation', 'kids'], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Frozen II', +// 'director' => 'Chris Buck & Jennifer Lee', +// 'year' => 2019, +// 'price' => 39.50, +// 'active' => true, +// 'generes' => ['animation', 'kids'], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Captain America: The First Avenger', +// 'director' => 'Joe Johnston', +// 'year' => 2011, +// 'price' => 25.94, +// 'active' => true, +// 'generes' => ['science fiction', 'action', 'comics'], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Captain Marvel', +// 'director' => 'Anna Boden & Ryan Fleck', +// 'year' => 2019, +// 'price' => 25.99, +// 'active' => true, +// 'generes' => ['science fiction', 'action', 'comics'], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::any()), +// Permission::read(Role::user(ID::custom('1'))), +// Permission::read(Role::user(ID::custom('2'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Work in Progress', +// 'director' => 'TBD', +// 'year' => 2025, +// 'price' => 0.0, +// 'active' => false, +// 'generes' => [], +// ])); +// +// static::getDatabase()->createDocument('movies', new Document([ +// '$permissions' => [ +// Permission::read(Role::user(ID::custom('x'))), +// Permission::create(Role::any()), +// Permission::create(Role::user(ID::custom('1x'))), +// Permission::create(Role::user(ID::custom('2x'))), +// Permission::update(Role::any()), +// Permission::update(Role::user(ID::custom('1x'))), +// Permission::update(Role::user(ID::custom('2x'))), +// Permission::delete(Role::any()), +// Permission::delete(Role::user(ID::custom('1x'))), +// Permission::delete(Role::user(ID::custom('2x'))), +// ], +// 'name' => 'Work in Progress 2', +// 'director' => 'TBD', +// 'year' => 2026, +// 'price' => 0.0, +// 'active' => false, +// 'generes' => [], +// ])); +// +// /** +// * Check Basic +// */ +// $documents = static::getDatabase()->count('movies'); +// +// $this->assertEquals(5, $documents); +// } +// +// /** +// * @depends testCreateExistsDelete +// */ +// public function testCreateListExistsDeleteCollection() +// { +// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors')); +// +// $this->assertCount(1, static::getDatabase()->listCollections()); +// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); +// +// // Collection names should not be unique +// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors2')); +// $this->assertCount(2, static::getDatabase()->listCollections()); +// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors2')); +// $collection = static::getDatabase()->getCollection('actors2'); +// $collection->setAttribute('name', 'actors'); // change name to one that exists +// +// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->updateDocument($collection->getCollection(), $collection->getId(), $collection)); +// $this->assertEquals(true, static::getDatabase()->deleteCollection('actors2')); // Delete collection when finished +// $this->assertCount(1, static::getDatabase()->listCollections()); +// +// $this->assertEquals(false, static::getDatabase()->getCollection('actors')->isEmpty()); +// $this->assertEquals(true, static::getDatabase()->deleteCollection('actors')); +// $this->assertEquals(true, static::getDatabase()->getCollection('actors')->isEmpty()); +// +// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); +// } +// +// /** +// * @depends testFind +// */ +// public function testCount() +// { +// $count = static::getDatabase()->count('movies'); +// $this->assertEquals(5, $count); +// +// $count = static::getDatabase()->count('movies', [new Query(Query::TYPE_EQUAL, 'year', [2019]),]); +// $this->assertEquals(2, $count); +// +// Authorization::unsetRole('userx'); +// $count = static::getDatabase()->count('movies'); +// $this->assertEquals(5, $count); +// +// Authorization::disable(); +// $count = static::getDatabase()->count('movies'); +// $this->assertEquals(6, $count); +// Authorization::reset(); +// +// Authorization::disable(); +// $count = static::getDatabase()->count('movies', [], 3); +// $this->assertEquals(3, $count); +// Authorization::reset(); +// +// /** +// * Test that OR queries are handled correctly +// */ +// Authorization::disable(); +// $count = static::getDatabase()->count('movies', [ +// new Query(Query::TYPE_EQUAL, 'director', ['TBD', 'Joe Johnston']), +// new Query(Query::TYPE_EQUAL, 'year', [2025]), +// ]); +// $this->assertEquals(1, $count); +// Authorization::reset(); +// } +// +// public function testRenameAttribute() +// { +// $this->assertTrue(true); +// } +// +// public function testRenameAttributeExisting() +// { +// $this->assertTrue(true); +// } +// +// public function testUpdateAttributeStructure() +// { +// $this->assertTrue(true); +// } +// +// /** +// * Ensure the collection is removed after use +// * +// * @depends testIndexCaseInsensitivity +// */ +// public function testCleanupAttributeTests() +// { +// $res = static::getDatabase()->deleteCollection('attributes'); +// +// $this->assertEquals(true, $res); +// } +//} diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index 4b6bff94ea6b88ad386d82415f070ac26bd656be..ffea83273614076a8952ae981b2fc5b757928c96 100644 GIT binary patch delta 27620 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 PG~9pWyshE^#<~9qF&|DI From 44b4eff05679e400c7e9b2c5256063a9cc4d04a9 Mon Sep 17 00:00:00 2001 From: fogelito Date: Wed, 26 Oct 2022 13:49:35 +0300 Subject: [PATCH 20/21] some fixes --- src/Database/Adapter/MariaDB.php | 37 +- src/Database/Adapter/Mongo/MongoDBAdapter.php | 2 +- src/Database/Adapter/SQLite.php | 27 +- src/Database/Database.php | 27 +- tests/Database/Adapter/MongoDBTest.php | 758 +++++++++--------- tests/Database/Adapter/database.sql | Bin 1081344 -> 1212416 bytes tests/Database/Base.php | 2 +- 7 files changed, 430 insertions(+), 423 deletions(-) diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 999406e09..fb7714404 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -108,7 +108,7 @@ public function exists(string $database, ?string $collection): bool /** * List Databases - * + * * @return array */ public function list(): array @@ -150,6 +150,9 @@ public function createCollection(string $name, array $attributes = [], array $in $id = $this->filter($name); $schemaAttributes = []; + /* + * Loop though the collection attributes for creation of attributes in schema + * */ foreach ($attributes as $attribute) { $attrId = $this->filter($attribute->getId()); $size = $attribute->getAttribute('size', 0); @@ -164,6 +167,9 @@ public function createCollection(string $name, array $attributes = [], array $in $schemaAttributes[] = "`{$attrId}` {$attrType}, "; } + /* + * Loop though the collection indexes for creation of indexes in schema + * */ $schemaIndexes = []; foreach ($indexes as $key => $index) { @@ -376,7 +382,7 @@ public function deleteAttribute(string $collection, string $id, bool $array = fa * @param string $collection * @param string $id * @param string $type - * @param array $attributes + * @param array $attributes Document[] * @param array $lengths * @param array $orders * @return bool @@ -404,6 +410,7 @@ public function createIndex(string $collection, string $id, string $type, array $order = $index['orders'][$key] ?? ''; $attributeName = $attribute->getId(); + // todo : make a function for this... if($attributeName === '$id')$attributeName = '_uid'; if($attributeName === '$createdAt')$attributeName = '_createdAt'; if($attributeName === '$updatedAt')$attributeName = '_updatedAt'; @@ -1179,7 +1186,7 @@ public function getSupportForSchemas(): bool { return true; } - + /** * Is index supported? * @@ -1245,7 +1252,7 @@ public static function getCountOfDefaultAttributes(): int { return 4; } - + /** * Returns number of indexes used by default. * @@ -1355,7 +1362,7 @@ public function getAttributeWidth(Document $collection): int /** * Get list of keywords that cannot be used * Refference: https://mariadb.com/kb/en/reserved-words/ - * + * * @return string[] */ public function getKeywords(): array @@ -1830,10 +1837,10 @@ protected function getSQLIndex(string $collection, string $id, string $type, ar /** * Get SQL condition for permissions * - * @param string $collection - * @param array $roles - * @return string - * @throws Exception + * @param string $collection + * @param array $roles + * @return string + * @throws Exception */ protected function getSQLPermissionsCondition(string $collection, array $roles): string { @@ -1849,7 +1856,7 @@ protected function getSQLPermissionsCondition(string $collection, array $roles): /** * Get SQL schema * - * @return string + * @return string */ protected function getSQLSchema(): string { @@ -1863,8 +1870,8 @@ protected function getSQLSchema(): string /** * Get SQL table * - * @param string $name - * @return string + * @param string $name + * @return string */ protected function getSQLTable(string $name): string { @@ -1876,7 +1883,7 @@ protected function getSQLTable(string $name): string * * @param mixed $value * @return int - * @throws Exception + * @throws Exception */ protected function getPDOType(mixed $value): int { @@ -1890,7 +1897,7 @@ protected function getPDOType(mixed $value): int /** * Returns the current PDO object - * @return PDO + * @return PDO */ protected function getPDO() { @@ -1925,5 +1932,5 @@ public function fixIndex(Document $index, array $attributes): Document { return $index; } - + } diff --git a/src/Database/Adapter/Mongo/MongoDBAdapter.php b/src/Database/Adapter/Mongo/MongoDBAdapter.php index 9e8fde2c2..5f07be67b 100644 --- a/src/Database/Adapter/Mongo/MongoDBAdapter.php +++ b/src/Database/Adapter/Mongo/MongoDBAdapter.php @@ -287,7 +287,7 @@ public function renameAttribute(string $collection, string $id, string $name): b * @param string $collection * @param string $id * @param string $type - * @param array $attributes + * @param array $attributes Document[] * @param array $lengths * @param array $orders * diff --git a/src/Database/Adapter/SQLite.php b/src/Database/Adapter/SQLite.php index e4c88c625..67d194aff 100644 --- a/src/Database/Adapter/SQLite.php +++ b/src/Database/Adapter/SQLite.php @@ -7,7 +7,6 @@ use PDOException; use Utopia\Database\Database; use Utopia\Database\Document; -use Utopia\Database\ID; use Utopia\Database\Exception\Duplicate; /** @@ -24,7 +23,7 @@ * 9. MODIFY COLUMN is not supported * 10. Can't rename an index directly */ -class SQLite extends MySQL +class SQLite extends MariaDB { /** @@ -192,10 +191,7 @@ public function createCollection(string $name, array $attributes = [], array $in var_dump($th->getMessage()); } - $permissionAttributes = array_map( - fn ($attribute) => new Document($attribute), - self::$permissionAttributes - ); + $permissionAttributes = Database::changeArrayToDocuments(self::$permissionAttributes); $attributes = Database::filterIndexAttributes(['_document', '_type', '_permission'], $permissionAttributes); $this->createIndex("{$id}_perms", '_index_1', Database::INDEX_UNIQUE, $attributes, [], []); @@ -263,18 +259,10 @@ public function updateAttribute(string $collection, string $id, string $type, in * @throws Exception * @throws PDOException */ - public function renameIndex(string $collectionName, string $old, string $new): bool + public function renameIndex(string $collection, string $old, string $new): bool { - $collection = $this->getCollection($collectionName); - if($collection->isEmpty()){ - throw new Exception('Collection ' . $collectionName . ' Not found'); - } - - // attribute IDs are case insensitive - $attributes = $collection->getAttribute('attributes', []); - - $collectionDocument = $this->getDocument(Database::METADATA, $collection); + $old = $this->filter($old); $new = $this->filter($new); $indexs = json_decode($collectionDocument['indexes'], true); @@ -287,9 +275,11 @@ public function renameIndex(string $collectionName, string $old, string $new): b } } + $attributes = json_decode($collectionDocument['attributes'], true); + $attributes = Database::changeArrayToDocuments($attributes); $attributes = Database::filterIndexAttributes( $index['attributes'], - $collection->getAttribute('attributes', []) + $attributes ); if ($index && $this->deleteIndex($collection, $old) @@ -313,7 +303,7 @@ public function renameIndex(string $collectionName, string $old, string $new): b * @param string $collection * @param string $id * @param string $type - * @param array $attributes + * @param array $attributes Document[] * @param array $lengths * @param array $orders * @return bool @@ -710,6 +700,7 @@ protected function getSQLIndex(string $collection, string $id, string $type, ar $order = $index['orders'][$key] ?? ''; $attributeName = $attribute->getId(); + // todo : make a function for this... if($attributeName === '$id')$attributeName = '_uid'; if($attributeName === '$createdAt')$attributeName = '_createdAt'; if($attributeName === '$updatedAt')$attributeName = '_updatedAt'; diff --git a/src/Database/Database.php b/src/Database/Database.php index b9e61d545..1e0f7674a 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -518,10 +518,6 @@ public function createCollection(string $id, array $attributes = [], array $inde throw new Duplicate('Collection ' . $id . ' Exists!'); } -// foreach ($indexes as $key => $index){ -// $indexes[$key] = $this->adapter->fixIndex($index, $attributes); -// } - $this->adapter->createCollection($id, $attributes, $indexes); if ($id === self::METADATA) { @@ -1068,6 +1064,7 @@ public function deleteAttribute(string $collection, string $id): bool } } + $attributes = array_values($attributes); $collection->setAttribute('attributes', $attributes); if ($collection->getId() !== self::METADATA) { @@ -1337,6 +1334,7 @@ public function deleteIndex(string $collectionName, string $id): bool } } + $indexes = array_values($indexes); $collection->setAttribute('indexes', $indexes); if ($collection->getId() !== self::METADATA) { @@ -1698,11 +1696,7 @@ static public function addFilter(string $name, callable $encode, callable $decod */ public function getInternalAttributes(): array { - $attributes = []; - foreach (self::$attributes as $internal){ - $attributes[] = new Document($internal); - } - return $attributes; + return self::changeArrayToDocuments(self::$attributes); } /** @@ -1983,4 +1977,19 @@ public static function convertQueries(Document $collection, array $queries): arr } return $queries; } + + + /** + * @param array $array + * @return Document[] + * @throws Exception + */ + public static function changeArrayToDocuments(array $array): array + { + return array_map( + fn ($attribute) => new Document($attribute), + $array + ); + } + } diff --git a/tests/Database/Adapter/MongoDBTest.php b/tests/Database/Adapter/MongoDBTest.php index c02882a8e..513a9471a 100644 --- a/tests/Database/Adapter/MongoDBTest.php +++ b/tests/Database/Adapter/MongoDBTest.php @@ -1,380 +1,380 @@ connect('redis', 6379); -// $redis->flushAll(); -// $cache = new Cache(new RedisAdapter($redis)); -// -// $options = new MongoClientOptions( -// 'utopia_testing', -// 'mongo', -// 27017, -// 'root', -// 'example' -// ); -// -// $client = new MongoClient($options, false); -// -// $database = new Database(new MongoDBAdapter($client), $cache); -// $database->setDefaultDatabase('utopiaTests'); -// $database->setNamespace('myapp_' . uniqid()); -// -// -// return self::$database = $database; -// } -// -// public function testCreateExistsDelete() -// { -// $this->assertNotNull(static::getDatabase()->create($this->testDatabase)); -// -// $this->assertEquals(true, static::getDatabase()->exists($this->testDatabase)); -// $this->assertEquals(true, static::getDatabase()->delete($this->testDatabase)); -// -// // Mongo creates on the fly, so this will never be true, do we want to try to make it pass -// // by doing something else? -// // $this->assertEquals(false, static::getDatabase()->exists($this->testDatabase)); -// // $this->assertEquals(true, static::getDatabase()->create($this->testDatabase)); -// // $this->assertEquals(true, static::getDatabase()->setDefaultDatabase($this->testDatabase)); -// } -// -// /** -// * @depends testCreateDocument -// */ -// public function testListDocumentSearch(Document $document) -// { -// static::getDatabase()->createIndex('documents', 'string', Database::INDEX_FULLTEXT, ['string']); -// static::getDatabase()->createDocument('documents', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::create(Role::any()), -// Permission::update(Role::any()), -// Permission::delete(Role::any()), -// ], -// 'string' => '*test+alias@email-provider.com', -// 'integer' => 0, -// 'bigint' => 8589934592, // 2^33 -// 'float' => 5.55, -// 'boolean' => true, -// 'colors' => ['pink', 'green', 'blue'], -// 'empty' => [], -// ])); -// -// $documents = static::getDatabase()->find('documents', [ -// Query::search('string', '*test+alias@email-provider.com') -// ]); -// -// $this->assertEquals(1, count($documents)); -// -// return $document; -// } -// -// /** -// * @depends testUpdateDocument -// */ -// public function testFind(Document $document) -// { -// static::getDatabase()->createCollection('movies'); -// -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'name', Database::VAR_STRING, 128, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'director', Database::VAR_STRING, 128, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true)); -// $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, null, true, true)); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$id' => ID::custom('frozen'), -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Frozen', -// 'director' => 'Chris Buck & Jennifer Lee', -// 'year' => 2013, -// 'price' => 39.50, -// 'active' => true, -// 'generes' => ['animation', 'kids'], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Frozen II', -// 'director' => 'Chris Buck & Jennifer Lee', -// 'year' => 2019, -// 'price' => 39.50, -// 'active' => true, -// 'generes' => ['animation', 'kids'], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Captain America: The First Avenger', -// 'director' => 'Joe Johnston', -// 'year' => 2011, -// 'price' => 25.94, -// 'active' => true, -// 'generes' => ['science fiction', 'action', 'comics'], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Captain Marvel', -// 'director' => 'Anna Boden & Ryan Fleck', -// 'year' => 2019, -// 'price' => 25.99, -// 'active' => true, -// 'generes' => ['science fiction', 'action', 'comics'], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::any()), -// Permission::read(Role::user(ID::custom('1'))), -// Permission::read(Role::user(ID::custom('2'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Work in Progress', -// 'director' => 'TBD', -// 'year' => 2025, -// 'price' => 0.0, -// 'active' => false, -// 'generes' => [], -// ])); -// -// static::getDatabase()->createDocument('movies', new Document([ -// '$permissions' => [ -// Permission::read(Role::user(ID::custom('x'))), -// Permission::create(Role::any()), -// Permission::create(Role::user(ID::custom('1x'))), -// Permission::create(Role::user(ID::custom('2x'))), -// Permission::update(Role::any()), -// Permission::update(Role::user(ID::custom('1x'))), -// Permission::update(Role::user(ID::custom('2x'))), -// Permission::delete(Role::any()), -// Permission::delete(Role::user(ID::custom('1x'))), -// Permission::delete(Role::user(ID::custom('2x'))), -// ], -// 'name' => 'Work in Progress 2', -// 'director' => 'TBD', -// 'year' => 2026, -// 'price' => 0.0, -// 'active' => false, -// 'generes' => [], -// ])); -// -// /** -// * Check Basic -// */ -// $documents = static::getDatabase()->count('movies'); -// -// $this->assertEquals(5, $documents); -// } -// -// /** -// * @depends testCreateExistsDelete -// */ -// public function testCreateListExistsDeleteCollection() -// { -// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors')); -// -// $this->assertCount(1, static::getDatabase()->listCollections()); -// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); -// -// // Collection names should not be unique -// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors2')); -// $this->assertCount(2, static::getDatabase()->listCollections()); -// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors2')); -// $collection = static::getDatabase()->getCollection('actors2'); -// $collection->setAttribute('name', 'actors'); // change name to one that exists -// -// $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->updateDocument($collection->getCollection(), $collection->getId(), $collection)); -// $this->assertEquals(true, static::getDatabase()->deleteCollection('actors2')); // Delete collection when finished -// $this->assertCount(1, static::getDatabase()->listCollections()); -// -// $this->assertEquals(false, static::getDatabase()->getCollection('actors')->isEmpty()); -// $this->assertEquals(true, static::getDatabase()->deleteCollection('actors')); -// $this->assertEquals(true, static::getDatabase()->getCollection('actors')->isEmpty()); -// -// $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); -// } -// -// /** -// * @depends testFind -// */ -// public function testCount() -// { -// $count = static::getDatabase()->count('movies'); -// $this->assertEquals(5, $count); -// -// $count = static::getDatabase()->count('movies', [new Query(Query::TYPE_EQUAL, 'year', [2019]),]); -// $this->assertEquals(2, $count); -// -// Authorization::unsetRole('userx'); -// $count = static::getDatabase()->count('movies'); -// $this->assertEquals(5, $count); -// -// Authorization::disable(); -// $count = static::getDatabase()->count('movies'); -// $this->assertEquals(6, $count); -// Authorization::reset(); -// -// Authorization::disable(); -// $count = static::getDatabase()->count('movies', [], 3); -// $this->assertEquals(3, $count); -// Authorization::reset(); -// -// /** -// * Test that OR queries are handled correctly -// */ -// Authorization::disable(); -// $count = static::getDatabase()->count('movies', [ -// new Query(Query::TYPE_EQUAL, 'director', ['TBD', 'Joe Johnston']), -// new Query(Query::TYPE_EQUAL, 'year', [2025]), -// ]); -// $this->assertEquals(1, $count); -// Authorization::reset(); -// } -// -// public function testRenameAttribute() -// { -// $this->assertTrue(true); -// } -// -// public function testRenameAttributeExisting() -// { -// $this->assertTrue(true); -// } -// -// public function testUpdateAttributeStructure() -// { -// $this->assertTrue(true); -// } -// -// /** -// * Ensure the collection is removed after use -// * -// * @depends testIndexCaseInsensitivity -// */ -// public function testCleanupAttributeTests() -// { -// $res = static::getDatabase()->deleteCollection('attributes'); -// -// $this->assertEquals(true, $res); -// } -//} + +namespace Utopia\Tests\Adapter; + +use Redis; +use Utopia\Cache\Cache; +use Utopia\Cache\Adapter\Redis as RedisAdapter; +use Utopia\Database\Database; +use Utopia\Database\Document; +use Utopia\Database\Adapter\Mongo\MongoClient; +use Utopia\Database\Adapter\Mongo\MongoClientOptions; +use Utopia\Database\Adapter\Mongo\MongoDBAdapter; +use Utopia\Database\ID; +use Utopia\Database\Permission; +use Utopia\Database\Query; +use Utopia\Database\Role; +use Utopia\Database\Validator\Authorization; + +use Utopia\Tests\Base; + +class MongoDBTest extends Base +{ + static $pool = null; + + /** + * @var Database + */ + static $database = null; + + + // TODO@kodumbeats hacky way to identify adapters for tests + // Remove once all methods are implemented + /** + * Return name of adapter + * + * @return string + */ + static function getAdapterName(): string + { + return "mongodb"; + } + + /** + * Return row limit of adapter + * + * @return int + */ + static function getAdapterRowLimit(): int + { + return 0; + } + + /** + * @return Database + */ + static function getDatabase(): Database + { + if (!is_null(self::$database)) { + return self::$database; + } + + $redis = new Redis(); + $redis->connect('redis', 6379); + $redis->flushAll(); + $cache = new Cache(new RedisAdapter($redis)); + + $options = new MongoClientOptions( + 'utopia_testing', + 'mongo', + 27017, + 'root', + 'example' + ); + + $client = new MongoClient($options, false); + + $database = new Database(new MongoDBAdapter($client), $cache); + $database->setDefaultDatabase('utopiaTests'); + $database->setNamespace('myapp_' . uniqid()); + + + return self::$database = $database; + } + + public function testCreateExistsDelete() + { + $this->assertNotNull(static::getDatabase()->create($this->testDatabase)); + + $this->assertEquals(true, static::getDatabase()->exists($this->testDatabase)); + $this->assertEquals(true, static::getDatabase()->delete($this->testDatabase)); + + // Mongo creates on the fly, so this will never be true, do we want to try to make it pass + // by doing something else? + // $this->assertEquals(false, static::getDatabase()->exists($this->testDatabase)); + // $this->assertEquals(true, static::getDatabase()->create($this->testDatabase)); + // $this->assertEquals(true, static::getDatabase()->setDefaultDatabase($this->testDatabase)); + } + + /** + * @depends testCreateDocument + */ + public function testListDocumentSearch(Document $document) + { + static::getDatabase()->createIndex('documents', 'string', Database::INDEX_FULLTEXT, ['string']); + static::getDatabase()->createDocument('documents', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'string' => '*test+alias@email-provider.com', + 'integer' => 0, + 'bigint' => 8589934592, // 2^33 + 'float' => 5.55, + 'boolean' => true, + 'colors' => ['pink', 'green', 'blue'], + 'empty' => [], + ])); + + $documents = static::getDatabase()->find('documents', [ + Query::search('string', '*test+alias@email-provider.com') + ]); + + $this->assertEquals(1, count($documents)); + + return $document; + } + + /** + * @depends testUpdateDocument + */ + public function testFind(Document $document) + { + static::getDatabase()->createCollection('movies'); + + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'name', Database::VAR_STRING, 128, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'director', Database::VAR_STRING, 128, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'year', Database::VAR_INTEGER, 0, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'price', Database::VAR_FLOAT, 0, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'active', Database::VAR_BOOLEAN, 0, true)); + $this->assertEquals(true, static::getDatabase()->createAttribute('movies', 'generes', Database::VAR_STRING, 32, true, null, true, true)); + + static::getDatabase()->createDocument('movies', new Document([ + '$id' => ID::custom('frozen'), + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Frozen', + 'director' => 'Chris Buck & Jennifer Lee', + 'year' => 2013, + 'price' => 39.50, + 'active' => true, + 'generes' => ['animation', 'kids'], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Frozen II', + 'director' => 'Chris Buck & Jennifer Lee', + 'year' => 2019, + 'price' => 39.50, + 'active' => true, + 'generes' => ['animation', 'kids'], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Captain America: The First Avenger', + 'director' => 'Joe Johnston', + 'year' => 2011, + 'price' => 25.94, + 'active' => true, + 'generes' => ['science fiction', 'action', 'comics'], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Captain Marvel', + 'director' => 'Anna Boden & Ryan Fleck', + 'year' => 2019, + 'price' => 25.99, + 'active' => true, + 'generes' => ['science fiction', 'action', 'comics'], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::any()), + Permission::read(Role::user(ID::custom('1'))), + Permission::read(Role::user(ID::custom('2'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Work in Progress', + 'director' => 'TBD', + 'year' => 2025, + 'price' => 0.0, + 'active' => false, + 'generes' => [], + ])); + + static::getDatabase()->createDocument('movies', new Document([ + '$permissions' => [ + Permission::read(Role::user(ID::custom('x'))), + Permission::create(Role::any()), + Permission::create(Role::user(ID::custom('1x'))), + Permission::create(Role::user(ID::custom('2x'))), + Permission::update(Role::any()), + Permission::update(Role::user(ID::custom('1x'))), + Permission::update(Role::user(ID::custom('2x'))), + Permission::delete(Role::any()), + Permission::delete(Role::user(ID::custom('1x'))), + Permission::delete(Role::user(ID::custom('2x'))), + ], + 'name' => 'Work in Progress 2', + 'director' => 'TBD', + 'year' => 2026, + 'price' => 0.0, + 'active' => false, + 'generes' => [], + ])); + + /** + * Check Basic + */ + $documents = static::getDatabase()->count('movies'); + + $this->assertEquals(5, $documents); + } + + /** + * @depends testCreateExistsDelete + */ + public function testCreateListExistsDeleteCollection() + { + $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors')); + + $this->assertCount(1, static::getDatabase()->listCollections()); + $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); + + // Collection names should not be unique + $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection('actors2')); + $this->assertCount(2, static::getDatabase()->listCollections()); + $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors2')); + $collection = static::getDatabase()->getCollection('actors2'); + $collection->setAttribute('name', 'actors'); // change name to one that exists + + $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->updateDocument($collection->getCollection(), $collection->getId(), $collection)); + $this->assertEquals(true, static::getDatabase()->deleteCollection('actors2')); // Delete collection when finished + $this->assertCount(1, static::getDatabase()->listCollections()); + + $this->assertEquals(false, static::getDatabase()->getCollection('actors')->isEmpty()); + $this->assertEquals(true, static::getDatabase()->deleteCollection('actors')); + $this->assertEquals(true, static::getDatabase()->getCollection('actors')->isEmpty()); + + $this->assertNotNull(static::getDatabase()->exists($this->testDatabase, 'actors')); + } + + /** + * @depends testFind + */ + public function testCount() + { + $count = static::getDatabase()->count('movies'); + $this->assertEquals(5, $count); + + $count = static::getDatabase()->count('movies', [new Query(Query::TYPE_EQUAL, 'year', [2019]),]); + $this->assertEquals(2, $count); + + Authorization::unsetRole('userx'); + $count = static::getDatabase()->count('movies'); + $this->assertEquals(5, $count); + + Authorization::disable(); + $count = static::getDatabase()->count('movies'); + $this->assertEquals(6, $count); + Authorization::reset(); + + Authorization::disable(); + $count = static::getDatabase()->count('movies', [], 3); + $this->assertEquals(3, $count); + Authorization::reset(); + + /** + * Test that OR queries are handled correctly + */ + Authorization::disable(); + $count = static::getDatabase()->count('movies', [ + new Query(Query::TYPE_EQUAL, 'director', ['TBD', 'Joe Johnston']), + new Query(Query::TYPE_EQUAL, 'year', [2025]), + ]); + $this->assertEquals(1, $count); + Authorization::reset(); + } + + public function testRenameAttribute() + { + $this->assertTrue(true); + } + + public function testRenameAttributeExisting() + { + $this->assertTrue(true); + } + + public function testUpdateAttributeStructure() + { + $this->assertTrue(true); + } + + /** + * Ensure the collection is removed after use + * + * @depends testIndexCaseInsensitivity + */ + public function testCleanupAttributeTests() + { + $res = static::getDatabase()->deleteCollection('attributes'); + + $this->assertEquals(true, $res); + } +} diff --git a/tests/Database/Adapter/database.sql b/tests/Database/Adapter/database.sql index ffea83273614076a8952ae981b2fc5b757928c96..ad8e44497d4ccf7d9afb8ad1d523602a5bcd5c8c 100644 GIT binary patch delta 40249 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 z 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 DX6WTn delta 31725 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 Si7_eTxaA9R=RBtj{eJ;h{|Sr$ diff --git a/tests/Database/Base.php b/tests/Database/Base.php index b9ceb1cdf..3858b26d6 100644 --- a/tests/Database/Base.php +++ b/tests/Database/Base.php @@ -310,7 +310,7 @@ public function testCreateDeleteIndex() $collection = static::getDatabase()->getCollection('indexes'); $this->assertCount(0, $collection->getAttribute('indexes')); - //static::getDatabase()->deleteCollection('indexes'); + static::getDatabase()->deleteCollection('indexes'); } public function testCreateCollectionWithSchema() From a65d9e0de287dbe01f5c92170543d186b3486bc8 Mon Sep 17 00:00:00 2001 From: fogelito Date: Wed, 26 Oct 2022 14:23:50 +0300 Subject: [PATCH 21/21] some fixes --- src/Database/Adapter.php | 2 +- src/Database/Adapter/MySQL.php | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 02c507828..aae342558 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -257,7 +257,7 @@ abstract public function renameIndex(string $collection, string $old, string $ne * @param string $collection * @param string $id * @param string $type - * @param array $attributes + * @param array $attributes Document[] * @param array $lengths * @param array $orders * diff --git a/src/Database/Adapter/MySQL.php b/src/Database/Adapter/MySQL.php index d84874a5f..3311b6d1f 100644 --- a/src/Database/Adapter/MySQL.php +++ b/src/Database/Adapter/MySQL.php @@ -10,13 +10,14 @@ class MySQL extends MariaDB { /** * Get SQL Index - * + * * @param string $collection * @param string $id * @param string $type * @param array $attributes - * + * * @return string + * @throws Exception */ protected function getSQLIndex(string $collection, string $id, string $type, array $attributes): string { @@ -63,12 +64,6 @@ public function fixIndex(Document $index, array $attributes): Document { $max = 768; // 3072 divided by utf8mb4 foreach ($attributes as $key => $attribute){ - - //Internal attributes do not have a real attribute -// if(in_array($attribute->getId(), ['$id', '$createdAt', '$updatedAt'])){ -// continue; -// } - $size = $index['lengths'][$key] ?? 0; if($attribute['type'] === Database::VAR_STRING){