From d543705a543c8c7f75a459228e68d29207cb5bae Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 15 Feb 2023 20:35:24 +1300 Subject: [PATCH] Migration for database update --- app/tasks/migrate.php | 1 + src/Appwrite/Migration/Migration.php | 33 +++++++ src/Appwrite/Migration/Version/V15.php | 5 - src/Appwrite/Migration/Version/V18.php | 123 +++++++++++++++++++++++++ 4 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 src/Appwrite/Migration/Version/V18.php diff --git a/app/tasks/migrate.php b/app/tasks/migrate.php index 1d155c210d..ded157e54b 100644 --- a/app/tasks/migrate.php +++ b/app/tasks/migrate.php @@ -85,6 +85,7 @@ $cli try { $migration ->setProject($project, $projectDB, $consoleDB) + ->setPDO($register->get('db')) ->execute(); } catch (\Throwable $th) { throw $th; diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 6f8c51201e..6081f4cc5f 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 */ @@ -49,6 +51,7 @@ abstract class Migration '1.1.1' => 'V16', '1.1.2' => 'V16', '1.2.0' => 'V17', + '1.3.0' => 'V18', ]; /** @@ -97,6 +100,13 @@ abstract class Migration return $this; } + public function setPDO(\PDO $pdo): self + { + $this->pdo = $pdo; + + return $this; + } + /** * Iterates through every document. * @@ -330,6 +340,29 @@ 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 :table MODIFY :attribute :type;'); + + $stmt->bindValue(':table', "{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$collection}`"); + $stmt->bindValue(':attribute', $attribute); + $stmt->bindValue(':type', $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 new file mode 100644 index 0000000000..c2345cad1d --- /dev/null +++ b/src/Appwrite/Migration/Version/V18.php @@ -0,0 +1,123 @@ +redis = $register->get('cache'); + + /** + * Disable SubQueries for Performance. + */ + foreach (['subQueryIndexes', 'subQueryPlatforms', 'subQueryDomains', 'subQueryKeys', 'subQueryWebhooks', 'subQuerySessions', 'subQueryTokens', 'subQueryMemberships', 'subQueryVariables'] as $name) { + Database::addFilter( + $name, + fn () => null, + fn () => [] + ); + } + + 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, 'migrateDocument']); + + Console::info('Migrating Cache'); + $this->forEachDocument([$this, 'migrateCache']); + } + + /** + * 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()}"; + + $floats = \array_filter($collection->getAttributes(), function ($attribute) { + return $attribute->getAttribute('type') === Database::VAR_FLOAT; + }); + + foreach ($floats as $attribute) { + $this->changeAttributeInternalType($collectionTable, $attribute->getId(), 'DOUBLE'); + } + } + } + } + + /** + * Migrate all Collections. + * + * @return void + */ + private function migrateCollections(): void + { + foreach ($this->collections as $collection) { + $id = $collection['$id']; + + Console::log("Migrating Collection \"{$id}\""); + $floats = \array_filter($collection, function ($attribute) { + return $attribute['type'] === Database::VAR_FLOAT; + }); + + foreach ($floats as $attribute) { + $this->changeAttributeInternalType($id, $attribute->getId(), 'DOUBLE'); + } + } + } + + /** + * Fix run on each document + * + * @param Document $document + * @return Document + */ + private function migrateDocument(Document $document): Document + { + switch ($document->getCollection()) { + case 'projects': + $document->setAttribute('version', '1.3.0'); + break; + } + + return $document; + } + + private function migrateCache(Document $document) { + $key = "cache-_{$this->project->getInternalId()}:_{$document->getCollection()}:{$document->getId()}"; + $value = $this->redis->get($key); + + if ($value) { + $this->redis->del($key); + $this->redis->set( $key. ':*', $value); + } + } +}