diff --git a/lib/Db/FeedMapperV2.php b/lib/Db/FeedMapperV2.php index bab170f792..9c90b6f4e5 100644 --- a/lib/Db/FeedMapperV2.php +++ b/lib/Db/FeedMapperV2.php @@ -29,6 +29,7 @@ class FeedMapperV2 extends NewsMapperV2 { const TABLE_NAME = 'news_feeds'; + const USER_TABLE_NAME = 'news_user_feeds'; /** * FeedMapper constructor. diff --git a/lib/Db/ItemMapperV2.php b/lib/Db/ItemMapperV2.php index 8a92354d80..8a337e0c14 100644 --- a/lib/Db/ItemMapperV2.php +++ b/lib/Db/ItemMapperV2.php @@ -31,6 +31,7 @@ class ItemMapperV2 extends NewsMapperV2 { const TABLE_NAME = 'news_items'; + const USER_TABLE_NAME = 'news_user_items'; /** * ItemMapper constructor. @@ -56,9 +57,8 @@ public function findAllFromUser(string $userId, array $params = []): array $builder = $this->db->getQueryBuilder(); $builder->select('items.*') ->from($this->tableName, 'items') - ->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id') - ->where('feeds.user_id = :user_id') - ->andWhere('feeds.deleted_at = 0') + ->innerJoin('items', self::USER_TABLE_NAME, 'users', 'items.id = users.item_id') + ->where('users.user_id = :user_id') ->setParameter('user_id', $userId, IQueryBuilder::PARAM_STR); foreach ($params as $key => $value) { @@ -92,10 +92,10 @@ public function findFromUser(string $userId, int $id): Entity $builder = $this->db->getQueryBuilder(); $builder->select('items.*') ->from($this->tableName, 'items') - ->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id') - ->where('feeds.user_id = :user_id') + ->innerJoin('items', self::USER_TABLE_NAME, 'users', 'items.id = users.item_id') + ->where('users.user_id = :user_id') ->andWhere('items.id = :item_id') - ->andWhere('feeds.deleted_at = 0') + ->andWhere('users.deleted_at = 0') ->setParameter('user_id', $userId, IQueryBuilder::PARAM_STR) ->setParameter('item_id', $id, IQueryBuilder::PARAM_INT); @@ -444,9 +444,10 @@ public function findAllFeed( ): array { $builder = $this->db->getQueryBuilder(); - $builder->select('items.*') + $builder->select('items.*', 'users.unread', 'users.starred', 'users.shared_by') ->from($this->tableName, 'items') ->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id') + ->innerJoin('items', self::USER_TABLE_NAME, 'users', 'items.id = users.item_id') ->andWhere('feeds.deleted_at = 0') ->andWhere('feeds.user_id = :userId') ->andWhere('items.feed_id = :feedId') @@ -501,9 +502,10 @@ public function findAllFolder( $folderWhere = $builder->expr()->eq('feeds.folder_id', new Literal($folderId), IQueryBuilder::PARAM_INT); } - $builder->select('items.*') + $builder->select('items.*', 'users.unread', 'users.starred', 'users.shared_by') ->from($this->tableName, 'items') ->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id') + ->innerJoin('items', self::USER_TABLE_NAME, 'users', 'items.id = users.item_id') ->andWhere('feeds.user_id = :userId') ->andWhere('feeds.deleted_at = 0') ->andWhere($folderWhere) @@ -550,11 +552,10 @@ public function findAllItems( ): array { $builder = $this->db->getQueryBuilder(); - $builder->select('items.*') + $builder->select('items.*', 'users.unread', 'users.starred', 'users.shared_by') ->from($this->tableName, 'items') - ->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id') - ->andWhere('feeds.user_id = :userId') - ->andWhere('feeds.deleted_at = 0') + ->innerJoin('items', self::USER_TABLE_NAME, 'users', 'items.id = users.item_id') + ->andWhere('users.user_id = :userId') ->setParameter('userId', $userId) ->addOrderBy('items.id', ($oldestFirst ? 'ASC' : 'DESC')); diff --git a/lib/Migration/Version160100Date20210821130702.php b/lib/Migration/Version160100Date20210821130702.php new file mode 100644 index 0000000000..6ed600672e --- /dev/null +++ b/lib/Migration/Version160100Date20210821130702.php @@ -0,0 +1,141 @@ +connection = $connection; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } + + /** + * @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('news_user_items')) { + $table = $schema->createTable('news_user_items'); + $table->addColumn('item_id', 'bigint', [ + 'notnull' => true, + 'length' => 8, + 'unsigned' => true, + ]); + $table->addColumn('user_id', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('unread', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $table->addColumn('starred', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $table->addColumn('last_modified', 'bigint', [ + 'notnull' => false, + 'length' => 8, + 'default' => 0, + 'unsigned' => true, + ]); + $table->addColumn('shared_by', 'string', [ + 'notnull' => false, + 'length' => 64 + ]); + $table->setPrimaryKey(['item_id', 'user_id']); + } + + if (!$schema->hasTable('news_user_feeds')) { + $table = $schema->createTable('news_user_feeds'); + $table->addColumn('feed_id', 'bigint', [ + 'notnull' => true, + 'length' => 8, + 'unsigned' => true, + ]); + $table->addColumn('user_id', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('folder_id', 'bigint', [ + 'notnull' => false, + 'length' => 8, + ]); + $table->addColumn('deleted_at', 'bigint', [ + 'notnull' => false, + 'length' => 8, + 'default' => 0, + 'unsigned' => true, + ]); + $table->addColumn('added', 'bigint', [ + 'notnull' => false, + 'length' => 8, + 'default' => 0, + 'unsigned' => true, + ]); + $table->addColumn('title', 'text', [ + 'notnull' => true, + ]); + $table->addColumn('last_modified', 'bigint', [ + 'notnull' => false, + 'length' => 8, + 'default' => 0, + 'unsigned' => true, + ]); + $table->setPrimaryKey(['feed_id', 'user_id']); + } + + return $schema; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + $qb = $this->connection->getQueryBuilder(); + $user_item_table = $qb->getTableName('news_user_items'); + $user_feed_table = $qb->getTableName('news_user_feeds'); + $item_table = $qb->getTableName('news_items'); + $feed_table = $qb->getTableName('news_feeds'); + + $items_query = "REPLACE INTO $user_item_table SELECT id AS 'item_id', ? AS 'user_id',`unread`,`starred`,`last_modified`,`shared_by` FROM $item_table where feed_id = ?;"; + + $feeds = $this->connection->executeQuery("SELECT `id`,`user_id` FROM $feed_table;")->fetchAll(); + foreach ($feeds as $feed) { + $this->connection->executeUpdate($items_query, [$feed['user_id'], $feed['id']]); + } + + $this->connection->executeUpdate("REPLACE INTO $user_feed_table SELECT id AS 'feed_id',user_id,folder_id,deleted_at,added,title,last_modified FROM $feed_table;"); + } +} diff --git a/tests/Unit/Db/ItemMapperTest.php b/tests/Unit/Db/ItemMapperTest.php index 7fc45018e2..e432fc45f3 100644 --- a/tests/Unit/Db/ItemMapperTest.php +++ b/tests/Unit/Db/ItemMapperTest.php @@ -88,12 +88,15 @@ public function testFindAllFromUser() $this->builder->expects($this->once()) ->method('innerJoin') - ->with('items', 'news_feeds', 'feeds', 'items.feed_id = feeds.id') + ->withConsecutive( + ['items', 'news_user_items', 'users', 'items.id = users.item_id'], + ['a', 'a', 'a', 'a'] + ) ->will($this->returnSelf()); $this->builder->expects($this->once()) ->method('where') - ->with('feeds.user_id = :user_id') + ->with('users.user_id = :user_id') ->will($this->returnSelf()); $this->builder->expects($this->once())