Skip to content

Commit

Permalink
DB: Updates should use set()
Browse files Browse the repository at this point in the history
Issue nextcloudGH-1211

Signed-off-by: Sean Molenaar <sean@seanmolenaar.eu>
  • Loading branch information
SMillerDev committed Mar 30, 2021
1 parent 7a2b3cc commit d51b4a0
Show file tree
Hide file tree
Showing 19 changed files with 741 additions and 129 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The format is almost based on [Keep a Changelog](https://keepachangelog.com/en/1

### Fixed
- Do not show deleted feeds in item list
- Fix update queries (#1211)

## [15.4.0-beta2] - 2021-02-27
### Fixed
Expand Down
3 changes: 3 additions & 0 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ Before you update to a new version, [check the changelog](https://github.com/nex
<command>OCA\News\Command\Debug\ItemList</command>
<command>OCA\News\Command\Debug\FolderItemList</command>
<command>OCA\News\Command\Debug\FeedItemList</command>
<command>OCA\News\Command\Debug\ItemRead</command>
<command>OCA\News\Command\Debug\FolderRead</command>
<command>OCA\News\Command\Debug\FeedRead</command>
</commands>

<settings>
Expand Down
85 changes: 85 additions & 0 deletions lib/Command/Debug/FeedRead.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);

namespace OCA\News\Command\Debug;

use OCA\News\Controller\ApiPayloadTrait;
use OCA\News\Db\ListType;
use OCA\News\Service\Exceptions\ServiceConflictException;
use OCA\News\Service\Exceptions\ServiceNotFoundException;
use OCA\News\Service\FeedServiceV2;
use OCA\News\Service\FolderServiceV2;
use OCA\News\Service\ItemServiceV2;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Class ItemRead
*
* @package OCA\News\Command
*/
class FeedRead extends Command
{
/**
* @var FeedServiceV2 service for the folders.
*/
protected $feedService;

/**
* @var ItemServiceV2 service for the items.
*/
protected $itemService;

public function __construct(FeedServiceV2 $feedService, ItemServiceV2 $itemService)
{
parent::__construct();

$this->feedService = $feedService;
$this->itemService = $itemService;
}

/**
* Configure command
*
* @return void
*/
protected function configure()
{
$this->setName('news:feed:read')
->setDescription('Read feed')
->addArgument('user-id', InputArgument::REQUIRED, 'User to modify the feed for')
->addArgument('id', InputArgument::REQUIRED, 'Feed ID');
}

/**
* Execute command
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$user = $input->getArgument('user-id');

$id = $input->getArgument('id');
if (!is_numeric($id)) {
$output->writeln('Invalid id!');
return 255;
}

try {
$read = $this->feedService->read($user, intval($id));
$output->writeln("Marked $read items as read", $output::VERBOSITY_VERBOSE);
} catch (ServiceConflictException | ServiceNotFoundException $e) {
$output->writeln('Failed: ' . $e->getMessage());
return 0;
}

return 0;
}
}
84 changes: 84 additions & 0 deletions lib/Command/Debug/FolderRead.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);

namespace OCA\News\Command\Debug;

use OCA\News\Controller\ApiPayloadTrait;
use OCA\News\Db\ListType;
use OCA\News\Service\Exceptions\ServiceConflictException;
use OCA\News\Service\Exceptions\ServiceNotFoundException;
use OCA\News\Service\FolderServiceV2;
use OCA\News\Service\ItemServiceV2;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Class ItemRead
*
* @package OCA\News\Command
*/
class FolderRead extends Command
{
/**
* @var FolderServiceV2 service for the folders.
*/
protected $folderService;

/**
* @var ItemServiceV2 service for the items.
*/
protected $itemService;

public function __construct(FolderServiceV2 $folderService, ItemServiceV2 $itemService)
{
parent::__construct();

$this->folderService = $folderService;
$this->itemService = $itemService;
}

/**
* Configure command
*
* @return void
*/
protected function configure()
{
$this->setName('news:folder:read')
->setDescription('Read folder')
->addArgument('user-id', InputArgument::REQUIRED, 'User to modify the folder for')
->addArgument('id', InputArgument::REQUIRED, 'Folder ID');
}

/**
* Execute command
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$user = $input->getArgument('user-id');

$id = $input->getArgument('id');
if (!is_numeric($id)) {
$output->writeln('Invalid id!');
return 255;
}

try {
$read = $this->folderService->read($user, intval($id));
$output->writeln("Marked $read items as read", $output::VERBOSITY_VERBOSE);
} catch (ServiceConflictException | ServiceNotFoundException $e) {
$output->writeln('Failed: ' . $e->getMessage());
return 0;
}

return 0;
}
}
87 changes: 87 additions & 0 deletions lib/Command/Debug/ItemRead.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php
declare(strict_types=1);

namespace OCA\News\Command\Debug;

use OCA\News\Controller\ApiPayloadTrait;
use OCA\News\Db\ListType;
use OCA\News\Service\Exceptions\ServiceConflictException;
use OCA\News\Service\Exceptions\ServiceNotFoundException;
use OCA\News\Service\ItemServiceV2;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Class ItemRead
*
* @package OCA\News\Command
*/
class ItemRead extends Command
{
use ApiPayloadTrait;

/**
* @var ItemServiceV2 service for the items.
*/
protected $itemService;

public function __construct(ItemServiceV2 $itemService)
{
parent::__construct();

$this->itemService = $itemService;
}

/**
* Configure command
*
* @return void
*/
protected function configure()
{
$this->setName('news:item:read')
->setDescription('Read item')
->addArgument('user-id', InputArgument::REQUIRED, 'User to modify the item for')
->addOption('id', 'i', InputOption::VALUE_REQUIRED, 'Item ID')
->addOption('read', 'r', InputOption::VALUE_NONE, 'Item read state');
}

/**
* Execute command
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$user = $input->getArgument('user-id');
$read = $input->getOption('read');

$id = $input->getOption('id');
if (!is_null($id) && !is_numeric($id)) {
$output->writeln('Invalid id!');
return 255;
}


try {
if (is_null($id)) {
$readItems = $this->itemService->readAll($user, $this->itemService->newest($user)->getId());
$output->writeln("Marked $readItems items as read", $output::VERBOSITY_VERBOSE);
} else {
$items = $this->itemService->read($user, intval($id), $read);
$output->writeln(json_encode($this->serialize($items), JSON_PRETTY_PRINT));
}
} catch (ServiceConflictException | ServiceNotFoundException $e) {
$output->writeln('Failed: ' . $e->getMessage());
return 1;
}

return 0;
}
}
32 changes: 25 additions & 7 deletions lib/Db/FeedMapperV2.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use OCA\News\Utility\Time;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\DB\Exception as DBException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\AppFramework\Db\Entity;
Expand Down Expand Up @@ -158,23 +159,40 @@ public function findAllFromFolder(?int $id): array
* @param string $userId
* @param int $id
* @param int|null $maxItemID
*
* @return int
* @throws DBException
*
* @TODO Update for NC 21
*/
public function read(string $userId, int $id, ?int $maxItemID = null): void
public function read(string $userId, int $id, ?int $maxItemID = null): int
{
$builder = $this->db->getQueryBuilder();
$builder->update(ItemMapperV2::TABLE_NAME, 'items')
$idBuilder = $this->db->getQueryBuilder();
$idBuilder->select('items.id')
->from(ItemMapperV2::TABLE_NAME, 'items')
->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id')
->setValue('unread', 0)
->andWhere('feeds.user_id = :userId')
->andWhere('feeds.id = :feedId')
->setParameter('userId', $userId)
->setParameter('feedId', $id);

if ($maxItemID !== null) {
$builder->andWhere('items.id =< :maxItemId')
->setParameter('maxItemId', $maxItemID);
$idBuilder->andWhere('items.id <= :maxItemId')
->setParameter('maxItemId', $maxItemID);
}

$this->db->executeUpdate($builder->getSQL());
$idList = array_map(function ($value): int {
return intval($value['id']);
}, $this->db->executeQuery($idBuilder->getSQL(), $idBuilder->getParameters())->fetchAll());

$builder = $this->db->getQueryBuilder();
$builder->update(ItemMapperV2::TABLE_NAME)
->set('unread', $builder->createParameter('unread'))
->andWhere('id IN (:idList)')
->andWhere('unread != :unread')
->setParameter('unread', false, IQueryBuilder::PARAM_BOOL)
->setParameter('idList', $idList, IQueryBuilder::PARAM_INT_ARRAY);

return $this->db->executeUpdate($builder->getSQL(), $builder->getParameters(), $builder->getParameterTypes());
}
}
43 changes: 30 additions & 13 deletions lib/Db/FolderMapperV2.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

use OCA\News\Utility\Time;
use OCP\AppFramework\Db\Entity;
use OCP\DB\Exception as DBException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;

/**
Expand Down Expand Up @@ -101,24 +103,39 @@ public function findFromUser(string $userId, int $id): Entity
* @param int $id
* @param int|null $maxItemID
*
* @return void
* @return int
*
* @throws DBException
* @TODO Update for NC 21
*/
public function read(string $userId, int $id, ?int $maxItemID = null): void
public function read(string $userId, int $id, ?int $maxItemID = null): int
{
$builder = $this->db->getQueryBuilder();
$builder->update(ItemMapperV2::TABLE_NAME, 'items')
->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id')
->setValue('unread', 0)
->andWhere('feeds.user_id = :userId')
->andWhere('feeds.folder_id = :folderId')
->setParameter('userId', $userId)
->setParameter('folderId', $id);
$idBuilder = $this->db->getQueryBuilder();
$idBuilder->select('items.id')
->from(ItemMapperV2::TABLE_NAME, 'items')
->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id')
->andWhere('feeds.user_id = :userId')
->andWhere('feeds.folder_id = :folderId')
->setParameter('userId', $userId)
->setParameter('folderId', $id);

if ($maxItemID !== null) {
$builder->andWhere('items.id =< :maxItemId')
->setParameter('maxItemId', $maxItemID);
$idBuilder->andWhere('items.id <= :maxItemId')
->setParameter('maxItemId', $maxItemID);
}

$this->db->executeUpdate($builder->getSQL());
$idList = array_map(function ($value): int {
return intval($value['id']);
}, $this->db->executeQuery($idBuilder->getSQL(), $idBuilder->getParameters())->fetchAll());

$builder = $this->db->getQueryBuilder();
$builder->update(ItemMapperV2::TABLE_NAME)
->set('unread', $builder->createParameter('unread'))
->andWhere('id IN (:idList)')
->andWhere('unread != :unread')
->setParameter('unread', false, IQueryBuilder::PARAM_BOOL)
->setParameter('idList', $idList, IQueryBuilder::PARAM_INT_ARRAY);

return $this->db->executeUpdate($builder->getSQL(), $builder->getParameters(), $builder->getParameterTypes());
}
}
Loading

0 comments on commit d51b4a0

Please sign in to comment.