From 20e3e61ad577014e5f092a292c90a8476f630355 Mon Sep 17 00:00:00 2001 From: Louis Chemineau Date: Wed, 2 Nov 2022 18:04:24 +0100 Subject: [PATCH] Add primary key index to collaborators table - Create new `photos_albums_collabs` table - with an `id` auto-incremented column - with a primary key using the `id` column - with a unique index instead of a unique constraint - Move data from `photos_collaborators` to `photos_albums_collabs` - Delete `photos_collaborators` table Signed-off-by: Louis Chemineau --- appinfo/info.xml | 2 +- lib/Album/AlbumMapper.php | 14 +- .../Version20001Date20220830131446.php | 42 +++--- .../Version20003Date20221102170153.php | 139 ++++++++++++++++++ .../Version20003Date20221103094628.php | 55 +++++++ package.json | 4 +- 6 files changed, 227 insertions(+), 29 deletions(-) create mode 100644 lib/Migration/Version20003Date20221102170153.php create mode 100644 lib/Migration/Version20003Date20221103094628.php diff --git a/appinfo/info.xml b/appinfo/info.xml index d590505e..140167a4 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -5,7 +5,7 @@ Photos Your memories under your control Your memories under your control - 2.1.0 + 2.2.0 agpl John Molakvoæ Photos diff --git a/lib/Album/AlbumMapper.php b/lib/Album/AlbumMapper.php index 66360a11..9be017d0 100644 --- a/lib/Album/AlbumMapper.php +++ b/lib/Album/AlbumMapper.php @@ -177,7 +177,7 @@ class AlbumMapper { $query->executeStatement(); $query = $this->connection->getQueryBuilder(); - $query->delete("photos_collaborators") + $query->delete("photos_albums_collabs") ->where($query->expr()->eq('album_id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT))); $query->executeStatement(); @@ -295,7 +295,7 @@ class AlbumMapper { public function getCollaborators(int $albumId): array { $query = $this->connection->getQueryBuilder(); $query->select("collaborator_id", "collaborator_type") - ->from("photos_collaborators") + ->from("photos_albums_collabs") ->where($query->expr()->eq('album_id', $query->createNamedParameter($albumId, IQueryBuilder::PARAM_INT))); $rows = $query->executeQuery()->fetchAll(); @@ -369,7 +369,7 @@ class AlbumMapper { } $query = $this->connection->getQueryBuilder(); - $query->insert('photos_collaborators') + $query->insert('photos_albums_collabs') ->setValue('album_id', $query->createNamedParameter($albumId, IQueryBuilder::PARAM_INT)) ->setValue('collaborator_id', $query->createNamedParameter($collaborator['id'])) ->setValue('collaborator_type', $query->createNamedParameter($collaborator['type'], IQueryBuilder::PARAM_INT)) @@ -378,7 +378,7 @@ class AlbumMapper { foreach ($collaboratorsToRemove as $collaborator) { $query = $this->connection->getQueryBuilder(); - $query->delete('photos_collaborators') + $query->delete('photos_albums_collabs') ->where($query->expr()->eq('album_id', $query->createNamedParameter($albumId, IQueryBuilder::PARAM_INT))) ->andWhere($query->expr()->eq('collaborator_id', $query->createNamedParameter($collaborator['id']))) ->andWhere($query->expr()->eq('collaborator_type', $query->createNamedParameter($collaborator['type'], IQueryBuilder::PARAM_INT))) @@ -400,7 +400,7 @@ class AlbumMapper { ->selectAlias("f.name", "file_name") ->selectAlias("a.name", "album_name") ->selectAlias("a.user", "album_user") - ->from("photos_collaborators", "c") + ->from("photos_albums_collabs", "c") ->leftJoin("c", "photos_albums", "a", $query->expr()->eq("a.album_id", "c.album_id")) ->leftJoin("a", "photos_albums_files", "p", $query->expr()->eq("a.album_id", "p.album_id")) ->leftJoin("p", "filecache", "f", $query->expr()->eq("p.file_id", "f.fileid")) @@ -445,7 +445,7 @@ class AlbumMapper { public function deleteUserFromAlbumCollaboratorsList(string $userId, int $albumId): void { // TODO: only delete if this was not a group share $query = $this->connection->getQueryBuilder(); - $query->delete('photos_collaborators') + $query->delete('photos_albums_collabs') ->where($query->expr()->eq('album_id', $query->createNamedParameter($albumId, IQueryBuilder::PARAM_INT))) ->andWhere($query->expr()->eq('collaborator_id', $query->createNamedParameter($userId))) ->andWhere($query->expr()->eq('collaborator_type', $query->createNamedParameter(self::TYPE_USER, IQueryBuilder::PARAM_INT))) @@ -462,7 +462,7 @@ class AlbumMapper { $query = $this->connection->getQueryBuilder(); $rows = $query ->select("a.album_id", "name", "user", "location", "created", "last_added_photo") - ->from("photos_collaborators", "c") + ->from("photos_albums_collabs", "c") ->leftJoin("c", "photos_albums", "a", $query->expr()->eq("a.album_id", "c.album_id")) ->leftJoin("a", "photos_albums_files", "p", $query->expr()->eq("a.album_id", "p.album_id")) ->where($query->expr()->eq('collaborator_id', $query->createNamedParameter($collaboratorId))) diff --git a/lib/Migration/Version20001Date20220830131446.php b/lib/Migration/Version20001Date20220830131446.php index d58a93e7..a44ff63f 100644 --- a/lib/Migration/Version20001Date20220830131446.php +++ b/lib/Migration/Version20001Date20220830131446.php @@ -3,9 +3,9 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2022 Your name + * @copyright Copyright (c) 2022 Louis Chemineau * - * @author Your name + * @author Louis Chemineau * * @license GNU AGPL version 3 or any later version * @@ -47,23 +47,27 @@ class Version20001Date20220830131446 extends SimpleMigrationStep { $schema = $schemaClosure(); $modified = false; - if (!$schema->hasTable("photos_collaborators")) { - $modified = true; - $table = $schema->createTable("photos_collaborators"); - $table->addColumn('album_id', Types::BIGINT, [ - 'notnull' => true, - 'length' => 20, - ]); - $table->addColumn('collaborator_id', Types::STRING, [ - 'notnull' => true, - 'length' => 64, - ]); - $table->addColumn('collaborator_type', Types::INTEGER, [ - 'notnull' => true, - ]); - - $table->addUniqueConstraint(['album_id', 'collaborator_id', 'collaborator_type'], 'collaborators_unique_idx'); - } + /** + * Replaced by Version20003Date20221102170153 + * + * if (!$schema->hasTable("photos_collaborators")) { + * $modified = true; + * $table = $schema->createTable("photos_collaborators"); + * $table->addColumn('album_id', Types::BIGINT, [ + * 'notnull' => true, + * 'length' => 20, + * ]); + * $table->addColumn('collaborator_id', Types::STRING, [ + * 'notnull' => true, + * 'length' => 64, + * ]); + * $table->addColumn('collaborator_type', Types::INTEGER, [ + * 'notnull' => true, + * ]); + * + * $table->addUniqueConstraint(['album_id', 'collaborator_id', 'collaborator_type'], 'collaborators_unique_idx'); + * } + */ if (!$schema->getTable("photos_albums_files")->hasColumn("owner")) { $modified = true; diff --git a/lib/Migration/Version20003Date20221102170153.php b/lib/Migration/Version20003Date20221102170153.php new file mode 100644 index 00000000..6a16a22a --- /dev/null +++ b/lib/Migration/Version20003Date20221102170153.php @@ -0,0 +1,139 @@ + + * + * @author Louis Chemineau + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Photos\Migration; + +use Closure; +use OCP\IDBConnection; +use OCP\DB\Types; +use OCP\DB\ISchemaWrapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version20003Date20221102170153 extends SimpleMigrationStep { + protected IDBConnection $connection; + + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if ($schema->hasTable("photos_albums_collabs")) { + return null; + } + + $table = $schema->createTable("photos_albums_collabs"); + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 20, + ]); + $table->addColumn('album_id', Types::BIGINT, [ + 'notnull' => true, + 'length' => 20, + ]); + $table->addColumn('collaborator_id', Types::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('collaborator_type', Types::INTEGER, [ + 'notnull' => true, + ]); + + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['album_id', 'collaborator_id', 'collaborator_type'], 'album_collabs_uniq_collab'); + + return $schema; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return void + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + if (!$schema->hasTable('photos_collaborators')) { + return; + } + + $insert = $this->connection->getQueryBuilder(); + $insert->insert('photos_albums_collabs') + ->values([ + 'album_id' => $insert->createParameter('album_id'), + 'collaborator_id' => $insert->createParameter('collaborator_id'), + 'collaborator_type' => $insert->createParameter('collaborator_type'), + ]); + + $select = $this->connection->getQueryBuilder(); + $select->select('*') + ->from('photos_collaborators') + ->setMaxResults(1000); + + $offset = 0; + $movedRows = 0; + do { + $movedRows = $this->chunkedCopying($insert, $select, $offset); + $offset += $movedRows; + } while ($movedRows !== 0); + } + + protected function chunkedCopying(IQueryBuilder $insert, IQueryBuilder $select, int $offset): int { + $this->connection->beginTransaction(); + + $result = $select + ->setFirstResult($offset) + ->executeQuery(); + + while ($row = $result->fetch()) { + $insert + ->setParameter('album_id', (int)$row['album_id'], IQueryBuilder::PARAM_INT) + ->setParameter('collaborator_id', $row['collaborator_id']) + ->setParameter('collaborator_type', (int) $row['collaborator_type'], IQueryBuilder::PARAM_INT) + ->executeStatement(); + } + + $result->closeCursor(); + $this->connection->commit(); + + return $result->rowCount(); + } +} diff --git a/lib/Migration/Version20003Date20221103094628.php b/lib/Migration/Version20003Date20221103094628.php new file mode 100644 index 00000000..30c127d6 --- /dev/null +++ b/lib/Migration/Version20003Date20221103094628.php @@ -0,0 +1,55 @@ + + * + * @author Louis Chemineau + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Photos\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version20003Date20221103094628 extends SimpleMigrationStep { + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if ($schema->hasTable('photos_collaborators')) { + $schema->dropTable('photos_collaborators'); + return $schema; + } + + return null; + } +} diff --git a/package.json b/package.json index f5f6f8cb..34c181aa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "photos", "description": "Your memories under your control", - "version": "2.1.0", + "version": "2.2.0", "author": "John Molakvoæ ", "contributors": [ "John Molakvoæ " @@ -95,4 +95,4 @@ "wait-on": "^6.0.1", "workbox-webpack-plugin": "^6.5.4" } -} +} \ No newline at end of file