diff --git a/.gitignore b/.gitignore index a1e420d..63d5303 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /var /composer.lock /.php_cs.cache -/.phpunit.result.cache \ No newline at end of file +/.phpunit.result.cache +/.idea diff --git a/composer.json b/composer.json index 9b76649..157780c 100644 --- a/composer.json +++ b/composer.json @@ -11,13 +11,13 @@ ], "require": { "php": "^7.4 || ^8.0", - "doctrine/dbal": "^3", + "doctrine/dbal": "^3|^4", "react/event-loop": "^1" }, "require-dev": { "phpunit/phpunit": "^9", "clue/block-react": "^1", - "react/mysql": "^0.5", + "react/mysql": "^0.6", "clue/reactphp-sqlite": "^1", "voryx/pgasync": "^2" }, diff --git a/src/ConnectionPool.php b/src/ConnectionPool.php index f51f614..37849a2 100644 --- a/src/ConnectionPool.php +++ b/src/ConnectionPool.php @@ -530,14 +530,14 @@ private function releaseConnection(SingleConnection $connection): PromiseInterfa /** @var \Drift\DBAL\ConnectionWorker $worker */ $worker = $this->connections[$connection]; $worker->setLeased(false); - return resolve(); + return resolve(null); } $deferred = $this->deferreds->current(); $this->deferreds->detach($deferred); $deferred->resolve($this->connections[$connection]); - return resolve(); + return resolve(null); } } diff --git a/src/Driver/Exception.php b/src/Driver/Exception.php index 8a3db59..f2222b6 100644 --- a/src/Driver/Exception.php +++ b/src/Driver/Exception.php @@ -42,7 +42,7 @@ public function __construct($message, $sqlState = null, $code = 0, ?Throwable $p $this->sqlState = $sqlState; } - public function getSQLState() + public function getSQLState(): ?string { return $this->sqlState; } diff --git a/src/Driver/PostgreSQL/PostgreSQLDriver.php b/src/Driver/PostgreSQL/PostgreSQLDriver.php index 87e67ad..977b76e 100644 --- a/src/Driver/PostgreSQL/PostgreSQLDriver.php +++ b/src/Driver/PostgreSQL/PostgreSQLDriver.php @@ -15,9 +15,9 @@ namespace Drift\DBAL\Driver\PostgreSQL; +use Doctrine\DBAL\ConnectionException; use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface; use Doctrine\DBAL\Driver\API\PostgreSQL\ExceptionConverter; -use Doctrine\DBAL\Exception; use Doctrine\DBAL\Query; use Doctrine\DBAL\Query\QueryBuilder; use Drift\DBAL\Credentials; @@ -77,7 +77,7 @@ public function query( array $parameters ): PromiseInterface { if ($this->isClosed) { - return reject(new Exception('Connection closed')); + return reject(new ConnectionException('Connection closed')); } /** @@ -134,7 +134,7 @@ public function query( public function insert(QueryBuilder $queryBuilder, string $table, array $values): PromiseInterface { if ($this->isClosed) { - return reject(new Exception('Connection closed')); + return reject(new ConnectionException('Connection closed')); } $queryBuilder = $this->createInsertQuery($queryBuilder, $table, $values); diff --git a/src/Mock/MockedDBALConnection.php b/src/Mock/MockedDBALConnection.php index 9c3099f..64d41af 100644 --- a/src/Mock/MockedDBALConnection.php +++ b/src/Mock/MockedDBALConnection.php @@ -15,142 +15,7 @@ namespace Drift\DBAL\Mock; -use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\ParameterType; -use Doctrine\DBAL\Result; -use Doctrine\DBAL\Statement; -use Doctrine\DBAL\Types\Type; -use Exception; - -/** - * Class MockedDBALConnection. - */ -class MockedDBALConnection extends Connection +final class MockedDBALConnection extends Connection { - /** - * Prepares an SQL statement. - * - * @param string $sql the SQL statement to prepare - * - * @throws \Doctrine\DBAL\Exception - */ - public function prepare(string $sql): Statement - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * BC layer for a wide-spread use-case of old DBAL APIs. - * - * @deprecated This API is deprecated and will be removed after 2022 - */ - public function query(string $sql): Result - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * {@inheritdoc} - * - * @return mixed - */ - public function quote($input, $type = ParameterType::STRING)/*: mixed // <--- from php 8*/ - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * BC layer for a wide-spread use-case of old DBAL APIs. - * - * @deprecated This API is deprecated and will be removed after 2022 - */ - public function exec(string $sql): int - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * {@inheritdoc} - * - * @return string|int|false A string representation of the last inserted ID. - */ - public function lastInsertId($name = null)/*: string|int|false // <--- from php 8 */ - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * {@inheritdoc} - */ - public function beginTransaction(): bool - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * {@inheritdoc} - */ - public function commit(): bool - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * {@inheritdoc} - */ - public function rollBack(): bool - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * {@inheritdoc} - */ - public function errorCode() - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * {@inheritdoc} - */ - public function errorInfo() - { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * Executes an, optionally parametrized, SQL query. - * - * If the query is parametrized, a prepared statement is used. - * If an SQLLogger is configured, the execution is logged. - * - * @param string $sql SQL query - * @param list|array $params Query parameters - * @param array|array $types Parameter types - * - * @throws \Doctrine\DBAL\Exception - */ - public function executeQuery( - string $sql, - array $params = [], - $types = [], - ?QueryCacheProfile $qcp = null - ): Result { - throw new Exception('Mocked method. Unable to be used'); - } - - /** - * BC layer for a wide-spread use-case of old DBAL APIs. - * - * @deprecated This API is deprecated and will be removed after 2022 - * - * @param array $params The query parameters - * @param array $types The parameter types - */ - public function executeUpdate(string $sql, array $params = [], array $types = []): int - { - throw new Exception('Mocked method. Unable to be used'); - } } diff --git a/src/Mock/MockedDriver.php b/src/Mock/MockedDriver.php index e108a79..087567c 100644 --- a/src/Mock/MockedDriver.php +++ b/src/Mock/MockedDriver.php @@ -17,65 +17,76 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver; -use Doctrine\DBAL\Driver\Connection as DriverConnection; use Doctrine\DBAL\Driver\API\ExceptionConverter; +use Doctrine\DBAL\Driver\Connection as DriverConnection; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; +use Doctrine\DBAL\ServerVersionProvider; use Exception; -/** - * Class MockedDriver. - */ -class MockedDriver implements Driver -{ - /** - * {@inheritdoc} - */ - public function connect(array $params, $username = null, $password = null, array $driverOptions = []): DriverConnection +if ((new \ReflectionMethod(Driver::class, 'getDatabasePlatform'))->getNumberOfParameters() === 1) { + final class MockedDriver implements Driver { - throw new Exception('Mocked method. Unable to be used'); - } + private AbstractPlatform $platform; - /** - * {@inheritdoc} - */ - public function getDatabasePlatform(): AbstractPlatform - { - throw new Exception('Mocked method. Unable to be used'); - } + public function __construct(AbstractPlatform $platform) + { + $this->platform = $platform; + } - /** - * Gets the SchemaManager that can be used to inspect and change the underlying - * database schema of the platform this driver connects to. - * - * @return AbstractSchemaManager - */ - public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager - { - throw new Exception('Mocked method. Unable to be used'); - } + public function connect(array $params): DriverConnection + { + throw new Exception('Mocked method. Unable to be used'); + } - /** - * {@inheritdoc} - */ - public function getName() - { - throw new Exception('Mocked method. Unable to be used'); - } + public function getDatabasePlatform(ServerVersionProvider $versionProvider): AbstractPlatform + { + return $this->platform; + } - /** - * {@inheritdoc} - */ - public function getDatabase(Connection $conn) - { - throw new Exception('Mocked method. Unable to be used'); + public function getExceptionConverter(): ExceptionConverter + { + throw new Exception('Mocked method. Unable to be used'); + } } - - /** - * {@inheritdoc} - */ - public function getExceptionConverter(): ExceptionConverter +} else { + final class MockedDriver implements Driver { - throw new Exception('Mocked method. Unable to be used'); + private AbstractPlatform $platform; + + public function __construct(AbstractPlatform $platform) + { + $this->platform = $platform; + } + + public function connect(array $params, $username = null, $password = null, array $driverOptions = []): DriverConnection + { + throw new Exception('Mocked method. Unable to be used'); + } + + public function getDatabasePlatform(): AbstractPlatform + { + return $this->platform; + } + + public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager + { + throw new Exception('Mocked method. Unable to be used'); + } + + public function getName() + { + throw new Exception('Mocked method. Unable to be used'); + } + + public function getDatabase(Connection $conn) + { + throw new Exception('Mocked method. Unable to be used'); + } + + public function getExceptionConverter(): ExceptionConverter + { + throw new Exception('Mocked method. Unable to be used'); + } } } diff --git a/src/SingleConnection.php b/src/SingleConnection.php index e16d37e..e2d3e7f 100644 --- a/src/SingleConnection.php +++ b/src/SingleConnection.php @@ -28,7 +28,6 @@ use React\EventLoop\Loop; use React\EventLoop\TimerInterface; use RuntimeException; -use function React\Promise\map; use React\Promise\PromiseInterface; use function React\Promise\resolve; @@ -163,7 +162,7 @@ public function createQueryBuilder(): QueryBuilder return new QueryBuilder( new MockedDBALConnection([ 'platform' => $this->platform, - ], new MockedDriver()) + ], new MockedDriver($this->platform)) ); } @@ -206,13 +205,17 @@ public function queryBySQL(string $sql, array $parameters = []): PromiseInterfac */ public function executeSQLs(array $sqls): PromiseInterface { - return - map($sqls, function (string $sql) { + $promise = resolve(null); + + foreach ($sqls as $sql) { + $promise = $promise->then(function () use ($sql) { return $this->queryBySQL($sql); - }) - ->then(function () { - return $this; - }); + }); + } + + return $promise->then(function () { + return $this; + }); } /** @@ -305,7 +308,7 @@ public function delete( array $values ): PromiseInterface { if (empty($values)) { - throw InvalidArgumentException::fromEmptyCriteria(); + throw new InvalidArgumentException('Empty criteria was used to build a query'); } $queryBuilder = $this @@ -332,7 +335,7 @@ public function update( array $values ): PromiseInterface { if (empty($id)) { - throw InvalidArgumentException::fromEmptyCriteria(); + throw new InvalidArgumentException('Empty criteria was used to build a query'); } $queryBuilder = $this @@ -401,7 +404,7 @@ public function createTable( bool $autoincrementId = false ): PromiseInterface { if (empty($fields)) { - throw InvalidArgumentException::fromEmptyCriteria(); + throw new InvalidArgumentException('Empty criteria was used to build a query'); } $schema = new Schema(); diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index d7b93da..a37f49e 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -228,7 +228,7 @@ public function testMultipleRows() ->query($queryBuilder ->select('*') ->from('test', 't') - ->where($queryBuilder->expr()->orX( + ->where($queryBuilder->expr()->or( $queryBuilder->expr()->eq('t.id', '?'), $queryBuilder->expr()->eq('t.id', '?') )) @@ -315,7 +315,7 @@ public function testFindShortcut() $this->assertNull($results[1]); $listResults = $results[2]; usort($listResults, function ($a1, $a2) { - return $a1['id'] > $a2['id']; + return $a1['id'] <=> $a2['id']; }); $this->assertSame($listResults, [ diff --git a/tests/SQLiteConnectionTest.php b/tests/SQLiteConnectionTest.php index e1b6937..65b21f3 100644 --- a/tests/SQLiteConnectionTest.php +++ b/tests/SQLiteConnectionTest.php @@ -15,7 +15,7 @@ namespace Drift\DBAL\Tests; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\AbstractPlatform; use Drift\DBAL\Connection; use Drift\DBAL\Credentials; use Drift\DBAL\Driver\SQLite\SQLiteDriver; @@ -32,7 +32,12 @@ class SQLiteConnectionTest extends ConnectionTest */ public function getConnection(LoopInterface $loop): Connection { - $platform = new SqlitePlatform(); + $platformClass = class_exists(\Doctrine\DBAL\Platforms\SQLitePlatform::class) + ? \Doctrine\DBAL\Platforms\SQLitePlatform::class + : \Doctrine\DBAL\Platforms\SqlitePlatform::class; + + /** @var AbstractPlatform $platform */ + $platform = new $platformClass(); return SingleConnection::createConnected(new SQLiteDriver( $loop