diff --git a/CHANGES.md b/CHANGES.md index c19edaa0c5..97c44bb03a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,14 +1,23 @@ -# Version TBD +# Version 1.3.0 ## Features - Password dictionary setting allows to compare user's password against command password database [4906](https://github.com/appwrite/appwrite/pull/4906) - Password history setting allows to save user's last used password so that it may not be used again. Maximum number of history saved is 20, which can be configured. Minimum is 0 which means disabled. [#4866](https://github.com/appwrite/appwrite/pull/4866) - Update APIs to check X-Appwrite-Timestamp header [#5024](https://github.com/appwrite/appwrite/pull/5024) +- Database relationships [#5238](https://github.com/appwrite/appwrite/pull/5238) +- New query operators [#5238](https://github.com/appwrite/appwrite/pull/5238) +- Team preferences [#5196](https://github.com/appwrite/appwrite/pull/5196) +- Update attribute metadata [#5164](https://github.com/appwrite/appwrite/pull/5164) ## Bugs - Fix not storing function's response on response codes 5xx [#4610](https://github.com/appwrite/appwrite/pull/4610) - Fix expire to formatTz in create account session [#4985](https://github.com/appwrite/appwrite/pull/4985) - Fix deleting projects when organization is deleted [#5335](https://github.com/appwrite/appwrite/pull/5335) +- Fix deleting collections from a project [#4983](https://github.com/appwrite/appwrite/pull/4983) +- Fix cleaning up project databases [#4984](https://github.com/appwrite/appwrite/pull/4984) +- Fix creating documents with attributes with special characters [#246](https://github.com/utopia-php/database/pull/246) +- Fix deleting attribute not deleting metadata index [#246](https://github.com/utopia-php/database/pull/246) +- Fix create attribute event payload [#246](https://github.com/utopia-php/database/pull/246) # Version 1.2.1 ## Changes diff --git a/app/init.php b/app/init.php index 6620985cdc..980040da68 100644 --- a/app/init.php +++ b/app/init.php @@ -101,7 +101,7 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours const APP_CACHE_BUSTER = 501; -const APP_VERSION_STABLE = '1.2.1'; +const APP_VERSION_STABLE = '1.3.0'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; const APP_DATABASE_ATTRIBUTE_IP = 'ip'; diff --git a/app/tasks/migrate.php b/app/tasks/migrate.php index 1d155c210d..7bb52f8970 100644 --- a/app/tasks/migrate.php +++ b/app/tasks/migrate.php @@ -85,10 +85,11 @@ $cli try { $migration ->setProject($project, $projectDB, $consoleDB) + ->setPDO($register->get('db')) ->execute(); } catch (\Throwable $th) { - throw $th; Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); + throw $th; } clearProjectsCache($redis, $project); diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 1e518a7b65..62c4dfba63 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -37,6 +37,8 @@ abstract class Migration */ protected Database $consoleDB; + protected \PDO $pdo; + /** * @var array */ @@ -99,6 +101,13 @@ abstract class Migration return $this; } + public function setPDO(\PDO $pdo): self + { + $this->pdo = $pdo; + + return $this; + } + /** * Iterates through every document. * @@ -332,6 +341,25 @@ abstract class Migration ); } + /** + * Change a collection attribute's internal type + * + * @param string $collection + * @param string $attribute + * @param string $type + * @return void + */ + protected function changeAttributeInternalType(string $collection, string $attribute, string $type): void + { + $stmt = $this->pdo->prepare("ALTER TABLE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$collection}` MODIFY `$attribute` $type;"); + + try { + $stmt->execute(); + } catch (\Exception $e) { + Console::warning($e->getMessage()); + } + } + /** * Executes migration for set project. */ diff --git a/src/Appwrite/Migration/Version/V15.php b/src/Appwrite/Migration/Version/V15.php index ac948d01d2..60f5fa20ab 100644 --- a/src/Appwrite/Migration/Version/V15.php +++ b/src/Appwrite/Migration/Version/V15.php @@ -17,11 +17,6 @@ use Utopia\Database\Helpers\Role; class V15 extends Migration { - /** - * @var \PDO $pdo - */ - private $pdo; - /** * @var array */ diff --git a/src/Appwrite/Migration/Version/V18.php b/src/Appwrite/Migration/Version/V18.php index 648a35d890..8f11e37a22 100644 --- a/src/Appwrite/Migration/Version/V18.php +++ b/src/Appwrite/Migration/Version/V18.php @@ -2,10 +2,8 @@ namespace Appwrite\Migration\Version; -use Appwrite\Auth\Auth; use Appwrite\Migration\Migration; use Utopia\CLI\Console; -use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; @@ -13,10 +11,11 @@ class V18 extends Migration { public function execute(): void { + /** * Disable SubQueries for Performance. */ - foreach (['subQueryIndexes', 'subQueryPlatforms', 'subQueryDomains', 'subQueryKeys', 'subQueryWebhooks', 'subQuerySessions', 'subQueryTokens', 'subQueryMemberships', 'subqueryVariables'] as $name) { + foreach (['subQueryIndexes', 'subQueryPlatforms', 'subQueryDomains', 'subQueryKeys', 'subQueryWebhooks', 'subQuerySessions', 'subQueryTokens', 'subQueryMemberships', 'subQueryVariables'] as $name) { Database::addFilter( $name, fn () => null, @@ -25,12 +24,44 @@ class V18 extends Migration } Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); + $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); + + Console::info('Migrating Databases'); + $this->migrateDatabases(); Console::info('Migrating Collections'); $this->migrateCollections(); Console::info('Migrating Documents'); - $this->forEachDocument([$this, 'fixDocument']); + $this->forEachDocument(function (Document $document) { + $this->migrateDocument($document); + }); + } + + /** + * Migrate all Databases. + * + * @return void + * @throws \Exception + */ + private function migrateDatabases(): void + { + foreach ($this->documentsIterator('databases') as $database) { + $databaseTable = "database_{$database->getInternalId()}"; + + Console::info("Migrating Collections of {$database->getId()} ({$database->getAttribute('name')})"); + + foreach ($this->documentsIterator($databaseTable) as $collection) { + $collectionTable = "{$databaseTable}_collection_{$collection->getInternalId()}"; + + foreach ($collection['attributes'] ?? [] as $attribute) { + if ($attribute['type'] !== Database::VAR_FLOAT) { + continue; + } + $this->changeAttributeInternalType($collectionTable, $attribute['key'], 'DOUBLE'); + } + } + } } /** @@ -38,14 +69,19 @@ class V18 extends Migration * * @return void */ - protected function migrateCollections(): void + private function migrateCollections(): void { foreach ($this->collections as $collection) { $id = $collection['$id']; Console::log("Migrating Collection \"{$id}\""); - $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); + foreach ($collection['attributes'] ?? [] as $attribute) { + if ($attribute['type'] !== Database::VAR_FLOAT) { + continue; + } + $this->changeAttributeInternalType($id, $attribute['$id'], 'DOUBLE'); + } switch ($id) { case 'users': @@ -59,6 +95,17 @@ class V18 extends Migration Console::warning("'passwordHistory' from {$id}: {$th->getMessage()}"); } break; + case 'teams': + try { + /** + * Create 'prefs' attribute + */ + $this->createAttributeFromCollection($this->projectDB, $id, 'prefs'); + $this->projectDB->deleteCachedCollection($id); + } catch (\Throwable $th) { + Console::warning("'prefs' from {$id}: {$th->getMessage()}"); + } + break; default: break; } @@ -70,10 +117,10 @@ class V18 extends Migration /** * Fix run on each document * - * @param \Utopia\Database\Document $document - * @return \Utopia\Database\Document + * @param Document $document + * @return Document */ - protected function fixDocument(Document $document) + private function migrateDocument(Document $document): Document { switch ($document->getCollection()) { case 'projects': @@ -96,6 +143,12 @@ class V18 extends Migration */ $document->setAttribute('passwordHistory', []); break; + case 'teams': + /** + * Default prefs + */ + $document->setAttribute('prefs', new \stdClass()); + break; } return $document;