Merge pull request #84 from ArabCoders/dev

Dropped support for alternative database engines.
This commit is contained in:
Abdulmohsen
2022-04-26 20:46:00 +03:00
committed by GitHub
14 changed files with 65 additions and 367 deletions

View File

@@ -1,22 +1,12 @@
# Watch State Sync
# WatchState
CLI based tool to sync watch state between different media servers.
WatchState is a CLI based tool to sync your watch state between different media servers, without relying on 3rd parties
services, like trakt.tv, This tool support `Plex Media Server`, `Emby` and `Jellyfin` out of the box currently, with
plans for future expansion for other media servers.
# Introduction
# Install
Ever wanted to sync your watch state without having to rely on 3rd party service like trakt.tv? then this tool is for
you. I had multiple problems with Plex trakt.tv plugin which led to my account being banned at trakt.tv, and on top of
that the plugin no longer supported. And I like to keep my own data locally if possible.
# Supported media servers.
* Plex
* Emby
* Jellyfin
## Install
create your `docker-compose.yaml` file
create your `docker-compose.yaml` file:
```yaml
version: '3.3'
@@ -26,7 +16,7 @@ services:
container_name: watchstate
restart: unless-stopped
environment:
# For more ENV variables please read at the bottom of README.md
# For more environment variables please read at the bottom of this page.
WS_UID: ${UID:-1000} # Set container operation user id.
WS_GID: ${GID:-1000} # Set container operation group id.
ports:
@@ -43,7 +33,7 @@ $ docker-compose up -d
# First time
Please run the following command to see all available commands you can also run help on each command to get more info.
Run the following command to see all available commands you can also run help on each command to get more info.
```bash
# Show all commands.
@@ -153,7 +143,8 @@ valid cron expression. for example, `0 */3 * * *` it will run every three hours
By default, the official container includes a small http server exposed at port `80`, we officially don't support HTTPS
inside the container for the HTTP server. However, for the adventurous people we expose port 443 as well, as such you
can customize the Caddyfile to support SSL. and do the necessary adjustments. However, do not expect us to help with it.
can customize the `docker/files/nginx.conf` to support SSL. and do the necessary adjustments. However, do not expect us
to help with it.
#### Example nginx reverse proxy.
@@ -194,8 +185,8 @@ it's more secure that way.
#### [WEBHOOK_TOKEN]
Should match the server specific ``webhook.token`` value. in `server.yaml`. if the key does not exist please refer to
the steps described at **Steps to enable webhook servers**.
Should match the server specific ``webhook.token`` value. Refer to the steps described
at **[Steps to enable webhook servers](#enable-webhooks-events-for-specific-server)**.
# Configuring Media servers to send webhook events.
@@ -272,8 +263,8 @@ Click `Save Changes`
Does not send webhooks events for "marked as watched/unwatched", or you added more than 1 item at time i.e. folder
import.
If you have multiuser setup, please will still report the admin account user_id as 1 even though when you get the list
of users ids it shows completely different user ID, so when you initially set up your server for multiuser, select your
If you have multi-user setup, Plex will still report the admin account user id as 1 even though when you get the list
of users ids it shows completely different user ID, so when you initially set up your server for multi-user, select your
admin account and after finishing you have to set the value manually to `1`. to do so please do the following
```bash
@@ -289,15 +280,13 @@ Emby does not send webhooks events for newly added items.
# Jellyfin
None that we are aware of.
If you don't select a user id there, sometimes the plugin will send itemAdd event without user info, and thus will fail
the check if you happen to enable `match user id`.
# Globally supported environment variables.
# Tool specific environment variables.
- (string) `WS_DATA_PATH` Where key data stored (config|db).
- (string) `WS_TMP_DIR` Where temp data stored. (logs|cache). Defaults to `WS_DATA_PATH` if not set.
- (string) `WS_STORAGE_PDO_DSN` PDO Data source Name, if you want to change from sqlite.
- (string) `WS_STORAGE_PDO_USERNAME` PDO username
- (string) `WS_STORAGE_PDO_PASSWORD` PDO password
- (string) `WS_TZ` Set timezone for example, `UTC`
- (bool) `WS_WEBHOOK_DEBUG` enable debug mode for webhook events.
- (bool) `WS_REQUEST_DEBUG` enable debug mode for pre webhook request.
@@ -327,7 +316,7 @@ None that we are aware of.
follows php [strtotime](https://www.php.net/strtotime) function rules.
- (bool) `WS_DEBUG_IMPORT` Whether to log invalid GUID items from server in `${WS_TMP_DIR}/debug`.
# Container specific environment variables
# Container specific environment variables.
- (int) `WS_NO_CHOWN` do not change ownership needed paths inside container.
- (int) `WS_DISABLE_HTTP` disable included HTTP Server.
@@ -339,4 +328,4 @@ None that we are aware of.
# FAQ
For some common questions, Please take look at this [frequently asked questions](FAQ.md) page.
For some common questions, Take look at this [frequently asked questions](FAQ.md) page.

View File

@@ -19,7 +19,7 @@ return (function () {
$config = [
'name' => 'WatchState',
'version' => 'v0.0.0',
'tz' => env('WS_TS', 'UTC'),
'tz' => env('WS_TZ', 'UTC'),
'path' => fixPath(env('WS_DATA_PATH', fn() => env('IN_DOCKER') ? '/config' : realpath(__DIR__ . '/../var'))),
'logs' => [
'prune' => [
@@ -31,18 +31,18 @@ return (function () {
$config['tmpDir'] = fixPath(env('WS_TMP_DIR', fn() => ag($config, 'path')));
$config['storage'] = [
'opts' => [
'dsn' => env('WS_STORAGE_PDO_DSN', fn() => 'sqlite:' . ag($config, 'path') . '/db/watchstate.db'),
'username' => env('WS_STORAGE_PDO_USERNAME', null),
'password' => env('WS_STORAGE_PDO_PASSWORD', null),
'exec' => [
'sqlite' => [
'PRAGMA journal_mode=MEMORY',
'PRAGMA SYNCHRONOUS=OFF'
],
'pgsql' => [],
'mysql' => [],
],
'dsn' => 'sqlite:' . ag($config, 'path') . '/db/watchstate.db',
'username' => null,
'password' => null,
'options' => [
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
],
'exec' => [
'PRAGMA journal_mode=MEMORY',
'PRAGMA SYNCHRONOUS=OFF'
],
];

View File

@@ -51,9 +51,26 @@ return (function (): array {
'shared' => false,
],
PDO::class => [
'class' => function (): PDO {
$pdo = new PDO(dsn: Config::get('storage.dsn'), options: [
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
foreach (Config::get('storage.exec', []) as $cmd) {
$pdo->exec($cmd);
}
return $pdo;
},
],
StorageInterface::class => [
'class' => function (LoggerInterface $logger): StorageInterface {
$adapter = (new PDOAdapter($logger))->setUp(Config::get('storage.opts', []));
'class' => function (LoggerInterface $logger, PDO $pdo): StorageInterface {
$adapter = new PDOAdapter($logger, $pdo);
if (true !== $adapter->isMigrated()) {
$adapter->migrations(StorageInterface::MIGRATE_UP);
@@ -63,6 +80,7 @@ return (function (): array {
},
'args' => [
LoggerInterface::class,
PDO::class,
],
],

View File

@@ -29,11 +29,10 @@ final class EnvCommand extends Command
}
(new Table($output))->setStyle('box')
->setHeaders(['Key', 'Value'])
->setHeaders(['Environment Key', 'Environment Value'])
->setRows($keys)
->render();
return self::SUCCESS;
}
}

View File

@@ -1,32 +0,0 @@
-- # migrate_up
CREATE TABLE `state`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(50) NOT NULL,
`updated` int(11) NOT NULL,
`watched` tinyint(4) NOT NULL DEFAULT 0,
`meta` text DEFAULT NULL,
`guid_plex` varchar(255) DEFAULT NULL,
`guid_imdb` varchar(255) DEFAULT NULL,
`guid_tvdb` varchar(255) DEFAULT NULL,
`guid_tmdb` varchar(255) DEFAULT NULL,
`guid_tvmaze` varchar(255) DEFAULT NULL,
`guid_tvrage` varchar(255) DEFAULT NULL,
`guid_anidb` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `type` (`type`),
KEY `watched` (`watched`),
KEY `updated` (`updated`),
KEY `guid_plex` (`guid_plex`),
KEY `guid_imdb` (`guid_imdb`),
KEY `guid_tvdb` (`guid_tvdb`),
KEY `guid_tmdb` (`guid_tmdb`),
KEY `guid_tvmaze` (`guid_tvmaze`),
KEY `guid_tvrage` (`guid_tvrage`),
KEY `guid_anidb` (`guid_anidb`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- # migrate_down
DROP TABLE IF EXISTS `state`;

View File

@@ -1,35 +0,0 @@
-- # migrate_up
CREATE SEQUENCE state_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1;
CREATE TABLE "state" (
"id" integer DEFAULT nextval('state_id_seq') NOT NULL,
"type" character varying NOT NULL,
"updated" integer NOT NULL,
"watched" smallint NOT NULL,
"meta" json,
"guid_plex" character varying,
"guid_imdb" character varying,
"guid_tvdb" character varying,
"guid_tmdb" character varying,
"guid_tvmaze" character varying,
"guid_tvrage" character varying,
"guid_anidb" character varying,
CONSTRAINT "state_pkey" PRIMARY KEY ("id")
) WITH (oids = false);
CREATE INDEX "state_guid_anidb" ON "state" USING btree ("guid_anidb");
CREATE INDEX "state_guid_imdb" ON "state" USING btree ("guid_imdb");
CREATE INDEX "state_guid_plex" ON "state" USING btree ("guid_plex");
CREATE INDEX "state_guid_tmdb" ON "state" USING btree ("guid_tmdb");
CREATE INDEX "state_guid_tvdb" ON "state" USING btree ("guid_tvdb");
CREATE INDEX "state_guid_tvmaze" ON "state" USING btree ("guid_tvmaze");
CREATE INDEX "state_guid_tvrage" ON "state" USING btree ("guid_tvrage");
CREATE INDEX "state_type" ON "state" USING btree ("type");
CREATE INDEX "state_updated" ON "state" USING btree ("updated");
CREATE INDEX "state_watched" ON "state" USING btree ("watched");
-- # migrate_down
DROP TABLE IF EXISTS "state";
DROP SEQUENCE IF EXISTS state_id_seq;

View File

@@ -18,13 +18,6 @@ use Psr\Log\LoggerInterface;
final class PDOAdapter implements StorageInterface
{
private array $supported = [
'sqlite',
'mysql',
'pgsql'
];
private PDO|null $pdo = null;
private bool $viaCommit = false;
private bool $singleTransaction = false;
@@ -39,57 +32,12 @@ final class PDOAdapter implements StorageInterface
'update' => null,
];
public function __construct(private LoggerInterface $logger)
public function __construct(private LoggerInterface $logger, private PDO $pdo)
{
}
public function setUp(array $opts): StorageInterface
{
if (null === ($opts['dsn'] ?? null)) {
throw new StorageException('No storage.opts.dsn (Data Source Name) was provided.', 10);
}
try {
$this->pdo = new PDO(
$opts['dsn'], $opts['username'] ?? null, $opts['password'] ?? null,
array_replace_recursive(
[
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
],
$opts['options'] ?? []
)
);
} catch (PDOException $e) {
throw new StorageException(sprintf('Unable to connect to storage backend. \'%s\'.', $e->getMessage()));
}
$driver = $this->getDriver();
if (!in_array($driver, $this->supported)) {
throw new StorageException(sprintf('%s Driver is not supported.', $driver), 11);
}
if (null !== ($exec = ag($opts, "exec.{$driver}")) && is_array($exec)) {
foreach ($exec as $cmd) {
$this->pdo->exec($cmd);
}
}
return $this;
}
public function insert(StateInterface $entity): StateInterface
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
try {
$data = $entity->getAll();
@@ -146,13 +94,6 @@ final class PDOAdapter implements StorageInterface
public function getAll(DateTimeInterface|null $date = null, StateInterface|null $class = null): array
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
$arr = [];
$sql = 'SELECT * FROM state';
@@ -174,13 +115,6 @@ final class PDOAdapter implements StorageInterface
public function update(StateInterface $entity): StateInterface
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
try {
$data = $entity->getAll();
@@ -213,13 +147,6 @@ final class PDOAdapter implements StorageInterface
public function matchAnyId(array $ids, StateInterface|null $class = null): StateInterface|null
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
if (null === $class) {
$class = Container::get(StateInterface::class);
}
@@ -277,13 +204,6 @@ final class PDOAdapter implements StorageInterface
public function remove(StateInterface $entity): bool
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
if (null === $entity->id && !$entity->hasGuids()) {
return false;
}
@@ -309,13 +229,6 @@ final class PDOAdapter implements StorageInterface
public function commit(array $entities): array
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
return $this->transactional(function () use ($entities) {
$list = [
StateInterface::TYPE_MOVIE => ['added' => 0, 'updated' => 0, 'failed' => 0],
@@ -360,13 +273,6 @@ final class PDOAdapter implements StorageInterface
public function migrations(string $dir, array $opts = []): mixed
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
$class = new PDOMigrations($this->pdo, $this->logger);
return match (strtolower($dir)) {
@@ -378,13 +284,6 @@ final class PDOAdapter implements StorageInterface
public function isMigrated(): bool
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
return (new PDOMigrations($this->pdo, $this->logger))->isMigrated();
}
@@ -393,13 +292,6 @@ final class PDOAdapter implements StorageInterface
*/
public function makeMigration(string $name, array $opts = []): mixed
{
if (null === $this->pdo) {
throw new StorageException(
afterLast(__CLASS__, '\\') . '->setUp(): method was not called.',
StorageException::SETUP_NOT_CALLED
);
}
return (new PDOMigrations($this->pdo, $this->logger))->make($name);
}
@@ -417,10 +309,6 @@ final class PDOAdapter implements StorageInterface
public function getPdo(): PDO
{
if (null === $this->pdo) {
throw new \RuntimeException('PDO is not initialized yet.');
}
return $this->pdo;
}
@@ -469,22 +357,6 @@ final class PDOAdapter implements StorageInterface
}
}
/**
* Get PDO Driver.
*
* @return string
*/
private function getDriver(): string
{
$driver = $this->pdo->getAttribute($this->pdo::ATTR_DRIVER_NAME);
if (empty($driver) || !is_string($driver)) {
$driver = 'unknown';
}
return strtolower($driver);
}
/**
* Generate SQL Insert Statement.
*

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Libs\Storage\PDO;
use App\Libs\Config;
use App\Libs\Storage\StorageInterface;
use Exception;
use PDO;
@@ -14,15 +13,13 @@ use RuntimeException;
final class PDOMigrations
{
private string $path;
private string $versionFile;
private string $driver;
private array $files = [];
public function __construct(private PDO $pdo, private LoggerInterface $logger)
{
$this->path = __DIR__ . '/Migrations';
$this->path = __DIR__ . '/../../../../migrations';
$this->driver = $this->getDriver();
$this->versionFile = Config::get('path') . sprintf('/db/%s.migration', $this->driver);
}
public function setLogger(LoggerInterface $logger): self
@@ -142,24 +139,12 @@ final class PDOMigrations
private function getVersion(): int
{
if ('sqlite' === $this->driver) {
return (int)$this->pdo->query('PRAGMA user_version')->fetchColumn();
}
if (file_exists($this->versionFile)) {
return (int)file_get_contents($this->versionFile);
}
return 0;
return (int)$this->pdo->query('PRAGMA user_version')->fetchColumn();
}
private function setVersion(int $version): void
{
if ('sqlite' === $this->driver) {
$this->pdo->exec('PRAGMA user_version = ' . $version);
} else {
file_put_contents($this->versionFile, $version);
}
$this->pdo->exec('PRAGMA user_version = ' . $version);
}
private function getDriver(): string

View File

@@ -16,15 +16,6 @@ interface StorageInterface
public const MIGRATE_DOWN = 'down';
/**
* Initiate Driver.
*
* @param array $opts
*
* @return $this
*/
public function setUp(array $opts): self;
/**
* Insert Entity immediately.
*

View File

@@ -9,6 +9,7 @@ use App\Libs\Extends\CliLogger;
use App\Libs\Mappers\Export\ExportMapper;
use App\Libs\Storage\PDO\PDOAdapter;
use App\Libs\Storage\StorageInterface;
use PDO;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
@@ -31,8 +32,7 @@ class ExportMapperTest extends TestCase
$logger = new CliLogger($this->output);
$this->storage = new PDOAdapter($logger);
$this->storage->setUp(['dsn' => 'sqlite::memory:']);
$this->storage = new PDOAdapter($logger, new PDO('sqlite::memory:'));
$this->storage->migrations('up');
$this->mapper = new ExportMapper($this->storage);

View File

@@ -10,6 +10,7 @@ use App\Libs\Extends\CliLogger;
use App\Libs\Mappers\Import\DirectMapper;
use App\Libs\Storage\PDO\PDOAdapter;
use App\Libs\Storage\StorageInterface;
use PDO;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
@@ -32,8 +33,7 @@ class DirectMapperTest extends TestCase
$logger = new CliLogger($this->output);
$this->storage = new PDOAdapter($logger);
$this->storage->setUp(['dsn' => 'sqlite::memory:']);
$this->storage = new PDOAdapter($logger, new PDO('sqlite::memory:'));
$this->storage->migrations('up');
$this->mapper = new DirectMapper($logger, $this->storage);

View File

@@ -10,6 +10,7 @@ use App\Libs\Extends\CliLogger;
use App\Libs\Mappers\Import\MemoryMapper;
use App\Libs\Storage\PDO\PDOAdapter;
use App\Libs\Storage\StorageInterface;
use PDO;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
@@ -32,8 +33,7 @@ class MemoryMapperTest extends TestCase
$logger = new CliLogger($this->output);
$this->storage = new PDOAdapter($logger);
$this->storage->setUp(['dsn' => 'sqlite::memory:']);
$this->storage = new PDOAdapter($logger, new PDO('sqlite::memory:'));
$this->storage->migrations('up');
$this->mapper = new MemoryMapper($logger, $this->storage);

View File

@@ -12,6 +12,7 @@ use App\Libs\Storage\StorageException;
use App\Libs\Storage\StorageInterface;
use DateTimeImmutable;
use Error;
use PDO;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
@@ -31,37 +32,10 @@ class PDOAdapterTest extends TestCase
$this->testMovie = require __DIR__ . '/../Fixtures/MovieEntity.php';
$this->testEpisode = require __DIR__ . '/../Fixtures/EpisodeEntity.php';
$this->storage = new PDOAdapter(new CliLogger($this->output));
$this->storage->setUp(['dsn' => 'sqlite::memory:']);
$this->storage = new PDOAdapter(new CliLogger($this->output), new PDO('sqlite::memory:'));
$this->storage->migrations('up');
}
/** StorageInterface::setUp */
public function test_setup_throw_exception_if_no_dsn(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(10);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->setUp([]);
}
public function test_setup_throw_exception_if_invalid_dsn(): void
{
$this->expectException(StorageException::class);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->setUp(['dsn' => 'not_real_driver::foo']);
}
/** StorageInterface::insert */
public function test_insert_call_without_setup_exception(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(StorageException::SETUP_NOT_CALLED);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->insert(new StateEntity([]));
}
public function test_insert_throw_exception_if_has_id(): void
{
$this->expectException(StorageException::class);
@@ -77,15 +51,6 @@ class PDOAdapterTest extends TestCase
$this->assertSame(1, $item->id);
}
/** StorageInterface::get */
public function test_get_call_without_setup_exception(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(StorageException::SETUP_NOT_CALLED);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->get(new StateEntity([]));
}
public function test_get_conditions(): void
{
$item = new StateEntity($this->testEpisode);
@@ -102,15 +67,6 @@ class PDOAdapterTest extends TestCase
$this->assertSame($modified->getAll(), $this->storage->get($modified)->getAll());
}
/** StorageInterface::getAll */
public function test_getAll_call_without_setup_exception(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(StorageException::SETUP_NOT_CALLED);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->getAll();
}
public function test_getAll_call_without_initialized_container(): void
{
$this->expectException(Error::class);
@@ -132,15 +88,6 @@ class PDOAdapterTest extends TestCase
$this->assertCount(0, $this->storage->getAll(date: new DateTimeImmutable('now'), class: $item));
}
/** StorageInterface::update */
public function test_update_call_without_setup_exception(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(StorageException::SETUP_NOT_CALLED);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->update(new StateEntity([]));
}
public function test_update_call_without_id_exception(): void
{
$this->expectException(StorageException::class);
@@ -161,15 +108,6 @@ class PDOAdapterTest extends TestCase
$this->assertSame($updatedItem->getAll(), $this->storage->get($item)->getAll());
}
/** StorageInterface::update */
public function test_matchAnyId_call_without_setup_exception(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(StorageException::SETUP_NOT_CALLED);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->matchAnyId([]);
}
public function test_matchAnyId_call_without_initialized_container(): void
{
$this->expectException(Error::class);
@@ -209,15 +147,6 @@ class PDOAdapterTest extends TestCase
);
}
/** StorageInterface::remove */
public function test_remove_call_without_setup_exception(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(StorageException::SETUP_NOT_CALLED);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->remove(new StateEntity([]));
}
public function test_remove_conditions(): void
{
$item1 = new StateEntity($this->testEpisode);
@@ -237,15 +166,6 @@ class PDOAdapterTest extends TestCase
$this->assertFalse($this->storage->remove($item3));
}
/** StorageInterface::commit */
public function test_commit_call_without_setup_exception(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(StorageException::SETUP_NOT_CALLED);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->commit([]);
}
public function test_commit_conditions(): void
{
$item1 = new StateEntity($this->testEpisode);
@@ -271,15 +191,6 @@ class PDOAdapterTest extends TestCase
);
}
/** StorageInterface::migrations */
public function test_migrations_call_without_setup_exception(): void
{
$this->expectException(StorageException::class);
$this->expectExceptionCode(StorageException::SETUP_NOT_CALLED);
$storage = new PDOAdapter(new CliLogger($this->output));
$storage->migrations('f');
}
public function test_migrations_call_with_wrong_direction_exception(): void
{
$this->expectException(StorageException::class);