From d9da223298f7df4980d06af2abc16589bea71cc4 Mon Sep 17 00:00:00 2001 From: prolic Date: Tue, 26 Jun 2018 19:16:40 +0800 Subject: [PATCH 01/25] use common sql interfaces --- composer.json | 3 ++- src/Connector.php | 14 -------------- src/Link.php | 2 +- src/Pool.php | 3 ++- src/TimeoutConnector.php | 1 + src/functions.php | 1 + test/PgSqlPoolTest.php | 2 +- test/PqPoolTest.php | 2 +- 8 files changed, 9 insertions(+), 19 deletions(-) delete mode 100644 src/Connector.php diff --git a/composer.json b/composer.json index 130dba2..d03a58a 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ } ], "require": { - "amphp/amp": "^2" + "amphp/amp": "^2", + "amphp/sql": "dev-master" }, "require-dev": { "amphp/phpunit-util": "^1", diff --git a/src/Connector.php b/src/Connector.php deleted file mode 100644 index cdcda41..0000000 --- a/src/Connector.php +++ /dev/null @@ -1,14 +0,0 @@ - - */ - public function connect(string $connectionString): Promise; -} diff --git a/src/Link.php b/src/Link.php index 665d46c..76cbf25 100644 --- a/src/Link.php +++ b/src/Link.php @@ -4,7 +4,7 @@ use Amp\Promise; -interface Link extends Executor { +interface Link extends \Amp\Sql\Link { /** * @param int $isolation * diff --git a/src/Pool.php b/src/Pool.php index 3eafd9a..e618f74 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -7,6 +7,7 @@ use Amp\Deferred; use Amp\Loop; use Amp\Promise; +use Amp\Sql\Connector; use function Amp\call; use function Amp\coroutine; @@ -16,7 +17,7 @@ final class Pool implements Link { const DEFAULT_MAX_CONNECTIONS = 100; const DEFAULT_IDLE_TIMEOUT = 60; - /** @var \Amp\Postgres\Connector */ + /** @var \Amp\Sql\Connector */ private $connector; /** @var string */ diff --git a/src/TimeoutConnector.php b/src/TimeoutConnector.php index 14c6c2c..72f47a8 100644 --- a/src/TimeoutConnector.php +++ b/src/TimeoutConnector.php @@ -3,6 +3,7 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\Connector; use Amp\TimeoutCancellationToken; final class TimeoutConnector implements Connector { diff --git a/src/functions.php b/src/functions.php index 22ed60a..dd7fd92 100644 --- a/src/functions.php +++ b/src/functions.php @@ -4,6 +4,7 @@ use Amp\Loop; use Amp\Promise; +use Amp\Sql\Connector; const LOOP_CONNECTOR_IDENTIFIER = Connector::class; diff --git a/test/PgSqlPoolTest.php b/test/PgSqlPoolTest.php index d0fbd3d..99ad6fe 100644 --- a/test/PgSqlPoolTest.php +++ b/test/PgSqlPoolTest.php @@ -2,11 +2,11 @@ namespace Amp\Postgres\Test; -use Amp\Postgres\Connector; use Amp\Postgres\Link; use Amp\Postgres\PgSqlConnection; use Amp\Postgres\Pool; use Amp\Promise; +use Amp\Sql\Connector; use Amp\Success; /** diff --git a/test/PqPoolTest.php b/test/PqPoolTest.php index f549f31..7967113 100644 --- a/test/PqPoolTest.php +++ b/test/PqPoolTest.php @@ -2,11 +2,11 @@ namespace Amp\Postgres\Test; -use Amp\Postgres\Connector; use Amp\Postgres\Link; use Amp\Postgres\Pool; use Amp\Postgres\PqConnection; use Amp\Promise; +use Amp\Sql\Connector; use Amp\Success; /** From 23b0ec44a224dfc88fc1e54f17f140bff97b4510 Mon Sep 17 00:00:00 2001 From: prolic Date: Wed, 27 Jun 2018 19:57:06 +0800 Subject: [PATCH 02/25] update changes after review --- src/CommandResult.php | 12 ------------ src/Connection.php | 2 +- src/ConnectionException.php | 2 ++ src/Connector.php | 14 ++++++++++++++ src/Executor.php | 28 ++++++++++++++-------------- src/FailureException.php | 6 ------ src/Link.php | 12 ++++++------ src/Listener.php | 2 +- src/ParseException.php | 2 ++ src/PgSqlCommandResult.php | 2 ++ src/PgSqlHandle.php | 11 +++++++---- src/PgSqlResultSet.php | 1 + src/Pool.php | 6 +++--- src/PqCommandResult.php | 1 + src/PqHandle.php | 16 +++++++++------- src/QueryError.php | 6 ------ src/QueryExecutionError.php | 2 ++ src/ResultSet.php | 16 ++-------------- src/Statement.php | 2 +- src/TimeoutConnector.php | 3 ++- src/Transaction.php | 13 +++++++------ src/functions.php | 3 +-- test/AbstractConnectTest.php | 6 +++--- test/AbstractLinkTest.php | 14 +++++++------- test/FunctionsTest.php | 6 +++--- test/PgSqlPoolTest.php | 2 +- test/PqPoolTest.php | 2 +- 27 files changed, 93 insertions(+), 99 deletions(-) delete mode 100644 src/CommandResult.php create mode 100644 src/Connector.php delete mode 100644 src/FailureException.php delete mode 100644 src/QueryError.php diff --git a/src/CommandResult.php b/src/CommandResult.php deleted file mode 100644 index 93b124f..0000000 --- a/src/CommandResult.php +++ /dev/null @@ -1,12 +0,0 @@ -busy) { diff --git a/src/ConnectionException.php b/src/ConnectionException.php index bcc1b5d..0cdb84c 100644 --- a/src/ConnectionException.php +++ b/src/ConnectionException.php @@ -2,5 +2,7 @@ namespace Amp\Postgres; +use Amp\Sql\FailureException; + class ConnectionException extends FailureException { } diff --git a/src/Connector.php b/src/Connector.php new file mode 100644 index 0000000..cdcda41 --- /dev/null +++ b/src/Connector.php @@ -0,0 +1,14 @@ + + */ + public function connect(string $connectionString): Promise; +} diff --git a/src/Executor.php b/src/Executor.php index 4585dc5..178026c 100644 --- a/src/Executor.php +++ b/src/Executor.php @@ -10,11 +10,11 @@ interface Executor { /** * @param string $sql * - * @return \Amp\Promise<\Amp\Postgres\CommandResult|\Amp\Postgres\TupleResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * - * @throws \Amp\Postgres\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Postgres\ConnectionException If the connection to the database is lost. - * @throws \Amp\Postgres\QueryError If the operation fails due to an error in the query (such as a syntax error). + * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. + * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. + * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). */ public function query(string $sql): Promise; @@ -22,11 +22,11 @@ public function query(string $sql): Promise; * @param string $sql * @param mixed[] $params * - * @return \Amp\Promise<\Amp\Postgres\CommandResult|\Amp\Postgres\TupleResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * - * @throws \Amp\Postgres\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Postgres\ConnectionException If the connection to the database is lost. - * @throws \Amp\Postgres\QueryError If the operation fails due to an error in the query (such as a syntax error). + * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. + * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. + * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). */ public function execute(string $sql, array $params = []): Promise; @@ -35,9 +35,9 @@ public function execute(string $sql, array $params = []): Promise; * * @return \Amp\Promise<\Amp\Postgres\Statement> * - * @throws \Amp\Postgres\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Postgres\ConnectionException If the connection to the database is lost. - * @throws \Amp\Postgres\QueryError If the operation fails due to an error in the query (such as a syntax error). + * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. + * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. + * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). */ public function prepare(string $sql): Promise; @@ -45,10 +45,10 @@ public function prepare(string $sql): Promise; * @param string $channel Channel name. * @param string $payload Notification payload. * - * @return \Amp\Promise<\Amp\Postgres\CommandResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * - * @throws \Amp\Postgres\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Postgres\ConnectionException If the connection to the database is lost. + * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. + * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. */ public function notify(string $channel, string $payload = ""): Promise; diff --git a/src/FailureException.php b/src/FailureException.php deleted file mode 100644 index 8250530..0000000 --- a/src/FailureException.php +++ /dev/null @@ -1,6 +0,0 @@ - * - * @throws \Amp\Postgres\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Postgres\ConnectionException If the connection to the database is lost. - * @throws \Amp\Postgres\QueryError If the operation fails due to an error in the query (such as a syntax error). + * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. + * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. + * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). */ public function transaction(int $isolation = Transaction::COMMITTED): Promise; @@ -21,9 +21,9 @@ public function transaction(int $isolation = Transaction::COMMITTED): Promise; * * @return \Amp\Promise<\Amp\Postgres\Listener> * - * @throws \Amp\Postgres\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Postgres\ConnectionException If the connection to the database is lost. - * @throws \Amp\Postgres\QueryError If the operation fails due to an error in the query (such as a syntax error). + * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. + * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. + * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). */ public function listen(string $channel): Promise; } diff --git a/src/Listener.php b/src/Listener.php index 71ee9eb..22e9495 100644 --- a/src/Listener.php +++ b/src/Listener.php @@ -69,7 +69,7 @@ public function getChannel(): string { /** * Unlistens from the channel. No more values will be emitted from this listener. * - * @return \Amp\Promise<\Amp\Postgres\CommandResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * * @throws \Error If this method was previously invoked. */ diff --git a/src/ParseException.php b/src/ParseException.php index 277f7e7..4c08e6b 100644 --- a/src/ParseException.php +++ b/src/ParseException.php @@ -2,6 +2,8 @@ namespace Amp\Postgres; +use Amp\Sql\FailureException; + class ParseException extends FailureException { public function __construct(string $message = '') { $message = "Parse error while splitting array" . (($message === '') ? '' : ": " . $message); diff --git a/src/PgSqlCommandResult.php b/src/PgSqlCommandResult.php index 0d8272a..bae37fc 100644 --- a/src/PgSqlCommandResult.php +++ b/src/PgSqlCommandResult.php @@ -2,6 +2,8 @@ namespace Amp\Postgres; +use Amp\Sql\CommandResult; + final class PgSqlCommandResult implements CommandResult { /** @var resource PostgreSQL result resource. */ private $handle; diff --git a/src/PgSqlHandle.php b/src/PgSqlHandle.php index 6a4845b..1ddfc1d 100644 --- a/src/PgSqlHandle.php +++ b/src/PgSqlHandle.php @@ -7,6 +7,9 @@ use Amp\Emitter; use Amp\Loop; use Amp\Promise; +use Amp\Sql\ConnectionException; +use Amp\Sql\FailureException; +use Amp\Sql\QueryError; use Amp\Success; use function Amp\call; @@ -198,7 +201,7 @@ public function lastUsedAt(): int { * * @resolve resource * - * @throws \Amp\Postgres\FailureException + * @throws FailureException */ private function send(callable $function, ...$args): \Generator { while ($this->deferred) { @@ -238,10 +241,10 @@ private function send(callable $function, ...$args): \Generator { /** * @param resource $result PostgreSQL result resource. * - * @return \Amp\Postgres\CommandResult|\Amp\Postgres\ResultSet + * @return \Amp\Sql\CommandResult|\Amp\Postgres\ResultSet * - * @throws \Amp\Postgres\FailureException - * @throws \Amp\Postgres\QueryError + * @throws FailureException + * @throws QueryError */ private function createResult($result) { switch (\pg_result_status($result, \PGSQL_STATUS_LONG)) { diff --git a/src/PgSqlResultSet.php b/src/PgSqlResultSet.php index e2476f9..d66d977 100644 --- a/src/PgSqlResultSet.php +++ b/src/PgSqlResultSet.php @@ -3,6 +3,7 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\FailureException; use Amp\Success; final class PgSqlResultSet implements ResultSet { diff --git a/src/Pool.php b/src/Pool.php index e618f74..b06819a 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -7,7 +7,7 @@ use Amp\Deferred; use Amp\Loop; use Amp\Promise; -use Amp\Sql\Connector; +use Amp\Sql\FailureException; use function Amp\call; use function Amp\coroutine; @@ -17,7 +17,7 @@ final class Pool implements Link { const DEFAULT_MAX_CONNECTIONS = 100; const DEFAULT_IDLE_TIMEOUT = 60; - /** @var \Amp\Sql\Connector */ + /** @var Connector */ private $connector; /** @var string */ @@ -180,7 +180,7 @@ public function getMaxConnections(): int { * * @resolve \Amp\Postgres\Connection * - * @throws \Amp\Postgres\FailureException If creating a new connection fails. + * @throws FailureException If creating a new connection fails. * @throws \Error If the pool has been closed. */ private function pop(): \Generator { diff --git a/src/PqCommandResult.php b/src/PqCommandResult.php index 5fac65e..37ba938 100644 --- a/src/PqCommandResult.php +++ b/src/PqCommandResult.php @@ -2,6 +2,7 @@ namespace Amp\Postgres; +use Amp\Sql\CommandResult; use pq; final class PqCommandResult implements CommandResult { diff --git a/src/PqHandle.php b/src/PqHandle.php index f919f9f..1d78f8e 100644 --- a/src/PqHandle.php +++ b/src/PqHandle.php @@ -8,6 +8,8 @@ use Amp\Emitter; use Amp\Loop; use Amp\Promise; +use Amp\Sql\ConnectionException; +use Amp\Sql\FailureException; use Amp\Success; use pq; use function Amp\call; @@ -173,9 +175,9 @@ private function free() { * * @return \Generator * - * @resolve \Amp\Postgres\CommandResult|\Amp\Postgres\TupleResult|\pq\Statement + * @resolve \Amp\Sql\CommandResult|\pq\Statement * - * @throws \Amp\Postgres\FailureException + * @throws FailureException */ private function send(callable $method, ...$args): \Generator { while ($this->busy) { @@ -294,8 +296,8 @@ private function release() { * @param string $name * @param array $params * - * @return \Amp\Promise - * @throws \Amp\Postgres\FailureException + * @return Promise + * @throws FailureException */ public function statementExecute(string $name, array $params): Promise { \assert(isset($this->statements[$name]), "Named statement not found when executing"); @@ -308,9 +310,9 @@ public function statementExecute(string $name, array $params): Promise { /** * @param string $name * - * @return \Amp\Promise + * @return Promise * - * @throws \Amp\Postgres\FailureException + * @throws FailureException */ public function statementDeallocate(string $name): Promise { if (!$this->handle) { @@ -439,7 +441,7 @@ static function (string $channel, string $message, int $pid) use ($emitter) { /** * @param string $channel * - * @return \Amp\Promise + * @return Promise * * @throws \Error */ diff --git a/src/QueryError.php b/src/QueryError.php deleted file mode 100644 index 5fea331..0000000 --- a/src/QueryError.php +++ /dev/null @@ -1,6 +0,0 @@ - + * @return \Amp\Promise<\Amp\Sql\CommandResult> */ public function execute(array $params = []): Promise; diff --git a/src/TimeoutConnector.php b/src/TimeoutConnector.php index 72f47a8..20ec37f 100644 --- a/src/TimeoutConnector.php +++ b/src/TimeoutConnector.php @@ -4,6 +4,7 @@ use Amp\Promise; use Amp\Sql\Connector; +use Amp\Sql\FailureException; use Amp\TimeoutCancellationToken; final class TimeoutConnector implements Connector { @@ -22,7 +23,7 @@ public function __construct(int $timeout = self::DEFAULT_TIMEOUT) { /** * {@inheritdoc} * - * @throws \Amp\Postgres\FailureException If connecting fails. + * @throws FailureException If connecting fails. * * @throws \Error If neither ext-pgsql or pecl-pq is loaded. */ diff --git a/src/Transaction.php b/src/Transaction.php index 4656028..6ad13eb 100644 --- a/src/Transaction.php +++ b/src/Transaction.php @@ -3,8 +3,9 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\Transaction as SqlTransaction; -final class Transaction implements Handle, Operation { +final class Transaction implements Handle, SqlTransaction { const UNCOMMITTED = 0; const COMMITTED = 1; const REPEATABLE = 2; @@ -189,7 +190,7 @@ public function notify(string $channel, string $payload = ""): Promise { /** * Commits the transaction and makes it inactive. * - * @return \Amp\Promise<\Amp\Postgres\CommandResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ @@ -208,7 +209,7 @@ public function commit(): Promise { /** * Rolls back the transaction and makes it inactive. * - * @return \Amp\Promise<\Amp\Postgres\CommandResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ @@ -229,7 +230,7 @@ public function rollback(): Promise { * * @param string $identifier Savepoint identifier. * - * @return \Amp\Promise<\Amp\Postgres\CommandResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ @@ -242,7 +243,7 @@ public function savepoint(string $identifier): Promise { * * @param string $identifier Savepoint identifier. * - * @return \Amp\Promise<\Amp\Postgres\CommandResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ @@ -255,7 +256,7 @@ public function rollbackTo(string $identifier): Promise { * * @param string $identifier Savepoint identifier. * - * @return \Amp\Promise<\Amp\Postgres\CommandResult> + * @return \Amp\Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ diff --git a/src/functions.php b/src/functions.php index dd7fd92..4f7e6b2 100644 --- a/src/functions.php +++ b/src/functions.php @@ -4,7 +4,6 @@ use Amp\Loop; use Amp\Promise; -use Amp\Sql\Connector; const LOOP_CONNECTOR_IDENTIFIER = Connector::class; @@ -29,7 +28,7 @@ function connector(Connector $connector = null): Connector { * * @return \Amp\Promise<\Amp\Postgres\Connection> * - * @throws \Amp\Postgres\FailureException If connecting fails. + * @throws \Amp\Sql\FailureException If connecting fails. * * @throws \Error If neither ext-pgsql or pecl-pq is loaded. * diff --git a/test/AbstractConnectTest.php b/test/AbstractConnectTest.php index a80acd1..293369c 100644 --- a/test/AbstractConnectTest.php +++ b/test/AbstractConnectTest.php @@ -54,7 +54,7 @@ public function testConnectCancellationAfterConnect() { /** * @depends testConnectCancellationBeforeConnect - * @expectedException \Amp\Postgres\FailureException + * @expectedException \Amp\Sql\FailureException */ public function testConnectInvalidUser() { Loop::run(function () { @@ -64,7 +64,7 @@ public function testConnectInvalidUser() { /** * @depends testConnectCancellationBeforeConnect - * @expectedException \Amp\Postgres\FailureException + * @expectedException \Amp\Sql\FailureException */ public function testConnectInvalidConnectionString() { Loop::run(function () { @@ -74,7 +74,7 @@ public function testConnectInvalidConnectionString() { /** * @depends testConnectCancellationBeforeConnect - * @expectedException \Amp\Postgres\FailureException + * @expectedException \Amp\Sql\FailureException */ public function testConnectInvalidHost() { Loop::run(function () { diff --git a/test/AbstractLinkTest.php b/test/AbstractLinkTest.php index f05c7f6..ebc7dff 100644 --- a/test/AbstractLinkTest.php +++ b/test/AbstractLinkTest.php @@ -5,15 +5,15 @@ use Amp\Coroutine; use Amp\Delayed; use Amp\Loop; -use Amp\Postgres\CommandResult; use Amp\Postgres\Link; use Amp\Postgres\Listener; -use Amp\Postgres\QueryError; use Amp\Postgres\QueryExecutionError; use Amp\Postgres\ResultSet; use Amp\Postgres\Statement; use Amp\Postgres\Transaction; use Amp\Postgres\TransactionError; +use Amp\Sql\CommandResult; +use Amp\Sql\QueryError; use PHPUnit\Framework\TestCase; abstract class AbstractLinkTest extends TestCase { @@ -86,7 +86,7 @@ public function testQueryWithUnconsumedTupleResult() { public function testQueryWithCommandResult() { Loop::run(function () { - /** @var \Amp\Postgres\CommandResult $result */ + /** @var CommandResult $result */ $result = yield $this->connection->query("INSERT INTO test VALUES ('canon', 'jp')"); $this->assertInstanceOf(CommandResult::class, $result); @@ -95,18 +95,18 @@ public function testQueryWithCommandResult() { } /** - * @expectedException \Amp\Postgres\QueryError + * @expectedException QueryError */ public function testQueryWithEmptyQuery() { Loop::run(function () { - /** @var \Amp\Postgres\CommandResult $result */ + /** @var \Amp\Sql\CommandResult $result */ $result = yield $this->connection->query(''); }); } public function testQueryWithSyntaxError() { Loop::run(function () { - /** @var \Amp\Postgres\CommandResult $result */ + /** @var \Amp\Sql\CommandResult $result */ try { $result = yield $this->connection->query("SELECT & FROM test"); $this->fail(\sprintf("An instance of %s was expected to be thrown", QueryExecutionError::class)); @@ -640,7 +640,7 @@ public function testNotify() { /** * @depends testListen - * @expectedException \Amp\Postgres\QueryError + * @expectedException QueryError * @expectedExceptionMessage Already listening on channel */ public function testListenOnSameChannel() { diff --git a/test/FunctionsTest.php b/test/FunctionsTest.php index 494e776..153db1b 100644 --- a/test/FunctionsTest.php +++ b/test/FunctionsTest.php @@ -22,7 +22,7 @@ public function testConnect() { } /** - * @expectedException \Amp\Postgres\FailureException + * @expectedException \Amp\Sql\FailureException */ public function testConnectInvalidUser() { Loop::run(function () { @@ -31,7 +31,7 @@ public function testConnectInvalidUser() { } /** - * @expectedException \Amp\Postgres\FailureException + * @expectedException \Amp\Sql\FailureException */ public function testConnectInvalidConnectionString() { Loop::run(function () { @@ -40,7 +40,7 @@ public function testConnectInvalidConnectionString() { } /** - * @expectedException \Amp\Postgres\FailureException + * @expectedException \Amp\Sql\FailureException */ public function testConnectInvalidHost() { Loop::run(function () { diff --git a/test/PgSqlPoolTest.php b/test/PgSqlPoolTest.php index 99ad6fe..d0fbd3d 100644 --- a/test/PgSqlPoolTest.php +++ b/test/PgSqlPoolTest.php @@ -2,11 +2,11 @@ namespace Amp\Postgres\Test; +use Amp\Postgres\Connector; use Amp\Postgres\Link; use Amp\Postgres\PgSqlConnection; use Amp\Postgres\Pool; use Amp\Promise; -use Amp\Sql\Connector; use Amp\Success; /** diff --git a/test/PqPoolTest.php b/test/PqPoolTest.php index 7967113..f549f31 100644 --- a/test/PqPoolTest.php +++ b/test/PqPoolTest.php @@ -2,11 +2,11 @@ namespace Amp\Postgres\Test; +use Amp\Postgres\Connector; use Amp\Postgres\Link; use Amp\Postgres\Pool; use Amp\Postgres\PqConnection; use Amp\Promise; -use Amp\Sql\Connector; use Amp\Success; /** From 7dc3917b2d48cf9f8acedcd80a15d5183717e50c Mon Sep 17 00:00:00 2001 From: prolic Date: Thu, 28 Jun 2018 16:31:41 +0800 Subject: [PATCH 03/25] move connector + connection config --- src/Connector.php | 14 -------------- src/Pool.php | 1 + src/TimeoutConnector.php | 4 +++- src/functions.php | 1 + test/PgSqlPoolTest.php | 2 +- test/PqPoolTest.php | 2 +- 6 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 src/Connector.php diff --git a/src/Connector.php b/src/Connector.php deleted file mode 100644 index cdcda41..0000000 --- a/src/Connector.php +++ /dev/null @@ -1,14 +0,0 @@ - - */ - public function connect(string $connectionString): Promise; -} diff --git a/src/Pool.php b/src/Pool.php index b06819a..b7e2143 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -7,6 +7,7 @@ use Amp\Deferred; use Amp\Loop; use Amp\Promise; +use Amp\Sql\Connector; use Amp\Sql\FailureException; use function Amp\call; use function Amp\coroutine; diff --git a/src/TimeoutConnector.php b/src/TimeoutConnector.php index 20ec37f..054d0ea 100644 --- a/src/TimeoutConnector.php +++ b/src/TimeoutConnector.php @@ -3,6 +3,7 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\ConnectionConfig; use Amp\Sql\Connector; use Amp\Sql\FailureException; use Amp\TimeoutCancellationToken; @@ -27,8 +28,9 @@ public function __construct(int $timeout = self::DEFAULT_TIMEOUT) { * * @throws \Error If neither ext-pgsql or pecl-pq is loaded. */ - public function connect(string $connectionString): Promise { + public function connect(ConnectionConfig $connectionConfig): Promise { $token = new TimeoutCancellationToken($this->timeout); + $connectionString = $connectionConfig->connectionString(); if (\extension_loaded("pq")) { return PqConnection::connect($connectionString, $token); diff --git a/src/functions.php b/src/functions.php index 4f7e6b2..2f1f3d5 100644 --- a/src/functions.php +++ b/src/functions.php @@ -4,6 +4,7 @@ use Amp\Loop; use Amp\Promise; +use Amp\Sql\Connector; const LOOP_CONNECTOR_IDENTIFIER = Connector::class; diff --git a/test/PgSqlPoolTest.php b/test/PgSqlPoolTest.php index d0fbd3d..f401c07 100644 --- a/test/PgSqlPoolTest.php +++ b/test/PgSqlPoolTest.php @@ -2,7 +2,7 @@ namespace Amp\Postgres\Test; -use Amp\Postgres\Connector; +use Amp\Sql\Connector; use Amp\Postgres\Link; use Amp\Postgres\PgSqlConnection; use Amp\Postgres\Pool; diff --git a/test/PqPoolTest.php b/test/PqPoolTest.php index f549f31..7967113 100644 --- a/test/PqPoolTest.php +++ b/test/PqPoolTest.php @@ -2,11 +2,11 @@ namespace Amp\Postgres\Test; -use Amp\Postgres\Connector; use Amp\Postgres\Link; use Amp\Postgres\Pool; use Amp\Postgres\PqConnection; use Amp\Promise; +use Amp\Sql\Connector; use Amp\Success; /** From c503e0bd516b923d9e61bc23915e3bffec50859b Mon Sep 17 00:00:00 2001 From: prolic Date: Thu, 28 Jun 2018 21:33:14 +0800 Subject: [PATCH 04/25] refactor connection --- src/Connection.php | 29 +++++++++++++-------------- src/ConnectionException.php | 8 -------- src/PgSqlConnection.php | 39 +++++++++++++++++++++---------------- src/PqConnection.php | 27 +++++++++++-------------- src/TimeoutConnector.php | 28 +++++++++++++++++--------- src/functions.php | 5 +++-- test/PgSqlPoolTest.php | 3 +-- 7 files changed, 70 insertions(+), 69 deletions(-) delete mode 100644 src/ConnectionException.php diff --git a/src/Connection.php b/src/Connection.php index 4c8d79b..4568798 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -2,40 +2,39 @@ namespace Amp\Postgres; -use Amp\CallableMaker; use Amp\CancellationToken; use Amp\Deferred; +use Amp\NullCancellationToken; use Amp\Promise; +use Amp\Sql\ConnectionConfig; use function Amp\call; abstract class Connection implements Handle, Link { - use CallableMaker; - /** @var \Amp\Postgres\Handle */ - private $handle; + protected $handle; /** @var \Amp\Deferred|null Used to only allow one transaction at a time. */ private $busy; /** @var callable */ - private $release; + protected $release; - /** - * @param string $connectionString - * @param \Amp\CancellationToken $token - * - * @return \Amp\Promise<\Amp\Postgres\Connection> - */ - abstract public static function connect(string $connectionString, CancellationToken $token = null): Promise; + /** @var ConnectionConfig */ + protected $config; + + /** @var CancellationToken */ + protected $token; /** * @param \Amp\Postgres\Handle $handle */ - public function __construct(Handle $handle) { - $this->handle = $handle; - $this->release = $this->callableFromInstanceMethod("release"); + public function __construct(ConnectionConfig $config, CancellationToken $token = null) { + $this->config = $config; + $this->token = $token ?? new NullCancellationToken(); } + abstract public function connect(): Promise; + /** * {@inheritdoc} */ diff --git a/src/ConnectionException.php b/src/ConnectionException.php deleted file mode 100644 index 0cdb84c..0000000 --- a/src/ConnectionException.php +++ /dev/null @@ -1,8 +0,0 @@ - - * - * @throws \Error If pecl-ev is used as a loop extension. */ - public static function connect(string $connectionString, CancellationToken $token = null): Promise { - // @codeCoverageIgnoreStart - if (Loop::get()->getHandle() instanceof \EvLoop) { - throw new \Error('ext-pgsql is not compatible with pecl-ev; use pecl-pq or a different loop extension'); - } // @codeCoverageIgnoreEnd - - $connectionString = \str_replace(";", " ", $connectionString); + public function connect(): Promise { + $connectionString = \str_replace(";", " ", $this->config->connectionString()); if (!$connection = @\pg_connect($connectionString, \PGSQL_CONNECT_ASYNC | \PGSQL_CONNECT_FORCE_NEW)) { return new Failure(new ConnectionException("Failed to create connection resource")); @@ -53,7 +50,9 @@ public static function connect(string $connectionString, CancellationToken $toke return; case \PGSQL_POLLING_OK: - $deferred->resolve(new self($connection, $resource)); + $this->handle = new PgSqlHandle($connection, $resource); + $this->release = $this->callableFromInstanceMethod("release"); + $deferred->resolve(); return; } }; @@ -63,15 +62,14 @@ public static function connect(string $connectionString, CancellationToken $toke $promise = $deferred->promise(); - $token = $token ?? new NullCancellationToken; - $id = $token->subscribe([$deferred, "fail"]); + $id = $this->token->subscribe([$deferred, "fail"]); - $promise->onResolve(function ($exception) use ($connection, $poll, $await, $id, $token) { + $promise->onResolve(function ($exception) use ($connection, $poll, $await, $id) { if ($exception) { \pg_close($connection); } - $token->unsubscribe($id); + $this->token->unsubscribe($id); Loop::cancel($poll); Loop::cancel($await); }); @@ -82,8 +80,15 @@ public static function connect(string $connectionString, CancellationToken $toke /** * @param resource $handle PostgreSQL connection handle. * @param resource $socket PostgreSQL connection stream socket. + * + * @throws \Error If pecl-ev is used as a loop extension. */ - public function __construct($handle, $socket) { - parent::__construct(new PgSqlHandle($handle, $socket)); + public function __construct(ConnectionConfig $config, CancellationToken $token = null) { + // @codeCoverageIgnoreStart + if (Loop::get()->getHandle() instanceof \EvLoop) { + throw new \Error('ext-pgsql is not compatible with pecl-ev; use pecl-pq or a different loop extension'); + } // @codeCoverageIgnoreEnd + + parent::__construct($config, $token); } } diff --git a/src/PqConnection.php b/src/PqConnection.php index af58224..63a8986 100644 --- a/src/PqConnection.php +++ b/src/PqConnection.php @@ -2,23 +2,25 @@ namespace Amp\Postgres; -use Amp\CancellationToken; +use Amp\CallableMaker; use Amp\Deferred; use Amp\Failure; use Amp\Loop; -use Amp\NullCancellationToken; use Amp\Promise; +use Amp\Sql\ConnectionException; use pq; final class PqConnection extends Connection { + use CallableMaker; + /** * @param string $connectionString * @param \Amp\CancellationToken $token * * @return \Amp\Promise<\Amp\Postgres\PgSqlConnection> */ - public static function connect(string $connectionString, CancellationToken $token = null): Promise { - $connectionString = \str_replace(";", " ", $connectionString); + public function connect(): Promise { + $connectionString = \str_replace(";", " ", $this->config->connectionString()); try { $connection = new pq\Connection($connectionString, pq\Connection::ASYNC); @@ -44,7 +46,8 @@ public static function connect(string $connectionString, CancellationToken $toke return; case pq\Connection::POLLING_OK: - $deferred->resolve(new self($connection)); + $this->handle = new PqHandle($connection); + $deferred->resolve(); return; } }; @@ -54,22 +57,14 @@ public static function connect(string $connectionString, CancellationToken $toke $promise = $deferred->promise(); - $token = $token ?? new NullCancellationToken; - $id = $token->subscribe([$deferred, "fail"]); + $id = $this->token->subscribe([$deferred, "fail"]); - $promise->onResolve(function () use ($poll, $await, $id, $token) { - $token->unsubscribe($id); + $promise->onResolve(function () use ($poll, $await, $id) { + $this->token->unsubscribe($id); Loop::cancel($poll); Loop::cancel($await); }); return $promise; } - - /** - * @param \pq\Connection $handle - */ - public function __construct(pq\Connection $handle) { - parent::__construct(new PqHandle($handle)); - } } diff --git a/src/TimeoutConnector.php b/src/TimeoutConnector.php index 054d0ea..291d831 100644 --- a/src/TimeoutConnector.php +++ b/src/TimeoutConnector.php @@ -2,6 +2,7 @@ namespace Amp\Postgres; +use function Amp\call; use Amp\Promise; use Amp\Sql\ConnectionConfig; use Amp\Sql\Connector; @@ -29,17 +30,26 @@ public function __construct(int $timeout = self::DEFAULT_TIMEOUT) { * @throws \Error If neither ext-pgsql or pecl-pq is loaded. */ public function connect(ConnectionConfig $connectionConfig): Promise { - $token = new TimeoutCancellationToken($this->timeout); - $connectionString = $connectionConfig->connectionString(); + return call(function () use ($connectionConfig) { + $token = new TimeoutCancellationToken($this->timeout); - if (\extension_loaded("pq")) { - return PqConnection::connect($connectionString, $token); - } + if (\extension_loaded("pq")) { + $connection = new PqConnection($connectionConfig, $token); - if (\extension_loaded("pgsql")) { - return PgSqlConnection::connect($connectionString, $token); - } + yield $connection->connect(); - throw new \Error("amphp/postgres requires either pecl-pq or ext-pgsql"); + return $connection; + } + + if (\extension_loaded("pgsql")) { + $connection = new PgSqlConnection($connectionConfig, $token); + + yield $connection->connect(); + + return $connection; + } + + throw new \Error("amphp/postgres requires either pecl-pq or ext-pgsql"); + }); } } diff --git a/src/functions.php b/src/functions.php index 2f1f3d5..3d7ed47 100644 --- a/src/functions.php +++ b/src/functions.php @@ -4,6 +4,7 @@ use Amp\Loop; use Amp\Promise; +use Amp\Sql\ConnectionConfig; use Amp\Sql\Connector; const LOOP_CONNECTOR_IDENTIFIER = Connector::class; @@ -35,8 +36,8 @@ function connector(Connector $connector = null): Connector { * * @codeCoverageIgnore */ -function connect(string $connectionString): Promise { - return connector()->connect($connectionString); +function connect(ConnectionConfig $config): Promise { + return connector()->connect($config); } /** diff --git a/test/PgSqlPoolTest.php b/test/PgSqlPoolTest.php index f401c07..6393d50 100644 --- a/test/PgSqlPoolTest.php +++ b/test/PgSqlPoolTest.php @@ -30,9 +30,8 @@ public function createLink(string $connectionString): Link { if (!isset($this->handles[$count])) { $this->fail("createConnection called too many times"); } - $handle = $this->handles[$count]; ++$count; - return new Success(new PgSqlConnection($handle, \pg_socket($handle))); + return new Success(); })); $pool = new Pool('connection string', \count($this->handles), $connector); From e203649dd4ab202a2dd959c5a58e4c16eb04acc1 Mon Sep 17 00:00:00 2001 From: prolic Date: Thu, 28 Jun 2018 23:02:17 +0800 Subject: [PATCH 05/25] update connection and pool --- src/Connection.php | 3 ++- src/Pool.php | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Connection.php b/src/Connection.php index 4568798..db95451 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -6,10 +6,11 @@ use Amp\Deferred; use Amp\NullCancellationToken; use Amp\Promise; +use Amp\Sql\Connection as SqlConnection; use Amp\Sql\ConnectionConfig; use function Amp\call; -abstract class Connection implements Handle, Link { +abstract class Connection implements SqlConnection, Handle { /** @var \Amp\Postgres\Handle */ protected $handle; diff --git a/src/Pool.php b/src/Pool.php index b7e2143..94f2f6f 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -9,10 +9,12 @@ use Amp\Promise; use Amp\Sql\Connector; use Amp\Sql\FailureException; +use Amp\Sql\Pool as SqlPool; use function Amp\call; use function Amp\coroutine; -final class Pool implements Link { +final class Pool implements SqlPool +{ use CallableMaker; const DEFAULT_MAX_CONNECTIONS = 100; From 5dd51b900def716697affdf0cdadd563c7c556f9 Mon Sep 17 00:00:00 2001 From: prolic Date: Thu, 28 Jun 2018 23:08:54 +0800 Subject: [PATCH 06/25] fix connection --- src/Connection.php | 57 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/src/Connection.php b/src/Connection.php index db95451..76ca52c 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -9,6 +9,7 @@ use Amp\Sql\Connection as SqlConnection; use Amp\Sql\ConnectionConfig; use function Amp\call; +use Amp\Sql\FailureException; abstract class Connection implements SqlConnection, Handle { /** @var \Amp\Postgres\Handle */ @@ -40,13 +41,19 @@ abstract public function connect(): Promise; * {@inheritdoc} */ final public function isAlive(): bool { - return $this->handle->isAlive(); + return $this->handle && $this->handle->isAlive(); } /** * {@inheritdoc} + * + * @throws FailureException */ final public function lastUsedAt(): int { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return $this->handle->lastUsedAt(); } @@ -54,7 +61,9 @@ final public function lastUsedAt(): int { * {@inheritdoc} */ final public function close() { - $this->handle->close(); + if ($this->handle) { + $this->handle->close(); + } } /** @@ -66,6 +75,10 @@ final public function close() { * @throws \Amp\Sql\FailureException */ private function send(string $methodName, ...$args): Promise { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + if ($this->busy) { return call(function () use ($methodName, $args) { while ($this->busy) { @@ -94,6 +107,10 @@ private function release() { * {@inheritdoc} */ final public function query(string $sql): Promise { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return $this->send("query", $sql); } @@ -101,6 +118,10 @@ final public function query(string $sql): Promise { * {@inheritdoc} */ final public function execute(string $sql, array $params = []): Promise { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return $this->send("execute", $sql, $params); } @@ -110,6 +131,10 @@ final public function execute(string $sql, array $params = []): Promise { * Statement instances returned by this method must also implement Operation. */ final public function prepare(string $sql): Promise { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return $this->send("prepare", $sql); } @@ -118,20 +143,36 @@ final public function prepare(string $sql): Promise { * {@inheritdoc} */ final public function notify(string $channel, string $payload = ""): Promise { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return $this->send("notify", $channel, $payload); } /** * {@inheritdoc} + * + * @throws FailureException */ final public function listen(string $channel): Promise { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return $this->send("listen", $channel); } /** * {@inheritdoc} + * + * @throws FailureException */ final public function transaction(int $isolation = Transaction::COMMITTED): Promise { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return call(function () use ($isolation) { switch ($isolation) { case Transaction::UNCOMMITTED: @@ -164,15 +205,27 @@ final public function transaction(int $isolation = Transaction::COMMITTED): Prom /** * {@inheritdoc} + * + * @throws FailureException */ final public function quoteString(string $data): string { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return $this->handle->quoteString($data); } /** * {@inheritdoc} + * + * @throws FailureException */ final public function quoteName(string $name): string { + if (! $this->handle) { + throw new FailureException('Not connected'); + } + return $this->handle->quoteName($name); } } From 1f0bf143eadeb69002d3c4e1760b18c53d6177d3 Mon Sep 17 00:00:00 2001 From: prolic Date: Fri, 29 Jun 2018 17:21:39 +0800 Subject: [PATCH 07/25] refactor connection and connector --- examples/transaction.php | 2 +- src/Connection.php | 55 +++++++++++++++++--------------- src/ConnectionConfig.php | 21 ++++++++++++ src/Internal/PooledStatement.php | 12 +++---- src/Link.php | 14 ++------ src/Listener.php | 1 + src/Operation.php | 10 ------ src/PgSqlConnection.php | 38 +++++++++++----------- src/PgSqlStatement.php | 2 ++ src/Pool.php | 4 ++- src/PqConnection.php | 33 +++++++++++-------- src/PqStatement.php | 2 ++ src/PqUnbufferedResultSet.php | 2 +- src/Statement.php | 29 ----------------- src/TimeoutConnector.php | 27 +++++----------- src/Transaction.php | 38 ++++++++++------------ test/AbstractLinkTest.php | 26 +++++++-------- test/PooledStatementTest.php | 2 +- 18 files changed, 146 insertions(+), 172 deletions(-) create mode 100644 src/ConnectionConfig.php delete mode 100644 src/Operation.php delete mode 100644 src/Statement.php diff --git a/examples/transaction.php b/examples/transaction.php index 13c7da7..cacadd9 100644 --- a/examples/transaction.php +++ b/examples/transaction.php @@ -15,7 +15,7 @@ yield $transaction->query('CREATE TABLE test (domain VARCHAR(63), tld VARCHAR(63), PRIMARY KEY (domain, tld))'); - /** @var \Amp\Postgres\Statement $statement */ + /** @var \Amp\Sql\Statement $statement */ $statement = yield $transaction->prepare('INSERT INTO test VALUES (?, ?)'); yield $statement->execute(['amphp', 'org']); diff --git a/src/Connection.php b/src/Connection.php index 76ca52c..28f9838 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -2,46 +2,49 @@ namespace Amp\Postgres; +use Amp\CallableMaker; use Amp\CancellationToken; use Amp\Deferred; -use Amp\NullCancellationToken; use Amp\Promise; -use Amp\Sql\Connection as SqlConnection; use Amp\Sql\ConnectionConfig; -use function Amp\call; use Amp\Sql\FailureException; +use Amp\Sql\Link; +use function Amp\call; + +abstract class Connection implements Link, Handle +{ + use CallableMaker; -abstract class Connection implements SqlConnection, Handle { - /** @var \Amp\Postgres\Handle */ - protected $handle; + /** @var Handle */ + private $handle; - /** @var \Amp\Deferred|null Used to only allow one transaction at a time. */ + /** @var Deferred|null Used to only allow one transaction at a time. */ private $busy; /** @var callable */ protected $release; - /** @var ConnectionConfig */ - protected $config; - - /** @var CancellationToken */ - protected $token; + /** + * @param ConnectionConfig $connectionConfig + * @param CancellationToken $token + * + * @return Promise + */ + abstract public static function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise; /** - * @param \Amp\Postgres\Handle $handle + * @param Handle $handle */ - public function __construct(ConnectionConfig $config, CancellationToken $token = null) { - $this->config = $config; - $this->token = $token ?? new NullCancellationToken(); + public function __construct(Handle $handle) { + $this->handle = $handle; + $this->release = $this->callableFromInstanceMethod("release"); } - abstract public function connect(): Promise; - /** * {@inheritdoc} */ final public function isAlive(): bool { - return $this->handle && $this->handle->isAlive(); + return $this->handle->isAlive(); } /** @@ -70,9 +73,9 @@ final public function close() { * @param string $methodName Method to execute. * @param mixed ...$args Arguments to pass to function. * - * @return \Amp\Promise + * @return Promise * - * @throws \Amp\Sql\FailureException + * @throws FailureException */ private function send(string $methodName, ...$args): Promise { if (! $this->handle) { @@ -168,26 +171,26 @@ final public function listen(string $channel): Promise { * * @throws FailureException */ - final public function transaction(int $isolation = Transaction::COMMITTED): Promise { + final public function transaction(int $isolation = Transaction::ISOLATION_COMMITTED): Promise { if (! $this->handle) { throw new FailureException('Not connected'); } return call(function () use ($isolation) { switch ($isolation) { - case Transaction::UNCOMMITTED: + case Transaction::ISOLATION_UNCOMMITTED: yield $this->handle->query("BEGIN TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"); break; - case Transaction::COMMITTED: + case Transaction::ISOLATION_COMMITTED: yield $this->handle->query("BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED"); break; - case Transaction::REPEATABLE: + case Transaction::ISOLATION_REPEATABLE: yield $this->handle->query("BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ"); break; - case Transaction::SERIALIZABLE: + case Transaction::ISOLATION_SERIALIZABLE: yield $this->handle->query("BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE"); break; diff --git a/src/ConnectionConfig.php b/src/ConnectionConfig.php new file mode 100644 index 0000000..47da661 --- /dev/null +++ b/src/ConnectionConfig.php @@ -0,0 +1,21 @@ +connectionString = $connectionString; + } + + public function connectionString(): string + { + return $this->connectionString; + } +} diff --git a/src/Internal/PooledStatement.php b/src/Internal/PooledStatement.php index c329967..0fff581 100644 --- a/src/Internal/PooledStatement.php +++ b/src/Internal/PooledStatement.php @@ -3,10 +3,10 @@ namespace Amp\Postgres\Internal; use Amp\Loop; -use Amp\Postgres\Operation; use Amp\Postgres\Pool; -use Amp\Postgres\Statement; use Amp\Promise; +use Amp\Sql\Operation; +use Amp\Sql\Statement; use function Amp\call; final class PooledStatement implements Statement { @@ -29,8 +29,8 @@ final class PooledStatement implements Statement { private $prepare; /** - * @param \Amp\Postgres\Pool $pool Pool used to re-create the statement if the original closes. - * @param \Amp\Postgres\Statement $statement + * @param Pool $pool Pool used to re-create the statement if the original closes. + * @param Statement $statement * @param callable $prepare */ public function __construct(Pool $pool, Statement $statement, callable $prepare) { @@ -47,7 +47,7 @@ public function __construct(Pool $pool, Statement $statement, callable $prepare) $idleTimeout = ((int) ($pool->getIdleTimeout() / 10)) ?: 1; while (!$statements->isEmpty()) { - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = $statements->bottom(); if ($statement->lastUsedAt() + $idleTimeout > $now) { @@ -76,7 +76,7 @@ public function execute(array $params = []): Promise { return call(function () use ($params) { if (!$this->statements->isEmpty()) { do { - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = $this->statements->shift(); } while (!$statement->isAlive() && !$this->statements->isEmpty()); } else { diff --git a/src/Link.php b/src/Link.php index 3c0d960..2c507c1 100644 --- a/src/Link.php +++ b/src/Link.php @@ -3,19 +3,9 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\Link as SqlLink; -interface Link extends \Amp\Sql\Link { - /** - * @param int $isolation - * - * @return \Amp\Promise<\Amp\Postgres\Transaction> - * - * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. - * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). - */ - public function transaction(int $isolation = Transaction::COMMITTED): Promise; - +interface Link extends SqlLink { /** * @param string $channel Channel name. * diff --git a/src/Listener.php b/src/Listener.php index 22e9495..37379e6 100644 --- a/src/Listener.php +++ b/src/Listener.php @@ -4,6 +4,7 @@ use Amp\Iterator; use Amp\Promise; +use Amp\Sql\Operation; final class Listener implements Iterator, Operation { /** @var \Amp\Iterator */ diff --git a/src/Operation.php b/src/Operation.php deleted file mode 100644 index 73e1ba3..0000000 --- a/src/Operation.php +++ /dev/null @@ -1,10 +0,0 @@ - + * @return Promise + * + * @throws \Error If pecl-ev is used as a loop extension. */ - public function connect(): Promise { - $connectionString = \str_replace(";", " ", $this->config->connectionString()); + public static function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise { + // @codeCoverageIgnoreStart + if (Loop::get()->getHandle() instanceof \EvLoop) { + throw new \Error('ext-pgsql is not compatible with pecl-ev; use pecl-pq or a different loop extension'); + } // @codeCoverageIgnoreEnd + + $connectionString = \str_replace(";", " ", $connectionConfig->connectionString()); if (!$connection = @\pg_connect($connectionString, \PGSQL_CONNECT_ASYNC | \PGSQL_CONNECT_FORCE_NEW)) { return new Failure(new ConnectionException("Failed to create connection resource")); @@ -50,9 +58,7 @@ public function connect(): Promise { return; case \PGSQL_POLLING_OK: - $this->handle = new PgSqlHandle($connection, $resource); - $this->release = $this->callableFromInstanceMethod("release"); - $deferred->resolve(); + $deferred->resolve(new self($connection, $resource)); return; } }; @@ -62,14 +68,15 @@ public function connect(): Promise { $promise = $deferred->promise(); - $id = $this->token->subscribe([$deferred, "fail"]); + $token = $token ?? new NullCancellationToken(); + $id = $token->subscribe([$deferred, "fail"]); - $promise->onResolve(function ($exception) use ($connection, $poll, $await, $id) { + $promise->onResolve(function ($exception) use ($connection, $poll, $await, $id, $token) { if ($exception) { \pg_close($connection); } - $this->token->unsubscribe($id); + $token->unsubscribe($id); Loop::cancel($poll); Loop::cancel($await); }); @@ -80,15 +87,8 @@ public function connect(): Promise { /** * @param resource $handle PostgreSQL connection handle. * @param resource $socket PostgreSQL connection stream socket. - * - * @throws \Error If pecl-ev is used as a loop extension. */ - public function __construct(ConnectionConfig $config, CancellationToken $token = null) { - // @codeCoverageIgnoreStart - if (Loop::get()->getHandle() instanceof \EvLoop) { - throw new \Error('ext-pgsql is not compatible with pecl-ev; use pecl-pq or a different loop extension'); - } // @codeCoverageIgnoreEnd - - parent::__construct($config, $token); + public function __construct($handle, $socket) { + parent::__construct(new PgSqlHandle($handle, $socket)); } } diff --git a/src/PgSqlStatement.php b/src/PgSqlStatement.php index 5b31281..6928d68 100644 --- a/src/PgSqlStatement.php +++ b/src/PgSqlStatement.php @@ -3,6 +3,8 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\Operation; +use Amp\Sql\Statement; final class PgSqlStatement implements Statement, Operation { /** @var \Amp\Postgres\PgSqlHandle */ diff --git a/src/Pool.php b/src/Pool.php index 94f2f6f..d76d3bb 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -9,9 +9,11 @@ use Amp\Promise; use Amp\Sql\Connector; use Amp\Sql\FailureException; +use Amp\Sql\Operation; use Amp\Sql\Pool as SqlPool; use function Amp\call; use function Amp\coroutine; +use Amp\Sql\Statement; final class Pool implements SqlPool { @@ -340,7 +342,7 @@ private function doPrepare(string $sql): \Generator { $connection = yield from $this->pop(); try { - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = yield $connection->prepare($sql); } catch (\Throwable $exception) { $this->push($connection); diff --git a/src/PqConnection.php b/src/PqConnection.php index 63a8986..6ff083a 100644 --- a/src/PqConnection.php +++ b/src/PqConnection.php @@ -2,25 +2,25 @@ namespace Amp\Postgres; -use Amp\CallableMaker; +use Amp\CancellationToken; use Amp\Deferred; use Amp\Failure; use Amp\Loop; +use Amp\NullCancellationToken; use Amp\Promise; +use Amp\Sql\ConnectionConfig; use Amp\Sql\ConnectionException; use pq; final class PqConnection extends Connection { - use CallableMaker; - /** - * @param string $connectionString - * @param \Amp\CancellationToken $token + * @param ConnectionConfig $connectionConfig + * @param CancellationToken $token * - * @return \Amp\Promise<\Amp\Postgres\PgSqlConnection> + * @return Promise */ - public function connect(): Promise { - $connectionString = \str_replace(";", " ", $this->config->connectionString()); + public static function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise { + $connectionString = \str_replace(";", " ", $connectionConfig->connectionString()); try { $connection = new pq\Connection($connectionString, pq\Connection::ASYNC); @@ -46,8 +46,7 @@ public function connect(): Promise { return; case pq\Connection::POLLING_OK: - $this->handle = new PqHandle($connection); - $deferred->resolve(); + $deferred->resolve(new self($connection)); return; } }; @@ -57,14 +56,22 @@ public function connect(): Promise { $promise = $deferred->promise(); - $id = $this->token->subscribe([$deferred, "fail"]); + $token = $token ?? new NullCancellationToken(); + $id = $token->subscribe([$deferred, "fail"]); - $promise->onResolve(function () use ($poll, $await, $id) { - $this->token->unsubscribe($id); + $promise->onResolve(function () use ($poll, $await, $id, $token) { + $token->unsubscribe($id); Loop::cancel($poll); Loop::cancel($await); }); return $promise; } + + /** + * @param \pq\Connection $handle + */ + public function __construct(pq\Connection $handle) { + parent::__construct(new PqHandle($handle)); + } } diff --git a/src/PqStatement.php b/src/PqStatement.php index a8e4c89..ca1443a 100644 --- a/src/PqStatement.php +++ b/src/PqStatement.php @@ -3,6 +3,8 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\Operation; +use Amp\Sql\Statement; final class PqStatement implements Statement, Operation { /** @var \Amp\Postgres\PqHandle */ diff --git a/src/PqUnbufferedResultSet.php b/src/PqUnbufferedResultSet.php index 9ffc4ce..b440ae4 100644 --- a/src/PqUnbufferedResultSet.php +++ b/src/PqUnbufferedResultSet.php @@ -6,7 +6,7 @@ use Amp\Promise; use pq; -final class PqUnbufferedResultSet implements ResultSet, Operation { +final class PqUnbufferedResultSet implements ResultSet { /** @var int */ private $numCols; diff --git a/src/Statement.php b/src/Statement.php deleted file mode 100644 index 2ab29c3..0000000 --- a/src/Statement.php +++ /dev/null @@ -1,29 +0,0 @@ - - */ - public function execute(array $params = []): Promise; - - /** - * @return bool True if the statement can still be executed, false if the connection has died. - */ - public function isAlive(): bool; - - /** - * @return string The SQL string used to prepare the statement. - */ - public function getQuery(): string; - - /** - * @return int Timestamp of when the statement was last used. - */ - public function lastUsedAt(): int; -} diff --git a/src/TimeoutConnector.php b/src/TimeoutConnector.php index 291d831..253dd2e 100644 --- a/src/TimeoutConnector.php +++ b/src/TimeoutConnector.php @@ -2,7 +2,6 @@ namespace Amp\Postgres; -use function Amp\call; use Amp\Promise; use Amp\Sql\ConnectionConfig; use Amp\Sql\Connector; @@ -30,26 +29,16 @@ public function __construct(int $timeout = self::DEFAULT_TIMEOUT) { * @throws \Error If neither ext-pgsql or pecl-pq is loaded. */ public function connect(ConnectionConfig $connectionConfig): Promise { - return call(function () use ($connectionConfig) { - $token = new TimeoutCancellationToken($this->timeout); + $token = new TimeoutCancellationToken($this->timeout); - if (\extension_loaded("pq")) { - $connection = new PqConnection($connectionConfig, $token); + if (\extension_loaded("pq")) { + return PqConnection::connect($connectionConfig, $token); + } - yield $connection->connect(); + if (\extension_loaded("pgsql")) { + return PgSqlConnection::connect($connectionConfig, $token); + } - return $connection; - } - - if (\extension_loaded("pgsql")) { - $connection = new PgSqlConnection($connectionConfig, $token); - - yield $connection->connect(); - - return $connection; - } - - throw new \Error("amphp/postgres requires either pecl-pq or ext-pgsql"); - }); + throw new \Error("amphp/postgres requires either pecl-pq or ext-pgsql"); } } diff --git a/src/Transaction.php b/src/Transaction.php index 6ad13eb..e392919 100644 --- a/src/Transaction.php +++ b/src/Transaction.php @@ -3,14 +3,10 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\Operation; use Amp\Sql\Transaction as SqlTransaction; final class Transaction implements Handle, SqlTransaction { - const UNCOMMITTED = 0; - const COMMITTED = 1; - const REPEATABLE = 2; - const SERIALIZABLE = 4; - /** @var \Amp\Postgres\Handle|null */ private $handle; @@ -26,12 +22,12 @@ final class Transaction implements Handle, SqlTransaction { * * @throws \Error If the isolation level is invalid. */ - public function __construct(Handle $handle, int $isolation = self::COMMITTED) { + public function __construct(Handle $handle, int $isolation = self::ISOLATION_COMMITTED) { switch ($isolation) { - case self::UNCOMMITTED: - case self::COMMITTED: - case self::REPEATABLE: - case self::SERIALIZABLE: + case self::ISOLATION_UNCOMMITTED: + case self::ISOLATION_COMMITTED: + case self::ISOLATION_REPEATABLE: + case self::ISOLATION_SERIALIZABLE: $this->isolation = $isolation; break; @@ -78,7 +74,7 @@ public function onDestruct(callable $onComplete) { * {@inheritdoc} */ public function isAlive(): bool { - return $this->handle !== null && $this->handle->isAlive(); + return $this->handle->isAlive(); } /** @@ -190,7 +186,7 @@ public function notify(string $channel, string $payload = ""): Promise { /** * Commits the transaction and makes it inactive. * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ @@ -209,7 +205,7 @@ public function commit(): Promise { /** * Rolls back the transaction and makes it inactive. * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ @@ -230,11 +226,11 @@ public function rollback(): Promise { * * @param string $identifier Savepoint identifier. * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ - public function savepoint(string $identifier): Promise { + public function createSavepoint(string $identifier): Promise { return $this->query("SAVEPOINT " . $this->quoteName($identifier)); } @@ -243,7 +239,7 @@ public function savepoint(string $identifier): Promise { * * @param string $identifier Savepoint identifier. * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. */ @@ -256,18 +252,18 @@ public function rollbackTo(string $identifier): Promise { * * @param string $identifier Savepoint identifier. * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ - public function release(string $identifier): Promise { + public function releaseSavepoint(string $identifier): Promise { return $this->query("RELEASE SAVEPOINT " . $this->quoteName($identifier)); } /** * {@inheritdoc} * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function quoteString(string $data): string { if ($this->handle === null) { @@ -280,7 +276,7 @@ public function quoteString(string $data): string { /** * {@inheritdoc} * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function quoteName(string $name): string { if ($this->handle === null) { diff --git a/test/AbstractLinkTest.php b/test/AbstractLinkTest.php index ebc7dff..eb4cfe6 100644 --- a/test/AbstractLinkTest.php +++ b/test/AbstractLinkTest.php @@ -9,11 +9,11 @@ use Amp\Postgres\Listener; use Amp\Postgres\QueryExecutionError; use Amp\Postgres\ResultSet; -use Amp\Postgres\Statement; use Amp\Postgres\Transaction; use Amp\Postgres\TransactionError; use Amp\Sql\CommandResult; use Amp\Sql\QueryError; +use Amp\Sql\Statement; use PHPUnit\Framework\TestCase; abstract class AbstractLinkTest extends TestCase { @@ -121,7 +121,7 @@ public function testPrepare() { Loop::run(function () { $query = "SELECT * FROM test WHERE domain=\$1"; - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = yield $this->connection->prepare($query); $this->assertSame($query, $statement->getQuery()); @@ -150,7 +150,7 @@ public function testPrepareWithNamedParams() { Loop::run(function () { $query = "SELECT * FROM test WHERE domain=:domain AND tld=:tld"; - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = yield $this->connection->prepare($query); $data = $this->getData()[0]; @@ -179,7 +179,7 @@ public function testPrepareWithUnnamedParams() { Loop::run(function () { $query = "SELECT * FROM test WHERE domain=? AND tld=?"; - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = yield $this->connection->prepare($query); $data = $this->getData()[0]; @@ -208,7 +208,7 @@ public function testPrepareWithNamedParamsWithDataAppearingAsNamedParam() { Loop::run(function () { $query = "SELECT * FROM test WHERE domain=:domain OR domain=':domain'"; - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = yield $this->connection->prepare($query); $data = $this->getData()[0]; @@ -239,7 +239,7 @@ public function testPrepareInvalidQuery() { Loop::run(function () { $query = "SELECT * FROM test WHERE invalid=\$1"; - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = yield $this->connection->prepare($query); }); } @@ -251,10 +251,10 @@ public function testPrepareSameQuery() { Loop::run(function () { $sql = "SELECT * FROM test WHERE domain=\$1"; - /** @var \Amp\Postgres\Statement $statement1 */ + /** @var Statement $statement1 */ $statement1 = yield $this->connection->prepare($sql); - /** @var \Amp\Postgres\Statement $statement2 */ + /** @var Statement $statement2 */ $statement2 = yield $this->connection->prepare($sql); $this->assertInstanceOf(Statement::class, $statement1); @@ -290,8 +290,8 @@ public function testSimultaneousPrepareSameQuery() { $statement2 = $this->connection->prepare($sql); /** - * @var \Amp\Postgres\Statement $statement1 - * @var \Amp\Postgres\Statement $statement2 + * @var Statement $statement1 + * @var Statement $statement2 */ list($statement1, $statement2) = yield [$statement1, $statement2]; @@ -332,7 +332,7 @@ public function testSimultaneousPrepareSameQuery() { public function testPrepareThenExecuteWithUnconsumedTupleResult() { Loop::run(function () { - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = yield $this->connection->prepare("SELECT * FROM test"); /** @var \Amp\Postgres\ResultSet $result */ @@ -494,7 +494,7 @@ public function testSimultaneousQueryAndPrepare() { })()); $promises[] = new Coroutine((function () { - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = (yield $this->connection->prepare("SELECT * FROM test")); /** @var \Amp\Postgres\ResultSet $result */ @@ -516,7 +516,7 @@ public function testSimultaneousQueryAndPrepare() { public function testSimultaneousPrepareAndExecute() { $promises[] = new Coroutine((function () { - /** @var \Amp\Postgres\Statement $statement */ + /** @var Statement $statement */ $statement = yield $this->connection->prepare("SELECT * FROM test"); /** @var \Amp\Postgres\ResultSet $result */ diff --git a/test/PooledStatementTest.php b/test/PooledStatementTest.php index 4f04f10..bb02c84 100644 --- a/test/PooledStatementTest.php +++ b/test/PooledStatementTest.php @@ -8,7 +8,7 @@ use Amp\Postgres\Internal\PooledStatement; use Amp\Postgres\Pool; use Amp\Postgres\ResultSet; -use Amp\Postgres\Statement; +use Amp\Sql\Statement; use Amp\Success; class PooledStatementTest extends TestCase { From 80a6c976d3fa70e209ac30a368ea266b94cf0759 Mon Sep 17 00:00:00 2001 From: prolic Date: Fri, 29 Jun 2018 17:41:56 +0800 Subject: [PATCH 08/25] update connection usage, clean up --- src/Executor.php | 8 ++++---- src/Internal/ArrayParser.php | 6 +++--- src/Internal/PooledStatement.php | 2 +- src/Internal/StatementStorage.php | 2 +- src/Link.php | 2 +- src/Listener.php | 10 +++++----- src/PgSqlHandle.php | 10 +++++----- src/PgSqlResultSet.php | 4 ++-- src/PgSqlStatement.php | 6 +++--- src/Pool.php | 26 +++++++++++++------------- src/PqHandle.php | 2 +- src/PqStatement.php | 6 +++--- src/PqUnbufferedResultSet.php | 4 ++-- src/Transaction.php | 22 +++++++++++----------- src/functions.php | 4 ++-- test/AbstractConnectTest.php | 24 ++++++++++++++---------- test/PgSqlConnectTest.php | 5 +++-- test/PqConnectTest.php | 5 +++-- 18 files changed, 77 insertions(+), 71 deletions(-) diff --git a/src/Executor.php b/src/Executor.php index 178026c..5d35580 100644 --- a/src/Executor.php +++ b/src/Executor.php @@ -10,7 +10,7 @@ interface Executor { /** * @param string $sql * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. @@ -22,7 +22,7 @@ public function query(string $sql): Promise; * @param string $sql * @param mixed[] $params * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. @@ -33,7 +33,7 @@ public function execute(string $sql, array $params = []): Promise; /** * @param string $sql * - * @return \Amp\Promise<\Amp\Postgres\Statement> + * @return Promise<@return PromiseStatement> * * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. @@ -45,7 +45,7 @@ public function prepare(string $sql): Promise; * @param string $channel Channel name. * @param string $payload Notification payload. * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. diff --git a/src/Internal/ArrayParser.php b/src/Internal/ArrayParser.php index b48db9e..bc81e25 100644 --- a/src/Internal/ArrayParser.php +++ b/src/Internal/ArrayParser.php @@ -12,7 +12,7 @@ final class ArrayParser { * * @return array Parsed column data. * - * @throws \Amp\Postgres\ParseException + * @throws ParseException */ public function parse(string $data, callable $cast = null, string $delimiter = ','): array { $data = \trim($data); @@ -40,7 +40,7 @@ public function parse(string $data, callable $cast = null, string $delimiter = ' * * @return \Generator * - * @throws \Amp\Postgres\ParseException + * @throws ParseException */ private function parser(string $data, callable $cast = null, string $delimiter = ','): \Generator { $data = \ltrim(\substr($data, 1)); @@ -106,7 +106,7 @@ private function parser(string $data, callable $cast = null, string $delimiter = * * @return string First non-whitespace character after given position. * - * @throws \Amp\Postgres\ParseException + * @throws ParseException */ private function trim(string &$data, int $position, string $delimiter): string { $data = \ltrim(\substr($data, $position)); diff --git a/src/Internal/PooledStatement.php b/src/Internal/PooledStatement.php index 0fff581..73d25aa 100644 --- a/src/Internal/PooledStatement.php +++ b/src/Internal/PooledStatement.php @@ -10,7 +10,7 @@ use function Amp\call; final class PooledStatement implements Statement { - /** @var \Amp\Postgres\Pool */ + /** @var Pool */ private $pool; /** @var \SplQueue */ diff --git a/src/Internal/StatementStorage.php b/src/Internal/StatementStorage.php index b98a259..daa7b78 100644 --- a/src/Internal/StatementStorage.php +++ b/src/Internal/StatementStorage.php @@ -7,7 +7,7 @@ class StatementStorage { use Struct; - /** @var \Amp\Promise|null */ + /** @var |null */ public $promise; /** @var int */ diff --git a/src/Link.php b/src/Link.php index 2c507c1..88c5375 100644 --- a/src/Link.php +++ b/src/Link.php @@ -9,7 +9,7 @@ interface Link extends SqlLink { /** * @param string $channel Channel name. * - * @return \Amp\Promise<\Amp\Postgres\Listener> + * @return Promise * * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. diff --git a/src/Listener.php b/src/Listener.php index 37379e6..70cfc08 100644 --- a/src/Listener.php +++ b/src/Listener.php @@ -16,13 +16,13 @@ final class Listener implements Iterator, Operation { /** @var callable|null */ private $unlisten; - /** @var \Amp\Postgres\Internal\ReferenceQueue */ + /** @var Internal\ReferenceQueue */ private $queue; /** * @param \Amp\Iterator $iterator Iterator emitting notificatons on the channel. * @param string $channel Channel name. - * @param callable(string $channel): \Amp\Promise $unlisten Function invoked to unlisten from the channel. + * @param callable(string $channel): $unlisten Function invoked to unlisten from the channel. */ public function __construct(Iterator $iterator, string $channel, callable $unlisten) { $this->iterator = $iterator; @@ -54,7 +54,7 @@ public function advance(): Promise { /** * {@inheritdoc} * - * @return \Amp\Postgres\Notification + * @return Notification */ public function getCurrent(): Notification { return $this->iterator->getCurrent(); @@ -70,7 +70,7 @@ public function getChannel(): string { /** * Unlistens from the channel. No more values will be emitted from this listener. * - * @return \Amp\Promise<\Amp\Sql\CommandResult> + * @return Promise<\Amp\Sql\CommandResult> * * @throws \Error If this method was previously invoked. */ @@ -79,7 +79,7 @@ public function unlisten(): Promise { throw new \Error("Already unlistened on this channel"); } - /** @var \Amp\Promise $promise */ + /** @var $promise */ $promise = ($this->unlisten)($this->channel); $this->unlisten = null; $promise->onResolve([$this->queue, "unreference"]); diff --git a/src/PgSqlHandle.php b/src/PgSqlHandle.php index 1ddfc1d..4e4ca82 100644 --- a/src/PgSqlHandle.php +++ b/src/PgSqlHandle.php @@ -49,7 +49,7 @@ final class PgSqlHandle implements Handle { /** @var callable */ private $unlisten; - /** @var \Amp\Postgres\Internal\StatementStorage[] */ + /** @var Internal\StatementStorage[] */ private $statements = []; /** @var int */ @@ -241,7 +241,7 @@ private function send(callable $function, ...$args): \Generator { /** * @param resource $result PostgreSQL result resource. * - * @return \Amp\Sql\CommandResult|\Amp\Postgres\ResultSet + * @return \Amp\Sql\CommandResult|ResultSet * * @throws FailureException * @throws QueryError @@ -279,7 +279,7 @@ private function createResult($result) { * @param string $name * @param array $params * - * @return \Amp\Promise + * @return Promise */ public function statementExecute(string $name, array $params): Promise { return call(function () use ($name, $params) { @@ -290,7 +290,7 @@ public function statementExecute(string $name, array $params): Promise { /** * @param string $name * - * @return \Amp\Promise + * @return Promise * * @throws \Error */ @@ -439,7 +439,7 @@ public function listen(string $channel): Promise { /** * @param string $channel * - * @return \Amp\Promise + * @return Promise * * @throws \Error */ diff --git a/src/PgSqlResultSet.php b/src/PgSqlResultSet.php index d66d977..11cba5a 100644 --- a/src/PgSqlResultSet.php +++ b/src/PgSqlResultSet.php @@ -25,7 +25,7 @@ final class PgSqlResultSet implements ResultSet { /** @var string[] */ private $fieldNames = []; - /** @var \Amp\Postgres\Internal\ArrayParser */ + /** @var Internal\ArrayParser */ private $parser; /** @@ -121,7 +121,7 @@ public function getCurrent() { * * @return array|bool|float|int Cast value. * - * @throws \Amp\Postgres\ParseException + * @throws ParseException */ private function cast(int $column, string $value) { switch ($this->fieldTypes[$column]) { diff --git a/src/PgSqlStatement.php b/src/PgSqlStatement.php index 6928d68..0468728 100644 --- a/src/PgSqlStatement.php +++ b/src/PgSqlStatement.php @@ -7,7 +7,7 @@ use Amp\Sql\Statement; final class PgSqlStatement implements Statement, Operation { - /** @var \Amp\Postgres\PgSqlHandle */ + /** @var PgSqlHandle */ private $handle; /** @var string */ @@ -16,7 +16,7 @@ final class PgSqlStatement implements Statement, Operation { /** @var string */ private $sql; - /** @var \Amp\Postgres\Internal\ReferenceQueue */ + /** @var Internal\ReferenceQueue */ private $queue; /** @var string[] */ @@ -26,7 +26,7 @@ final class PgSqlStatement implements Statement, Operation { private $lastUsedAt; /** - * @param \Amp\Postgres\PgSqlHandle $handle + * @param PgSqlHandle $handle * @param string $name * @param string $sql * @param string[] $params diff --git a/src/Pool.php b/src/Pool.php index d76d3bb..7a20c75 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -37,13 +37,13 @@ final class Pool implements SqlPool /** @var \SplObjectStorage */ private $connections; - /** @var \Amp\Promise|null */ + /** @var |null */ private $promise; /** @var \Amp\Deferred|null */ private $deferred; - /** @var \Amp\Postgres\Connection|\Amp\Promise|null Connection used for notification listening. */ + /** @var Connection||null Connection used for notification listening. */ private $listeningConnection; /** @var int Number of listeners on listening connection. */ @@ -90,7 +90,7 @@ public function __construct( $this->timeoutWatcher = Loop::repeat(1000, static function () use (&$idleTimeout, $connections, $idle) { $now = \time(); while (!$idle->isEmpty()) { - /** @var \Amp\Postgres\Connection $connection */ + /** @var Connection $connection */ $connection = $idle->bottom(); if ($connection->lastUsedAt() + $idleTimeout > $now) { @@ -183,7 +183,7 @@ public function getMaxConnections(): int { /** * @return \Generator * - * @resolve \Amp\Postgres\Connection + * @resolve Connection * * @throws FailureException If creating a new connection fails. * @throws \Error If the pool has been closed. @@ -231,7 +231,7 @@ private function pop(): \Generator { } } - /** @var \Amp\Postgres\Connection $connection */ + /** @var Connection $connection */ $connection = $this->idle->shift(); if ($connection->isAlive()) { @@ -253,7 +253,7 @@ private function pop(): \Generator { } /** - * @param \Amp\Postgres\Connection $connection + * @param Connection $connection * * @throws \Error If the connection is not part of this pool. */ @@ -276,7 +276,7 @@ private function push(Connection $connection) { */ public function query(string $sql): Promise { return call(function () use ($sql) { - /** @var \Amp\Postgres\Connection $connection */ + /** @var Connection $connection */ $connection = yield from $this->pop(); try { @@ -303,7 +303,7 @@ public function query(string $sql): Promise { */ public function execute(string $sql, array $params = []): Promise { return call(function () use ($sql, $params) { - /** @var \Amp\Postgres\Connection $connection */ + /** @var Connection $connection */ $connection = yield from $this->pop(); try { @@ -338,7 +338,7 @@ public function prepare(string $sql): Promise { } private function doPrepare(string $sql): \Generator { - /** @var \Amp\Postgres\Connection $connection */ + /** @var Connection $connection */ $connection = yield from $this->pop(); try { @@ -366,7 +366,7 @@ private function doPrepare(string $sql): \Generator { */ public function notify(string $channel, string $payload = ""): Promise { return call(function () use ($channel, $payload) { - /** @var \Amp\Postgres\Connection $connection */ + /** @var Connection $connection */ $connection = yield from $this->pop(); try { @@ -395,7 +395,7 @@ public function listen(string $channel): Promise { } try { - /** @var \Amp\Postgres\Listener $listener */ + /** @var Listener $listener */ $listener = yield $this->listeningConnection->listen($channel); } catch (\Throwable $exception) { if (--$this->listenerCount === 0) { @@ -423,11 +423,11 @@ public function listen(string $channel): Promise { */ public function transaction(int $isolation = Transaction::COMMITTED): Promise { return call(function () use ($isolation) { - /** @var \Amp\Postgres\Connection $connection */ + /** @var Connection $connection */ $connection = yield from $this->pop(); try { - /** @var \Amp\Postgres\Transaction $transaction */ + /** @var Transaction $transaction */ $transaction = yield $connection->transaction($isolation); } catch (\Throwable $exception) { $this->push($connection); diff --git a/src/PqHandle.php b/src/PqHandle.php index 1d78f8e..fb09613 100644 --- a/src/PqHandle.php +++ b/src/PqHandle.php @@ -36,7 +36,7 @@ final class PqHandle implements Handle { /** @var \Amp\Emitter[] */ private $listeners; - /** @var \Amp\Postgres\Internal\PqStatementStorage[] */ + /** @var @return PromiseInternal\PqStatementStorage[] */ private $statements = []; /** @var callable */ diff --git a/src/PqStatement.php b/src/PqStatement.php index ca1443a..6f4332e 100644 --- a/src/PqStatement.php +++ b/src/PqStatement.php @@ -7,7 +7,7 @@ use Amp\Sql\Statement; final class PqStatement implements Statement, Operation { - /** @var \Amp\Postgres\PqHandle */ + /** @var @return PromisePqHandle */ private $handle; /** @var string */ @@ -16,7 +16,7 @@ final class PqStatement implements Statement, Operation { /** @var string */ private $sql; - /** @var \Amp\Postgres\Internal\ReferenceQueue */ + /** @var @return PromiseInternal\ReferenceQueue */ private $queue; /** @var array */ @@ -26,7 +26,7 @@ final class PqStatement implements Statement, Operation { private $lastUsedAt; /** - * @param \Amp\Postgres\PqHandle $handle + * @param @return PromisePqHandle $handle * @param string $name Statement name. * @param string $sql Original prepared SQL query. * @param string[] $params Parameter indices to parameter names. diff --git a/src/PqUnbufferedResultSet.php b/src/PqUnbufferedResultSet.php index b440ae4..db7c5e8 100644 --- a/src/PqUnbufferedResultSet.php +++ b/src/PqUnbufferedResultSet.php @@ -19,11 +19,11 @@ final class PqUnbufferedResultSet implements ResultSet { /** @var int Next row fetch type. */ private $type = self::FETCH_ASSOC; - /** @var \Amp\Postgres\Internal\ReferenceQueue */ + /** @var Internal\ReferenceQueue */ private $queue; /** - * @param callable(): \Amp\Promise $fetch Function to fetch next result row. + * @param callable(): $fetch Function to fetch next result row. * @param \pq\Result $result PostgreSQL result object. */ public function __construct(callable $fetch, pq\Result $result) { diff --git a/src/Transaction.php b/src/Transaction.php index e392919..6a5ffc9 100644 --- a/src/Transaction.php +++ b/src/Transaction.php @@ -7,17 +7,17 @@ use Amp\Sql\Transaction as SqlTransaction; final class Transaction implements Handle, SqlTransaction { - /** @var \Amp\Postgres\Handle|null */ + /** @var Handle|null */ private $handle; /** @var int */ private $isolation; - /** @var \Amp\Postgres\Internal\ReferenceQueue */ + /** @var Internal\ReferenceQueue */ private $queue; /** - * @param \Amp\Postgres\Handle $handle + * @param Handle $handle * @param int $isolation * * @throws \Error If the isolation level is invalid. @@ -94,7 +94,7 @@ public function getIsolationLevel(): int { /** * {@inheritdoc} * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function query(string $sql): Promise { if ($this->handle === null) { @@ -120,7 +120,7 @@ public function query(string $sql): Promise { /** * {@inheritdoc} * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function prepare(string $sql): Promise { if ($this->handle === null) { @@ -146,7 +146,7 @@ public function prepare(string $sql): Promise { /** * {@inheritdoc} * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function execute(string $sql, array $params = []): Promise { if ($this->handle === null) { @@ -173,7 +173,7 @@ public function execute(string $sql, array $params = []): Promise { /** * {@inheritdoc} * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function notify(string $channel, string $payload = ""): Promise { if ($this->handle === null) { @@ -188,7 +188,7 @@ public function notify(string $channel, string $payload = ""): Promise { * * @return Promise<\Amp\Sql\CommandResult> * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function commit(): Promise { if ($this->handle === null) { @@ -207,7 +207,7 @@ public function commit(): Promise { * * @return Promise<\Amp\Sql\CommandResult> * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function rollback(): Promise { if ($this->handle === null) { @@ -228,7 +228,7 @@ public function rollback(): Promise { * * @return Promise<\Amp\Sql\CommandResult> * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function createSavepoint(string $identifier): Promise { return $this->query("SAVEPOINT " . $this->quoteName($identifier)); @@ -241,7 +241,7 @@ public function createSavepoint(string $identifier): Promise { * * @return Promise<\Amp\Sql\CommandResult> * - * @throws \Amp\Postgres\TransactionError If the transaction has been committed or rolled back. + * @throws TransactionError If the transaction has been committed or rolled back. */ public function rollbackTo(string $identifier): Promise { return $this->query("ROLLBACK TO " . $this->quoteName($identifier)); diff --git a/src/functions.php b/src/functions.php index 3d7ed47..b799cca 100644 --- a/src/functions.php +++ b/src/functions.php @@ -28,7 +28,7 @@ function connector(Connector $connector = null): Connector { * * @param string $connectionString * - * @return \Amp\Promise<\Amp\Postgres\Connection> + * @return Promise * * @throws \Amp\Sql\FailureException If connecting fails. * @@ -46,7 +46,7 @@ function connect(ConnectionConfig $config): Promise { * @param string $connectionString * @param int $maxConnections * - * @return \Amp\Postgres\Pool + * @return Pool */ function pool(string $connectionString, int $maxConnections = Pool::DEFAULT_MAX_CONNECTIONS): Pool { return new Pool($connectionString, $maxConnections, connector()); diff --git a/test/AbstractConnectTest.php b/test/AbstractConnectTest.php index 293369c..7a79318 100644 --- a/test/AbstractConnectTest.php +++ b/test/AbstractConnectTest.php @@ -7,21 +7,25 @@ use Amp\Loop; use Amp\Postgres\Connection; use Amp\Promise; +use Amp\Sql\ConnectionConfig; use Amp\TimeoutCancellationToken; use PHPUnit\Framework\TestCase; abstract class AbstractConnectTest extends TestCase { /** - * @param string $connectionString - * @param \Amp\CancellationToken|null $token + * @param ConnectionConfig $connectionConfig + * @param CancellationToken|null $token * - * @return \Amp\Promise + * @return Promise */ - abstract public function connect(string $connectionString, CancellationToken $token = null): Promise; + abstract public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise; public function testConnect() { Loop::run(function () { - $connection = yield $this->connect('host=localhost user=postgres', new TimeoutCancellationToken(100)); + $connection = yield $this->connect( + new \Amp\Postgres\ConnectionConfig(new \Amp\Postgres\ConnectionConfig('host=localhost user=postgres')), + new TimeoutCancellationToken(100) + ); $this->assertInstanceOf(Connection::class, $connection); }); } @@ -35,7 +39,7 @@ public function testConnectCancellationBeforeConnect() { $source = new CancellationTokenSource; $token = $source->getToken(); $source->cancel(); - $connection = yield $this->connect('host=localhost user=postgres', $token); + $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('host=localhost user=postgres'), $token); }); } @@ -46,7 +50,7 @@ public function testConnectCancellationAfterConnect() { Loop::run(function () { $source = new CancellationTokenSource; $token = $source->getToken(); - $connection = yield $this->connect('host=localhost user=postgres', $token); + $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('host=localhost user=postgres'), $token); $this->assertInstanceOf(Connection::class, $connection); $source->cancel(); }); @@ -58,7 +62,7 @@ public function testConnectCancellationAfterConnect() { */ public function testConnectInvalidUser() { Loop::run(function () { - $connection = yield $this->connect('host=localhost user=invalid', new TimeoutCancellationToken(100)); + $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('host=localhost user=invalid'), new TimeoutCancellationToken(100)); }); } @@ -68,7 +72,7 @@ public function testConnectInvalidUser() { */ public function testConnectInvalidConnectionString() { Loop::run(function () { - $connection = yield $this->connect('invalid connection string', new TimeoutCancellationToken(100)); + $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('invalid connection string'), new TimeoutCancellationToken(100)); }); } @@ -78,7 +82,7 @@ public function testConnectInvalidConnectionString() { */ public function testConnectInvalidHost() { Loop::run(function () { - $connection = yield $this->connect('hostaddr=invalid.host user=postgres', new TimeoutCancellationToken(100)); + $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('hostaddr=invalid.host user=postgres'), new TimeoutCancellationToken(100)); }); } } diff --git a/test/PgSqlConnectTest.php b/test/PgSqlConnectTest.php index d21e215..7532a9d 100644 --- a/test/PgSqlConnectTest.php +++ b/test/PgSqlConnectTest.php @@ -5,12 +5,13 @@ use Amp\CancellationToken; use Amp\Postgres\PgSqlConnection; use Amp\Promise; +use Amp\Sql\ConnectionConfig; /** * @requires extension pgsql */ class PgSqlConnectTest extends AbstractConnectTest { - public function connect(string $connectionString, CancellationToken $token = null): Promise { - return PgSqlConnection::connect($connectionString, $token); + public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise { + return PgSqlConnection::connect($connectionConfig, $token); } } diff --git a/test/PqConnectTest.php b/test/PqConnectTest.php index 03760df..3d70f23 100644 --- a/test/PqConnectTest.php +++ b/test/PqConnectTest.php @@ -5,12 +5,13 @@ use Amp\CancellationToken; use Amp\Postgres\PqConnection; use Amp\Promise; +use Amp\Sql\ConnectionConfig; /** * @requires extension pq */ class PqConnectTest extends AbstractConnectTest { - public function connect(string $connectionString, CancellationToken $token = null): Promise { - return PqConnection::connect($connectionString, $token); + public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise { + return PqConnection::connect($connectionConfig, $token); } } From 83f2052a6cd1a4ea6c629436da27c1324556461f Mon Sep 17 00:00:00 2001 From: prolic Date: Fri, 29 Jun 2018 17:50:18 +0800 Subject: [PATCH 09/25] implement lastUsedAt in pool --- src/Pool.php | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Pool.php b/src/Pool.php index 7a20c75..2613943 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -67,6 +67,9 @@ final class Pool implements SqlPool /** @var bool */ private $closed = false; + /** @var int */ + private $lastUsedAt; + public function __construct( string $connectionString, int $maxConnections = self::DEFAULT_MAX_CONNECTIONS, @@ -105,6 +108,8 @@ public function __construct( }); Loop::unreference($this->timeoutWatcher); + + $this->lastUsedAt = \time(); } public function __destruct() { @@ -134,6 +139,11 @@ public function isAlive(): bool { return !$this->closed; } + public function lastUsedAt(): int + { + return $this->lastUsedAt; + } + /** * Close all connections in the pool. No further queries may be made after a pool is closed. */ @@ -155,6 +165,9 @@ public function extractConnection(): Promise { return call(function () { $connection = yield from $this->pop(); $this->connections->detach($connection); + + $this->lastUsedAt = \time(); + return $connection; }); } @@ -217,6 +230,9 @@ private function pop(): \Generator { } $this->connections->attach($connection); + + $this->lastUsedAt = \time(); + return $connection; } @@ -240,6 +256,8 @@ private function pop(): \Generator { yield $connection->query("RESET ALL"); } + $this->lastUsedAt = \time(); + return $connection; } catch (FailureException $exception) { // Fall-through to remove connection below. @@ -269,6 +287,8 @@ private function push(Connection $connection) { if ($this->deferred instanceof Deferred) { $this->deferred->resolve($connection); } + + $this->lastUsedAt = \time(); } /** @@ -294,6 +314,8 @@ public function query(string $sql): Promise { $this->push($connection); } + $this->lastUsedAt = \time(); + return $result; }); } @@ -321,6 +343,8 @@ public function execute(string $sql, array $params = []): Promise { $this->push($connection); } + $this->lastUsedAt = \time(); + return $result; }); } @@ -333,6 +357,9 @@ public function execute(string $sql, array $params = []): Promise { public function prepare(string $sql): Promise { return call(function () use ($sql) { $statement = yield from $this->doPrepare($sql); + + $this->lastUsedAt = \time(); + return new Internal\PooledStatement($this, $statement, $this->prepare); }); } @@ -358,6 +385,8 @@ private function doPrepare(string $sql): \Generator { $this->push($connection); }); + $this->lastUsedAt = \time(); + return $statement; } @@ -375,6 +404,8 @@ public function notify(string $channel, string $payload = ""): Promise { $this->push($connection); } + $this->lastUsedAt = \time(); + return $result; }); } @@ -414,6 +445,8 @@ public function listen(string $channel): Promise { } }); + $this->lastUsedAt = \time(); + return $listener; }); } @@ -438,6 +471,8 @@ public function transaction(int $isolation = Transaction::COMMITTED): Promise { $this->push($connection); }); + $this->lastUsedAt = \time(); + return $transaction; }); } From d26bc3eedb545d9bad41910bfc06879ecca05346 Mon Sep 17 00:00:00 2001 From: prolic Date: Fri, 29 Jun 2018 18:19:18 +0800 Subject: [PATCH 10/25] apply php cs fixes --- .php_cs | 10 ++++ .php_cs.dist | 40 ------------- composer.json | 11 +++- examples/basic.php | 2 +- examples/listen.php | 8 +-- examples/multi-listen.php | 12 ++-- examples/transaction.php | 6 +- src/Connection.php | 42 +++++++++----- src/Executor.php | 3 +- src/Handle.php | 3 +- src/Internal/ArrayParser.php | 12 ++-- src/Internal/PooledStatement.php | 24 +++++--- src/Internal/PqStatementStorage.php | 3 +- src/Internal/ReferenceQueue.php | 15 +++-- src/Internal/StatementStorage.php | 3 +- src/Internal/functions.php | 6 +- src/Link.php | 3 +- src/Listener.php | 24 +++++--- src/Notification.php | 3 +- src/ParseException.php | 6 +- src/PgSqlCommandResult.php | 15 +++-- src/PgSqlConnection.php | 9 ++- src/PgSqlHandle.php | 57 ++++++++++++------- src/PgSqlResultSet.php | 30 ++++++---- src/PgSqlStatement.php | 24 +++++--- src/Pool.php | 62 ++++++++++++-------- src/Pool2.php | 46 +++++++++++++++ src/PoolError.php | 3 +- src/PqBufferedResultSet.php | 18 ++++-- src/PqCommandResult.php | 9 ++- src/PqConnection.php | 9 ++- src/PqHandle.php | 60 +++++++++++++------- src/PqStatement.php | 24 +++++--- src/PqUnbufferedResultSet.php | 18 ++++-- src/QueryExecutionError.php | 9 ++- src/ResultSet.php | 3 +- src/TimeoutConnector.php | 9 ++- src/Transaction.php | 60 +++++++++++++------- src/TransactionError.php | 3 +- src/functions.php | 15 +++-- test/AbstractConnectTest.php | 21 ++++--- test/AbstractConnectionTest.php | 6 +- test/AbstractLinkTest.php | 88 +++++++++++++++++++---------- test/ArrayParserTest.php | 54 ++++++++++++------ test/EncodeTest.php | 33 +++++++---- test/FunctionsTest.php | 18 ++++-- test/PgSqlConnectTest.php | 6 +- test/PgSqlConnectionTest.php | 9 ++- test/PgSqlPoolTest.php | 12 ++-- test/PoolTest.php | 9 ++- test/PooledStatementTest.php | 9 ++- test/PqConnectTest.php | 6 +- test/PqConnectionTest.php | 9 ++- test/PqPoolTest.php | 9 ++- 54 files changed, 657 insertions(+), 351 deletions(-) create mode 100644 .php_cs delete mode 100644 .php_cs.dist create mode 100644 src/Pool2.php diff --git a/.php_cs b/.php_cs new file mode 100644 index 0000000..06572ee --- /dev/null +++ b/.php_cs @@ -0,0 +1,10 @@ +getFinder()->in(__DIR__); + +$cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__; + +$config->setCacheFile($cacheDir . '/.php_cs.cache'); + +return $config; diff --git a/.php_cs.dist b/.php_cs.dist deleted file mode 100644 index 9c4a372..0000000 --- a/.php_cs.dist +++ /dev/null @@ -1,40 +0,0 @@ -setRiskyAllowed(true) - ->setRules([ - "@PSR1" => true, - "@PSR2" => true, - "braces" => [ - "allow_single_line_closure" => true, - "position_after_functions_and_oop_constructs" => "same", - ], - "array_syntax" => ["syntax" => "short"], - "cast_spaces" => true, - "combine_consecutive_unsets" => true, - "function_to_constant" => true, - "no_multiline_whitespace_before_semicolons" => true, - "no_unused_imports" => true, - "no_useless_else" => true, - "no_useless_return" => true, - "no_whitespace_before_comma_in_array" => true, - "no_whitespace_in_blank_line" => true, - "non_printable_character" => true, - "normalize_index_brace" => true, - "ordered_imports" => true, - "php_unit_construct" => true, - "php_unit_dedicate_assert" => true, - "php_unit_fqcn_annotation" => true, - "phpdoc_summary" => true, - "phpdoc_types" => true, - "psr4" => true, - "return_type_declaration" => ["space_before" => "none"], - "short_scalar_cast" => true, - "single_blank_line_before_namespace" => true, - ]) - ->setFinder( - PhpCsFixer\Finder::create() - ->in(__DIR__ . "/examples") - ->in(__DIR__ . "/src") - ->in(__DIR__ . "/test") - ); diff --git a/composer.json b/composer.json index d03a58a..f8d3f27 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "require-dev": { "amphp/phpunit-util": "^1", "phpunit/phpunit": "^6", - "friendsofphp/php-cs-fixer": "^2.3", + "amphp/php-cs-fixer-config": "dev-master", "phpstan/phpstan": "^0.9" }, "autoload": { @@ -48,7 +48,12 @@ } }, "scripts": { - "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit", - "code-style": "@php ./vendor/bin/php-cs-fixer fix" + "check": [ + "@cs", + "@test" + ], + "cs": "php-cs-fixer fix -v --diff --dry-run", + "cs-fix": "php-cs-fixer fix -v --diff", + "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit" } } diff --git a/examples/basic.php b/examples/basic.php index 53feea0..dd7d465 100644 --- a/examples/basic.php +++ b/examples/basic.php @@ -1,7 +1,7 @@ #!/usr/bin/env php listen($channel); - printf("Listening on channel '%s'\n", $listener->getChannel()); + \printf("Listening on channel '%s'\n", $listener->getChannel()); Loop::delay(3000, function () use ($listener) { // Unlisten in 3 seconds. - printf("Unlistening from channel '%s'\n", $listener->getChannel()); + \printf("Unlistening from channel '%s'\n", $listener->getChannel()); return $listener->unlisten(); }); @@ -31,7 +31,7 @@ while (yield $listener->advance()) { $notification = $listener->getCurrent(); - printf( + \printf( "Received notification from PID %d on channel '%s' with payload: %s\n", $notification->pid, $notification->channel, diff --git a/examples/multi-listen.php b/examples/multi-listen.php index 956a957..957f9c1 100644 --- a/examples/multi-listen.php +++ b/examples/multi-listen.php @@ -1,7 +1,7 @@ #!/usr/bin/env php listen($channel1); - printf("Listening on channel '%s'\n", $listener1->getChannel()); + \printf("Listening on channel '%s'\n", $listener1->getChannel()); /** @var \Amp\Postgres\Listener $listener2 */ $listener2 = yield $pool->listen($channel2); - printf("Listening on channel '%s'\n", $listener2->getChannel()); + \printf("Listening on channel '%s'\n", $listener2->getChannel()); Loop::delay(6000, function () use ($listener1) { // Unlisten in 6 seconds. - printf("Unlistening from channel '%s'\n", $listener1->getChannel()); + \printf("Unlistening from channel '%s'\n", $listener1->getChannel()); return $listener1->unlisten(); }); Loop::delay(4000, function () use ($listener2) { // Unlisten in 4 seconds. - printf("Unlistening from channel '%s'\n", $listener2->getChannel()); + \printf("Unlistening from channel '%s'\n", $listener2->getChannel()); return $listener2->unlisten(); }); @@ -53,7 +53,7 @@ while (yield $iterator->advance()) { $notification = $iterator->getCurrent(); - printf( + \printf( "Received notification from PID %d on channel '%s' with payload: %s\n", $notification->pid, $notification->channel, diff --git a/examples/transaction.php b/examples/transaction.php index cacadd9..6e3b64f 100644 --- a/examples/transaction.php +++ b/examples/transaction.php @@ -1,7 +1,7 @@ #!/usr/bin/env php execute('SELECT * FROM test WHERE tld = :tld', ['tld' => 'com']); $format = "%-20s | %-10s\n"; - printf($format, 'TLD', 'Domain'); + \printf($format, 'TLD', 'Domain'); while (yield $result->advance()) { $row = $result->getCurrent(); - printf($format, $row['domain'], $row['tld']); + \printf($format, $row['domain'], $row['tld']); } yield $transaction->rollback(); diff --git a/src/Connection.php b/src/Connection.php index 28f9838..4aaa06f 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -35,7 +35,8 @@ abstract public static function connect(ConnectionConfig $connectionConfig, Canc /** * @param Handle $handle */ - public function __construct(Handle $handle) { + public function __construct(Handle $handle) + { $this->handle = $handle; $this->release = $this->callableFromInstanceMethod("release"); } @@ -43,7 +44,8 @@ public function __construct(Handle $handle) { /** * {@inheritdoc} */ - final public function isAlive(): bool { + final public function isAlive(): bool + { return $this->handle->isAlive(); } @@ -52,7 +54,8 @@ final public function isAlive(): bool { * * @throws FailureException */ - final public function lastUsedAt(): int { + final public function lastUsedAt(): int + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -63,7 +66,8 @@ final public function lastUsedAt(): int { /** * {@inheritdoc} */ - final public function close() { + final public function close() + { if ($this->handle) { $this->handle->close(); } @@ -77,7 +81,8 @@ final public function close() { * * @throws FailureException */ - private function send(string $methodName, ...$args): Promise { + private function send(string $methodName, ...$args): Promise + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -98,7 +103,8 @@ private function send(string $methodName, ...$args): Promise { /** * Releases the transaction lock. */ - private function release() { + private function release() + { \assert($this->busy !== null); $deferred = $this->busy; @@ -109,7 +115,8 @@ private function release() { /** * {@inheritdoc} */ - final public function query(string $sql): Promise { + final public function query(string $sql): Promise + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -120,7 +127,8 @@ final public function query(string $sql): Promise { /** * {@inheritdoc} */ - final public function execute(string $sql, array $params = []): Promise { + final public function execute(string $sql, array $params = []): Promise + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -133,7 +141,8 @@ final public function execute(string $sql, array $params = []): Promise { * * Statement instances returned by this method must also implement Operation. */ - final public function prepare(string $sql): Promise { + final public function prepare(string $sql): Promise + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -145,7 +154,8 @@ final public function prepare(string $sql): Promise { /** * {@inheritdoc} */ - final public function notify(string $channel, string $payload = ""): Promise { + final public function notify(string $channel, string $payload = ""): Promise + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -158,7 +168,8 @@ final public function notify(string $channel, string $payload = ""): Promise { * * @throws FailureException */ - final public function listen(string $channel): Promise { + final public function listen(string $channel): Promise + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -171,7 +182,8 @@ final public function listen(string $channel): Promise { * * @throws FailureException */ - final public function transaction(int $isolation = Transaction::ISOLATION_COMMITTED): Promise { + final public function transaction(int $isolation = Transaction::ISOLATION_COMMITTED): Promise + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -211,7 +223,8 @@ final public function transaction(int $isolation = Transaction::ISOLATION_COMMIT * * @throws FailureException */ - final public function quoteString(string $data): string { + final public function quoteString(string $data): string + { if (! $this->handle) { throw new FailureException('Not connected'); } @@ -224,7 +237,8 @@ final public function quoteString(string $data): string { * * @throws FailureException */ - final public function quoteName(string $name): string { + final public function quoteName(string $name): string + { if (! $this->handle) { throw new FailureException('Not connected'); } diff --git a/src/Executor.php b/src/Executor.php index 5d35580..50ff4c9 100644 --- a/src/Executor.php +++ b/src/Executor.php @@ -4,7 +4,8 @@ use Amp\Promise; -interface Executor { +interface Executor +{ const STATEMENT_NAME_PREFIX = "amp_"; /** diff --git a/src/Handle.php b/src/Handle.php index f33d1c7..1b93bdb 100644 --- a/src/Handle.php +++ b/src/Handle.php @@ -2,7 +2,8 @@ namespace Amp\Postgres; -interface Handle extends Executor { +interface Handle extends Executor +{ /** * @return int Timestamp of last activity on the handle. */ diff --git a/src/Internal/ArrayParser.php b/src/Internal/ArrayParser.php index bc81e25..450796a 100644 --- a/src/Internal/ArrayParser.php +++ b/src/Internal/ArrayParser.php @@ -4,7 +4,8 @@ use Amp\Postgres\ParseException; -final class ArrayParser { +final class ArrayParser +{ /** * @param string $data String representation of PostgreSQL array. * @param callable|null $cast Callback to cast parsed values. @@ -14,7 +15,8 @@ final class ArrayParser { * * @throws ParseException */ - public function parse(string $data, callable $cast = null, string $delimiter = ','): array { + public function parse(string $data, callable $cast = null, string $delimiter = ','): array + { $data = \trim($data); if ($data[0] !== '{' || \substr($data, -1) !== '}') { @@ -42,7 +44,8 @@ public function parse(string $data, callable $cast = null, string $delimiter = ' * * @throws ParseException */ - private function parser(string $data, callable $cast = null, string $delimiter = ','): \Generator { + private function parser(string $data, callable $cast = null, string $delimiter = ','): \Generator + { $data = \ltrim(\substr($data, 1)); do { @@ -108,7 +111,8 @@ private function parser(string $data, callable $cast = null, string $delimiter = * * @throws ParseException */ - private function trim(string &$data, int $position, string $delimiter): string { + private function trim(string &$data, int $position, string $delimiter): string + { $data = \ltrim(\substr($data, $position)); if ($data === '') { diff --git a/src/Internal/PooledStatement.php b/src/Internal/PooledStatement.php index 73d25aa..67afe0a 100644 --- a/src/Internal/PooledStatement.php +++ b/src/Internal/PooledStatement.php @@ -9,7 +9,8 @@ use Amp\Sql\Statement; use function Amp\call; -final class PooledStatement implements Statement { +final class PooledStatement implements Statement +{ /** @var Pool */ private $pool; @@ -33,7 +34,8 @@ final class PooledStatement implements Statement { * @param Statement $statement * @param callable $prepare */ - public function __construct(Pool $pool, Statement $statement, callable $prepare) { + public function __construct(Pool $pool, Statement $statement, callable $prepare) + { $this->lastUsedAt = \time(); $this->statements = $statements = new \SplQueue; $this->pool = $pool; @@ -61,7 +63,8 @@ public function __construct(Pool $pool, Statement $statement, callable $prepare) Loop::unreference($this->timeoutWatcher); } - public function __destruct() { + public function __destruct() + { Loop::cancel($this->timeoutWatcher); } @@ -70,7 +73,8 @@ public function __destruct() { * * Unlike regular statements, as long as the pool is open this statement will not die. */ - public function execute(array $params = []): Promise { + public function execute(array $params = []): Promise + { $this->lastUsedAt = \time(); return call(function () use ($params) { @@ -108,7 +112,8 @@ public function execute(array $params = []): Promise { * * @param Statement $statement */ - private function push(Statement $statement) { + private function push(Statement $statement) + { $maxConnections = $this->pool->getMaxConnections(); if ($this->statements->count() > ($maxConnections / 10)) { @@ -124,17 +129,20 @@ private function push(Statement $statement) { /** {@inheritdoc} */ - public function isAlive(): bool { + public function isAlive(): bool + { return $this->pool->isAlive(); } /** {@inheritdoc} */ - public function getQuery(): string { + public function getQuery(): string + { return $this->sql; } /** {@inheritdoc} */ - public function lastUsedAt(): int { + public function lastUsedAt(): int + { return $this->lastUsedAt; } } diff --git a/src/Internal/PqStatementStorage.php b/src/Internal/PqStatementStorage.php index b2deffc..d0ea108 100644 --- a/src/Internal/PqStatementStorage.php +++ b/src/Internal/PqStatementStorage.php @@ -2,7 +2,8 @@ namespace Amp\Postgres\Internal; -class PqStatementStorage extends StatementStorage { +class PqStatementStorage extends StatementStorage +{ /** @var \pq\Statement */ public $statement; } diff --git a/src/Internal/ReferenceQueue.php b/src/Internal/ReferenceQueue.php index 2323447..bfde708 100644 --- a/src/Internal/ReferenceQueue.php +++ b/src/Internal/ReferenceQueue.php @@ -4,14 +4,16 @@ use Amp\Loop; -final class ReferenceQueue { +final class ReferenceQueue +{ /** @var callable[]|null */ private $onDestruct = []; /** @var int */ private $refCount = 1; - public function onDestruct(callable $onDestruct) { + public function onDestruct(callable $onDestruct) + { if (!$this->refCount) { try { $onDestruct(); @@ -26,12 +28,14 @@ public function onDestruct(callable $onDestruct) { $this->onDestruct[] = $onDestruct; } - public function reference() { + public function reference() + { \assert($this->refCount, "The reference queue has already been fully unreferenced and destroyed"); ++$this->refCount; } - public function unreference() { + public function unreference() + { \assert($this->refCount, "The reference queue has already been fully unreferenced and destroyed"); if (--$this->refCount) { @@ -50,7 +54,8 @@ public function unreference() { $this->onDestruct = null; } - public function isReferenced(): bool { + public function isReferenced(): bool + { return (bool) $this->refCount; } } diff --git a/src/Internal/StatementStorage.php b/src/Internal/StatementStorage.php index daa7b78..7d81ed2 100644 --- a/src/Internal/StatementStorage.php +++ b/src/Internal/StatementStorage.php @@ -4,7 +4,8 @@ use Amp\Struct; -class StatementStorage { +class StatementStorage +{ use Struct; /** @var |null */ diff --git a/src/Internal/functions.php b/src/Internal/functions.php index d53ae64..86a9b38 100644 --- a/src/Internal/functions.php +++ b/src/Internal/functions.php @@ -14,7 +14,8 @@ * * @return string SQL statement with Postgres-style placeholders */ -function parseNamedParams(string $sql, array &$names = null): string { +function parseNamedParams(string $sql, array &$names = null): string +{ $names = []; return \preg_replace_callback(STATEMENT_PARAM_REGEX, function (array $matches) use (&$names) { static $index = 0, $unnamed = 0, $numbered = 1; @@ -44,7 +45,8 @@ function parseNamedParams(string $sql, array &$names = null): string { * * @throws \Error If the $param array does not contain a key corresponding to a named parameter. */ -function replaceNamedParams(array $params, array $names): array { +function replaceNamedParams(array $params, array $names): array +{ $values = []; foreach ($names as $index => $name) { if (!\array_key_exists($name, $params)) { diff --git a/src/Link.php b/src/Link.php index 88c5375..77686e9 100644 --- a/src/Link.php +++ b/src/Link.php @@ -5,7 +5,8 @@ use Amp\Promise; use Amp\Sql\Link as SqlLink; -interface Link extends SqlLink { +interface Link extends SqlLink +{ /** * @param string $channel Channel name. * diff --git a/src/Listener.php b/src/Listener.php index 70cfc08..d78edec 100644 --- a/src/Listener.php +++ b/src/Listener.php @@ -6,7 +6,8 @@ use Amp\Promise; use Amp\Sql\Operation; -final class Listener implements Iterator, Operation { +final class Listener implements Iterator, Operation +{ /** @var \Amp\Iterator */ private $iterator; @@ -24,14 +25,16 @@ final class Listener implements Iterator, Operation { * @param string $channel Channel name. * @param callable(string $channel): $unlisten Function invoked to unlisten from the channel. */ - public function __construct(Iterator $iterator, string $channel, callable $unlisten) { + public function __construct(Iterator $iterator, string $channel, callable $unlisten) + { $this->iterator = $iterator; $this->channel = $channel; $this->unlisten = $unlisten; $this->queue = new Internal\ReferenceQueue; } - public function __destruct() { + public function __destruct() + { if ($this->unlisten) { $this->unlisten(); // Invokes $this->queue->complete(). } @@ -40,14 +43,16 @@ public function __destruct() { /** * {@inheritdoc} */ - public function onDestruct(callable $onComplete) { + public function onDestruct(callable $onComplete) + { $this->queue->onDestruct($onComplete); } /** * {@inheritdoc} */ - public function advance(): Promise { + public function advance(): Promise + { return $this->iterator->advance(); } @@ -56,14 +61,16 @@ public function advance(): Promise { * * @return Notification */ - public function getCurrent(): Notification { + public function getCurrent(): Notification + { return $this->iterator->getCurrent(); } /** * @return string Channel name. */ - public function getChannel(): string { + public function getChannel(): string + { return $this->channel; } @@ -74,7 +81,8 @@ public function getChannel(): string { * * @throws \Error If this method was previously invoked. */ - public function unlisten(): Promise { + public function unlisten(): Promise + { if (!$this->unlisten) { throw new \Error("Already unlistened on this channel"); } diff --git a/src/Notification.php b/src/Notification.php index 7d714c5..39d31e0 100644 --- a/src/Notification.php +++ b/src/Notification.php @@ -4,7 +4,8 @@ use Amp\Struct; -final class Notification { +final class Notification +{ use Struct; /** @var string Channel name. */ diff --git a/src/ParseException.php b/src/ParseException.php index 4c08e6b..bc66d5e 100644 --- a/src/ParseException.php +++ b/src/ParseException.php @@ -4,8 +4,10 @@ use Amp\Sql\FailureException; -class ParseException extends FailureException { - public function __construct(string $message = '') { +class ParseException extends FailureException +{ + public function __construct(string $message = '') + { $message = "Parse error while splitting array" . (($message === '') ? '' : ": " . $message); parent::__construct($message); } diff --git a/src/PgSqlCommandResult.php b/src/PgSqlCommandResult.php index bae37fc..909c852 100644 --- a/src/PgSqlCommandResult.php +++ b/src/PgSqlCommandResult.php @@ -4,35 +4,40 @@ use Amp\Sql\CommandResult; -final class PgSqlCommandResult implements CommandResult { +final class PgSqlCommandResult implements CommandResult +{ /** @var resource PostgreSQL result resource. */ private $handle; /** * @param resource $handle PostgreSQL result resource. */ - public function __construct($handle) { + public function __construct($handle) + { $this->handle = $handle; } /** * Frees the result resource. */ - public function __destruct() { + public function __destruct() + { \pg_free_result($this->handle); } /** * @return int Number of rows affected by the INSERT, UPDATE, or DELETE query. */ - public function affectedRows(): int { + public function affectedRows(): int + { return \pg_affected_rows($this->handle); } /** * @return string */ - public function lastOid(): string { + public function lastOid(): string + { return (string) \pg_last_oid($this->handle); } } diff --git a/src/PgSqlConnection.php b/src/PgSqlConnection.php index 5fb3bc7..c92e1b2 100644 --- a/src/PgSqlConnection.php +++ b/src/PgSqlConnection.php @@ -12,7 +12,8 @@ use Amp\Sql\ConnectionConfig; use Amp\Sql\ConnectionException; -final class PgSqlConnection extends Connection { +final class PgSqlConnection extends Connection +{ use CallableMaker; /** @@ -23,7 +24,8 @@ final class PgSqlConnection extends Connection { * * @throws \Error If pecl-ev is used as a loop extension. */ - public static function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise { + public static function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise + { // @codeCoverageIgnoreStart if (Loop::get()->getHandle() instanceof \EvLoop) { throw new \Error('ext-pgsql is not compatible with pecl-ev; use pecl-pq or a different loop extension'); @@ -88,7 +90,8 @@ public static function connect(ConnectionConfig $connectionConfig, CancellationT * @param resource $handle PostgreSQL connection handle. * @param resource $socket PostgreSQL connection stream socket. */ - public function __construct($handle, $socket) { + public function __construct($handle, $socket) + { parent::__construct(new PgSqlHandle($handle, $socket)); } } diff --git a/src/PgSqlHandle.php b/src/PgSqlHandle.php index 4e4ca82..061c4b5 100644 --- a/src/PgSqlHandle.php +++ b/src/PgSqlHandle.php @@ -13,7 +13,8 @@ use Amp\Success; use function Amp\call; -final class PgSqlHandle implements Handle { +final class PgSqlHandle implements Handle +{ use CallableMaker; const DIAGNOSTIC_CODES = [ @@ -61,7 +62,8 @@ final class PgSqlHandle implements Handle { * @param resource $handle PostgreSQL connection handle. * @param resource $socket PostgreSQL connection stream socket. */ - public function __construct($handle, $socket) { + public function __construct($handle, $socket) + { $this->handle = $handle; $this->lastUsedAt = \time(); @@ -151,14 +153,16 @@ public function __construct($handle, $socket) { /** * Frees Io watchers from loop. */ - public function __destruct() { + public function __destruct() + { $this->free(); } /** * {@inheritdoc} */ - public function close() { + public function close() + { if ($this->deferred) { $deferred = $this->deferred; $this->deferred = null; @@ -170,7 +174,8 @@ public function close() { $this->handle = null; } - private function free() { + private function free() + { if (\is_resource($this->handle)) { \pg_close($this->handle); } @@ -182,14 +187,16 @@ private function free() { /** * {@inheritdoc} */ - public function isAlive(): bool { + public function isAlive(): bool + { return $this->handle !== null; } /** * {@inheritdoc} */ - public function lastUsedAt(): int { + public function lastUsedAt(): int + { return $this->lastUsedAt; } @@ -203,7 +210,8 @@ public function lastUsedAt(): int { * * @throws FailureException */ - private function send(callable $function, ...$args): \Generator { + private function send(callable $function, ...$args): \Generator + { while ($this->deferred) { try { yield $this->deferred->promise(); @@ -246,7 +254,8 @@ private function send(callable $function, ...$args): \Generator { * @throws FailureException * @throws QueryError */ - private function createResult($result) { + private function createResult($result) + { switch (\pg_result_status($result, \PGSQL_STATUS_LONG)) { case \PGSQL_EMPTY_QUERY: throw new QueryError("Empty query string"); @@ -281,7 +290,8 @@ private function createResult($result) { * * @return Promise */ - public function statementExecute(string $name, array $params): Promise { + public function statementExecute(string $name, array $params): Promise + { return call(function () use ($name, $params) { return $this->createResult(yield from $this->send("pg_send_execute", $name, $params)); }); @@ -294,7 +304,8 @@ public function statementExecute(string $name, array $params): Promise { * * @throws \Error */ - public function statementDeallocate(string $name): Promise { + public function statementDeallocate(string $name): Promise + { if (!\is_resource($this->handle)) { return new Success; // Connection closed, no need to deallocate. } @@ -315,7 +326,8 @@ public function statementDeallocate(string $name): Promise { /** * {@inheritdoc} */ - public function query(string $sql): Promise { + public function query(string $sql): Promise + { if (!\is_resource($this->handle)) { throw new \Error("The connection to the database has been closed"); } @@ -328,7 +340,8 @@ public function query(string $sql): Promise { /** * {@inheritdoc} */ - public function execute(string $sql, array $params = []): Promise { + public function execute(string $sql, array $params = []): Promise + { if (!\is_resource($this->handle)) { throw new \Error("The connection to the database has been closed"); } @@ -344,7 +357,8 @@ public function execute(string $sql, array $params = []): Promise { /** * {@inheritdoc} */ - public function prepare(string $sql): Promise { + public function prepare(string $sql): Promise + { if (!\is_resource($this->handle)) { throw new \Error("The connection to the database has been closed"); } @@ -405,7 +419,8 @@ public function prepare(string $sql): Promise { /** * {@inheritdoc} */ - public function notify(string $channel, string $payload = ""): Promise { + public function notify(string $channel, string $payload = ""): Promise + { if ($payload === "") { return $this->query(\sprintf("NOTIFY %s", $this->quoteName($channel))); } @@ -416,7 +431,8 @@ public function notify(string $channel, string $payload = ""): Promise { /** * {@inheritdoc} */ - public function listen(string $channel): Promise { + public function listen(string $channel): Promise + { return call(function () use ($channel) { if (isset($this->listeners[$channel])) { throw new QueryError(\sprintf("Already listening on channel '%s'", $channel)); @@ -443,7 +459,8 @@ public function listen(string $channel): Promise { * * @throws \Error */ - private function unlisten(string $channel): Promise { + private function unlisten(string $channel): Promise + { \assert(isset($this->listeners[$channel]), "Not listening on that channel"); $emitter = $this->listeners[$channel]; @@ -462,7 +479,8 @@ private function unlisten(string $channel): Promise { /** * {@inheritdoc} */ - public function quoteString(string $data): string { + public function quoteString(string $data): string + { if (!\is_resource($this->handle)) { throw new \Error("The connection to the database has been closed"); } @@ -473,7 +491,8 @@ public function quoteString(string $data): string { /** * {@inheritdoc} */ - public function quoteName(string $name): string { + public function quoteName(string $name): string + { if (!\is_resource($this->handle)) { throw new \Error("The connection to the database has been closed"); } diff --git a/src/PgSqlResultSet.php b/src/PgSqlResultSet.php index 11cba5a..594a398 100644 --- a/src/PgSqlResultSet.php +++ b/src/PgSqlResultSet.php @@ -6,7 +6,8 @@ use Amp\Sql\FailureException; use Amp\Success; -final class PgSqlResultSet implements ResultSet { +final class PgSqlResultSet implements ResultSet +{ /** @var resource PostgreSQL result resource. */ private $handle; @@ -31,7 +32,8 @@ final class PgSqlResultSet implements ResultSet { /** * @param resource $handle PostgreSQL result resource. */ - public function __construct($handle) { + public function __construct($handle) + { $this->handle = $handle; $numFields = \pg_num_fields($this->handle); @@ -46,14 +48,16 @@ public function __construct($handle) { /** * Frees the result resource. */ - public function __destruct() { + public function __destruct() + { \pg_free_result($this->handle); } /** * {@inheritdoc} */ - public function advance(int $type = self::FETCH_ASSOC): Promise { + public function advance(int $type = self::FETCH_ASSOC): Promise + { $this->currentRow = null; $this->type = $type; @@ -67,7 +71,8 @@ public function advance(int $type = self::FETCH_ASSOC): Promise { /** * {@inheritdoc} */ - public function getCurrent() { + public function getCurrent() + { if ($this->currentRow !== null) { return $this->currentRow; } @@ -123,7 +128,8 @@ public function getCurrent() { * * @throws ParseException */ - private function cast(int $column, string $value) { + private function cast(int $column, string $value) + { switch ($this->fieldTypes[$column]) { case 16: // bool return $value === 't'; @@ -229,14 +235,16 @@ private function cast(int $column, string $value) { /** * @return int Number of rows in the result set. */ - public function numRows(): int { + public function numRows(): int + { return \pg_num_rows($this->handle); } /** * @return int Number of fields in each row. */ - public function numFields(): int { + public function numFields(): int + { return \pg_num_fields($this->handle); } @@ -247,7 +255,8 @@ public function numFields(): int { * * @throws \Error If the field number does not exist in the result. */ - public function fieldName(int $fieldNum): string { + public function fieldName(int $fieldNum): string + { if (0 > $fieldNum || $this->numFields() <= $fieldNum) { throw new \Error(\sprintf('No field with index %d in result', $fieldNum)); } @@ -262,7 +271,8 @@ public function fieldName(int $fieldNum): string { * * @throws \Error If the field name does not exist in the result. */ - public function fieldNum(string $fieldName): int { + public function fieldNum(string $fieldName): int + { $result = \pg_field_num($this->handle, $fieldName); if (-1 === $result) { diff --git a/src/PgSqlStatement.php b/src/PgSqlStatement.php index 0468728..aa9fdf3 100644 --- a/src/PgSqlStatement.php +++ b/src/PgSqlStatement.php @@ -6,7 +6,8 @@ use Amp\Sql\Operation; use Amp\Sql\Statement; -final class PgSqlStatement implements Statement, Operation { +final class PgSqlStatement implements Statement, Operation +{ /** @var PgSqlHandle */ private $handle; @@ -31,7 +32,8 @@ final class PgSqlStatement implements Statement, Operation { * @param string $sql * @param string[] $params */ - public function __construct(PgSqlHandle $handle, string $name, string $sql, array $params) { + public function __construct(PgSqlHandle $handle, string $name, string $sql, array $params) + { $this->handle = $handle; $this->name = $name; $this->sql = $sql; @@ -40,33 +42,39 @@ public function __construct(PgSqlHandle $handle, string $name, string $sql, arra $this->lastUsedAt = \time(); } - public function __destruct() { + public function __destruct() + { $this->handle->statementDeallocate($this->name); $this->queue->unreference(); } /** {@inheritdoc} */ - public function isAlive(): bool { + public function isAlive(): bool + { return $this->handle->isAlive(); } /** {@inheritdoc} */ - public function getQuery(): string { + public function getQuery(): string + { return $this->sql; } /** {@inheritdoc} */ - public function lastUsedAt(): int { + public function lastUsedAt(): int + { return $this->lastUsedAt; } /** {@inheritdoc} */ - public function execute(array $params = []): Promise { + public function execute(array $params = []): Promise + { return $this->handle->statementExecute($this->name, Internal\replaceNamedParams($params, $this->params)); } /** {@inheritdoc} */ - public function onDestruct(callable $onDestruct) { + public function onDestruct(callable $onDestruct) + { $this->queue->onDestruct($onDestruct); } } diff --git a/src/Pool.php b/src/Pool.php index 2613943..fe59fe1 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -10,12 +10,11 @@ use Amp\Sql\Connector; use Amp\Sql\FailureException; use Amp\Sql\Operation; -use Amp\Sql\Pool as SqlPool; +use Amp\Sql\Statement; use function Amp\call; use function Amp\coroutine; -use Amp\Sql\Statement; -final class Pool implements SqlPool +final class Pool implements Pool { use CallableMaker; @@ -112,19 +111,23 @@ public function __construct( $this->lastUsedAt = \time(); } - public function __destruct() { + public function __destruct() + { Loop::cancel($this->timeoutWatcher); } - public function resetConnections(bool $reset = true) { + public function resetConnections(bool $reset = true) + { $this->resetConnections = $reset; } - public function getIdleTimeout(): int { + public function getIdleTimeout(): int + { return $this->idleTimeout; } - public function setIdleTimeout(int $timeout) { + public function setIdleTimeout(int $timeout) + { if ($timeout < 1) { throw new \Error("Timeout must be greater than or equal to 1"); } @@ -135,7 +138,8 @@ public function setIdleTimeout(int $timeout) { /** * @return bool */ - public function isAlive(): bool { + public function isAlive(): bool + { return !$this->closed; } @@ -147,7 +151,8 @@ public function lastUsedAt(): int /** * Close all connections in the pool. No further queries may be made after a pool is closed. */ - public function close() { + public function close() + { $this->closed = true; foreach ($this->connections as $connection) { $connection->close(); @@ -161,7 +166,8 @@ public function close() { /** * {@inheritdoc} */ - public function extractConnection(): Promise { + public function extractConnection(): Promise + { return call(function () { $connection = yield from $this->pop(); $this->connections->detach($connection); @@ -175,21 +181,24 @@ public function extractConnection(): Promise { /** * {@inheritdoc} */ - public function getConnectionCount(): int { + public function getConnectionCount(): int + { return $this->connections->count(); } /** * {@inheritdoc} */ - public function getIdleConnectionCount(): int { + public function getIdleConnectionCount(): int + { return $this->idle->count(); } /** * {@inheritdoc} */ - public function getMaxConnections(): int { + public function getMaxConnections(): int + { return $this->maxConnections; } @@ -201,7 +210,8 @@ public function getMaxConnections(): int { * @throws FailureException If creating a new connection fails. * @throws \Error If the pool has been closed. */ - private function pop(): \Generator { + private function pop(): \Generator + { if ($this->closed) { throw new \Error("The pool has been closed"); } @@ -275,7 +285,8 @@ private function pop(): \Generator { * * @throws \Error If the connection is not part of this pool. */ - private function push(Connection $connection) { + private function push(Connection $connection) + { \assert(isset($this->connections[$connection]), 'Connection is not part of this pool'); if ($connection->isAlive()) { @@ -294,7 +305,8 @@ private function push(Connection $connection) { /** * {@inheritdoc} */ - public function query(string $sql): Promise { + public function query(string $sql): Promise + { return call(function () use ($sql) { /** @var Connection $connection */ $connection = yield from $this->pop(); @@ -323,7 +335,8 @@ public function query(string $sql): Promise { /** * {@inheritdoc} */ - public function execute(string $sql, array $params = []): Promise { + public function execute(string $sql, array $params = []): Promise + { return call(function () use ($sql, $params) { /** @var Connection $connection */ $connection = yield from $this->pop(); @@ -354,7 +367,8 @@ public function execute(string $sql, array $params = []): Promise { * * Prepared statements returned by this method will stay alive as long as the pool remains open. */ - public function prepare(string $sql): Promise { + public function prepare(string $sql): Promise + { return call(function () use ($sql) { $statement = yield from $this->doPrepare($sql); @@ -364,7 +378,8 @@ public function prepare(string $sql): Promise { }); } - private function doPrepare(string $sql): \Generator { + private function doPrepare(string $sql): \Generator + { /** @var Connection $connection */ $connection = yield from $this->pop(); @@ -393,7 +408,8 @@ private function doPrepare(string $sql): \Generator { /** * {@inheritdoc} */ - public function notify(string $channel, string $payload = ""): Promise { + public function notify(string $channel, string $payload = ""): Promise + { return call(function () use ($channel, $payload) { /** @var Connection $connection */ $connection = yield from $this->pop(); @@ -413,7 +429,8 @@ public function notify(string $channel, string $payload = ""): Promise { /** * {@inheritdoc} */ - public function listen(string $channel): Promise { + public function listen(string $channel): Promise + { return call(function () use ($channel) { ++$this->listenerCount; @@ -454,7 +471,8 @@ public function listen(string $channel): Promise { /** * {@inheritdoc} */ - public function transaction(int $isolation = Transaction::COMMITTED): Promise { + public function transaction(int $isolation = Transaction::COMMITTED): Promise + { return call(function () use ($isolation) { /** @var Connection $connection */ $connection = yield from $this->pop(); diff --git a/src/Pool2.php b/src/Pool2.php new file mode 100644 index 0000000..e50a5ed --- /dev/null +++ b/src/Pool2.php @@ -0,0 +1,46 @@ + + */ + public function extractConnection(): Promise; + + /** + * @return int Total number of active connections in the pool. + */ + public function getConnectionCount(): int; + + /** + * @return int Total number of idle connections in the pool. + */ + public function getIdleConnectionCount(): int; + + /** + * @return int Maximum number of connections this pool will create. + */ + public function getMaxConnections(): int; + + /** + * @param bool $reset True to automatically reset a connection in the pool before using it for an operation. + */ + public function resetConnections(bool $reset); + + /** + * @return int Number of seconds a connection may remain idle before it is automatically closed. + */ + public function getIdleTimeout(): int; + + /** + * @param int $timeout Number of seconds a connection may remain idle before it is automatically closed. + */ + public function setIdleTimeout(int $timeout); +} diff --git a/src/PoolError.php b/src/PoolError.php index 9119703..926ab2e 100644 --- a/src/PoolError.php +++ b/src/PoolError.php @@ -2,5 +2,6 @@ namespace Amp\Postgres; -final class PoolError extends \Error { +final class PoolError extends \Error +{ } diff --git a/src/PqBufferedResultSet.php b/src/PqBufferedResultSet.php index cf54c74..968b879 100644 --- a/src/PqBufferedResultSet.php +++ b/src/PqBufferedResultSet.php @@ -6,7 +6,8 @@ use Amp\Success; use pq; -final class PqBufferedResultSet implements ResultSet { +final class PqBufferedResultSet implements ResultSet +{ /** @var \pq\Result */ private $result; @@ -22,7 +23,8 @@ final class PqBufferedResultSet implements ResultSet { /** * @param pq\Result $result PostgreSQL result object. */ - public function __construct(pq\Result $result) { + public function __construct(pq\Result $result) + { $this->result = $result; $this->result->autoConvert = pq\Result::CONV_SCALAR | pq\Result::CONV_ARRAY; } @@ -30,7 +32,8 @@ public function __construct(pq\Result $result) { /** * {@inheritdoc} */ - public function advance(int $type = self::FETCH_ASSOC): Promise { + public function advance(int $type = self::FETCH_ASSOC): Promise + { $this->currentRow = null; $this->type = $type; @@ -44,7 +47,8 @@ public function advance(int $type = self::FETCH_ASSOC): Promise { /** * {@inheritdoc} */ - public function getCurrent() { + public function getCurrent() + { if ($this->currentRow !== null) { return $this->currentRow; } @@ -65,11 +69,13 @@ public function getCurrent() { } } - public function numRows(): int { + public function numRows(): int + { return $this->result->numRows; } - public function numFields(): int { + public function numFields(): int + { return $this->result->numCols; } } diff --git a/src/PqCommandResult.php b/src/PqCommandResult.php index 37ba938..43af02d 100644 --- a/src/PqCommandResult.php +++ b/src/PqCommandResult.php @@ -5,21 +5,24 @@ use Amp\Sql\CommandResult; use pq; -final class PqCommandResult implements CommandResult { +final class PqCommandResult implements CommandResult +{ /** @var \pq\Result PostgreSQL result object. */ private $result; /** * @param \pq\Result $result PostgreSQL result object. */ - public function __construct(pq\Result $result) { + public function __construct(pq\Result $result) + { $this->result = $result; } /** * @return int Number of rows affected by the INSERT, UPDATE, or DELETE query. */ - public function affectedRows(): int { + public function affectedRows(): int + { return $this->result->affectedRows; } } diff --git a/src/PqConnection.php b/src/PqConnection.php index 6ff083a..9415ae5 100644 --- a/src/PqConnection.php +++ b/src/PqConnection.php @@ -12,14 +12,16 @@ use Amp\Sql\ConnectionException; use pq; -final class PqConnection extends Connection { +final class PqConnection extends Connection +{ /** * @param ConnectionConfig $connectionConfig * @param CancellationToken $token * * @return Promise */ - public static function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise { + public static function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise + { $connectionString = \str_replace(";", " ", $connectionConfig->connectionString()); try { @@ -71,7 +73,8 @@ public static function connect(ConnectionConfig $connectionConfig, CancellationT /** * @param \pq\Connection $handle */ - public function __construct(pq\Connection $handle) { + public function __construct(pq\Connection $handle) + { parent::__construct(new PqHandle($handle)); } } diff --git a/src/PqHandle.php b/src/PqHandle.php index fb09613..b2e1407 100644 --- a/src/PqHandle.php +++ b/src/PqHandle.php @@ -15,7 +15,8 @@ use function Amp\call; use function Amp\coroutine; -final class PqHandle implements Handle { +final class PqHandle implements Handle +{ use CallableMaker; /** @var \pq\Connection PostgreSQL connection object. */ @@ -56,7 +57,8 @@ final class PqHandle implements Handle { * * @param \pq\Connection $handle */ - public function __construct(pq\Connection $handle) { + public function __construct(pq\Connection $handle) + { $this->handle = $handle; $this->lastUsedAt = \time(); @@ -131,28 +133,32 @@ public function __construct(pq\Connection $handle) { /** * Frees Io watchers from loop. */ - public function __destruct() { + public function __destruct() + { $this->free(); } /** * {@inheritdoc} */ - public function isAlive(): bool { + public function isAlive(): bool + { return $this->handle !== null; } /** * {@inheritdoc} */ - public function lastUsedAt(): int { + public function lastUsedAt(): int + { return $this->lastUsedAt; } /** * {@inheritdoc} */ - public function close() { + public function close() + { if ($this->deferred) { $deferred = $this->deferred; $this->deferred = null; @@ -164,7 +170,8 @@ public function close() { $this->free(); } - private function free() { + private function free() + { Loop::cancel($this->poll); Loop::cancel($this->await); } @@ -179,7 +186,8 @@ private function free() { * * @throws FailureException */ - private function send(callable $method, ...$args): \Generator { + private function send(callable $method, ...$args): \Generator + { while ($this->busy) { try { yield $this->busy->promise(); @@ -245,7 +253,8 @@ private function send(callable $method, ...$args): \Generator { } } - private function fetch(): \Generator { + private function fetch(): \Generator + { if (!$this->handle->busy) { // Results buffered. $result = $this->handle->getResult(); } else { @@ -279,7 +288,8 @@ private function fetch(): \Generator { } } - private function release() { + private function release() + { \assert( $this->busy instanceof Deferred && $this->busy !== $this->deferred, "Connection in invalid state when releasing" @@ -299,7 +309,8 @@ private function release() { * @return Promise * @throws FailureException */ - public function statementExecute(string $name, array $params): Promise { + public function statementExecute(string $name, array $params): Promise + { \assert(isset($this->statements[$name]), "Named statement not found when executing"); $statement = $this->statements[$name]->statement; @@ -314,7 +325,8 @@ public function statementExecute(string $name, array $params): Promise { * * @throws FailureException */ - public function statementDeallocate(string $name): Promise { + public function statementDeallocate(string $name): Promise + { if (!$this->handle) { return new Success; // Connection dead. } @@ -335,7 +347,8 @@ public function statementDeallocate(string $name): Promise { /** * {@inheritdoc} */ - public function query(string $sql): Promise { + public function query(string $sql): Promise + { if (!$this->handle) { throw new \Error("The connection to the database has been closed"); } @@ -346,7 +359,8 @@ public function query(string $sql): Promise { /** * {@inheritdoc} */ - public function execute(string $sql, array $params = []): Promise { + public function execute(string $sql, array $params = []): Promise + { if (!$this->handle) { throw new \Error("The connection to the database has been closed"); } @@ -360,7 +374,8 @@ public function execute(string $sql, array $params = []): Promise { /** * {@inheritdoc} */ - public function prepare(string $sql): Promise { + public function prepare(string $sql): Promise + { if (!$this->handle) { throw new \Error("The connection to the database has been closed"); } @@ -401,14 +416,16 @@ public function prepare(string $sql): Promise { /** * {@inheritdoc} */ - public function notify(string $channel, string $payload = ""): Promise { + public function notify(string $channel, string $payload = ""): Promise + { return new Coroutine($this->send([$this->handle, "notifyAsync"], $channel, $payload)); } /** * {@inheritdoc} */ - public function listen(string $channel): Promise { + public function listen(string $channel): Promise + { return call(function () use ($channel) { if (isset($this->listeners[$channel])) { throw new QueryError(\sprintf("Already listening on channel '%s'", $channel)); @@ -445,7 +462,8 @@ static function (string $channel, string $message, int $pid) use ($emitter) { * * @throws \Error */ - private function unlisten(string $channel): Promise { + private function unlisten(string $channel): Promise + { \assert(isset($this->listeners[$channel]), "Not listening on that channel"); $emitter = $this->listeners[$channel]; @@ -464,7 +482,8 @@ private function unlisten(string $channel): Promise { /** * {@inheritdoc} */ - public function quoteString(string $data): string { + public function quoteString(string $data): string + { if (!$this->handle) { throw new \Error("The connection to the database has been closed"); } @@ -475,7 +494,8 @@ public function quoteString(string $data): string { /** * {@inheritdoc} */ - public function quoteName(string $name): string { + public function quoteName(string $name): string + { if (!$this->handle) { throw new \Error("The connection to the database has been closed"); } diff --git a/src/PqStatement.php b/src/PqStatement.php index 6f4332e..1788e44 100644 --- a/src/PqStatement.php +++ b/src/PqStatement.php @@ -6,7 +6,8 @@ use Amp\Sql\Operation; use Amp\Sql\Statement; -final class PqStatement implements Statement, Operation { +final class PqStatement implements Statement, Operation +{ /** @var @return PromisePqHandle */ private $handle; @@ -31,7 +32,8 @@ final class PqStatement implements Statement, Operation { * @param string $sql Original prepared SQL query. * @param string[] $params Parameter indices to parameter names. */ - public function __construct(PqHandle $handle, string $name, string $sql, array $params) { + public function __construct(PqHandle $handle, string $name, string $sql, array $params) + { $this->handle = $handle; $this->name = $name; $this->params = $params; @@ -40,34 +42,40 @@ public function __construct(PqHandle $handle, string $name, string $sql, array $ $this->lastUsedAt = \time(); } - public function __destruct() { + public function __destruct() + { $this->handle->statementDeallocate($this->name); $this->queue->unreference(); } /** {@inheritdoc} */ - public function isAlive(): bool { + public function isAlive(): bool + { return $this->handle->isAlive(); } /** {@inheritdoc} */ - public function getQuery(): string { + public function getQuery(): string + { return $this->sql; } /** {@inheritdoc} */ - public function lastUsedAt(): int { + public function lastUsedAt(): int + { return $this->lastUsedAt; } /** {@inheritdoc} */ - public function execute(array $params = []): Promise { + public function execute(array $params = []): Promise + { $this->lastUsedAt = \time(); return $this->handle->statementExecute($this->name, Internal\replaceNamedParams($params, $this->params)); } /** {@inheritdoc} */ - public function onDestruct(callable $onDestruct) { + public function onDestruct(callable $onDestruct) + { $this->queue->onDestruct($onDestruct); } } diff --git a/src/PqUnbufferedResultSet.php b/src/PqUnbufferedResultSet.php index db7c5e8..0794ab0 100644 --- a/src/PqUnbufferedResultSet.php +++ b/src/PqUnbufferedResultSet.php @@ -6,7 +6,8 @@ use Amp\Promise; use pq; -final class PqUnbufferedResultSet implements ResultSet { +final class PqUnbufferedResultSet implements ResultSet +{ /** @var int */ private $numCols; @@ -26,7 +27,8 @@ final class PqUnbufferedResultSet implements ResultSet { * @param callable(): $fetch Function to fetch next result row. * @param \pq\Result $result PostgreSQL result object. */ - public function __construct(callable $fetch, pq\Result $result) { + public function __construct(callable $fetch, pq\Result $result) + { $this->numCols = $result->numCols; $this->queue = $queue = new Internal\ReferenceQueue; @@ -46,7 +48,8 @@ public function __construct(callable $fetch, pq\Result $result) { /** * {@inheritdoc} */ - public function advance(int $type = self::FETCH_ASSOC): Promise { + public function advance(int $type = self::FETCH_ASSOC): Promise + { $this->currentRow = null; $this->type = $type; @@ -56,7 +59,8 @@ public function advance(int $type = self::FETCH_ASSOC): Promise { /** * {@inheritdoc} */ - public function getCurrent() { + public function getCurrent() + { if ($this->currentRow !== null) { return $this->currentRow; } @@ -79,14 +83,16 @@ public function getCurrent() { /** * @return int Number of fields (columns) in each result set. */ - public function numFields(): int { + public function numFields(): int + { return $this->numCols; } /** * {@inheritdoc} */ - public function onDestruct(callable $onComplete) { + public function onDestruct(callable $onComplete) + { $this->queue->onDestruct($onComplete); } } diff --git a/src/QueryExecutionError.php b/src/QueryExecutionError.php index ede93fa..ab7e8ad 100644 --- a/src/QueryExecutionError.php +++ b/src/QueryExecutionError.php @@ -4,16 +4,19 @@ use Amp\Sql\QueryError; -class QueryExecutionError extends QueryError { +class QueryExecutionError extends QueryError +{ /** @var mixed[] */ private $diagnostics; - public function __construct(string $message, array $diagnostics, \Throwable $previous = null) { + public function __construct(string $message, array $diagnostics, \Throwable $previous = null) + { parent::__construct($message, 0, $previous); $this->diagnostics = $diagnostics; } - public function getDiagnostics(): array { + public function getDiagnostics(): array + { return $this->diagnostics; } } diff --git a/src/ResultSet.php b/src/ResultSet.php index 5e1fca8..a7ac24c 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -4,7 +4,8 @@ use Amp\Sql\ResultSet as SqlResultSet; -interface ResultSet extends SqlResultSet { +interface ResultSet extends SqlResultSet +{ /** * Returns the number of fields (columns) in each row. * diff --git a/src/TimeoutConnector.php b/src/TimeoutConnector.php index 253dd2e..8aa98e1 100644 --- a/src/TimeoutConnector.php +++ b/src/TimeoutConnector.php @@ -8,7 +8,8 @@ use Amp\Sql\FailureException; use Amp\TimeoutCancellationToken; -final class TimeoutConnector implements Connector { +final class TimeoutConnector implements Connector +{ const DEFAULT_TIMEOUT = 5000; /** @var int */ @@ -17,7 +18,8 @@ final class TimeoutConnector implements Connector { /** * @param int $timeout Milliseconds until connections attempts are cancelled. */ - public function __construct(int $timeout = self::DEFAULT_TIMEOUT) { + public function __construct(int $timeout = self::DEFAULT_TIMEOUT) + { $this->timeout = $timeout; } @@ -28,7 +30,8 @@ public function __construct(int $timeout = self::DEFAULT_TIMEOUT) { * * @throws \Error If neither ext-pgsql or pecl-pq is loaded. */ - public function connect(ConnectionConfig $connectionConfig): Promise { + public function connect(ConnectionConfig $connectionConfig): Promise + { $token = new TimeoutCancellationToken($this->timeout); if (\extension_loaded("pq")) { diff --git a/src/Transaction.php b/src/Transaction.php index 6a5ffc9..e274320 100644 --- a/src/Transaction.php +++ b/src/Transaction.php @@ -6,7 +6,8 @@ use Amp\Sql\Operation; use Amp\Sql\Transaction as SqlTransaction; -final class Transaction implements Handle, SqlTransaction { +final class Transaction implements Handle, SqlTransaction +{ /** @var Handle|null */ private $handle; @@ -22,7 +23,8 @@ final class Transaction implements Handle, SqlTransaction { * * @throws \Error If the isolation level is invalid. */ - public function __construct(Handle $handle, int $isolation = self::ISOLATION_COMMITTED) { + public function __construct(Handle $handle, int $isolation = self::ISOLATION_COMMITTED) + { switch ($isolation) { case self::ISOLATION_UNCOMMITTED: case self::ISOLATION_COMMITTED: @@ -39,7 +41,8 @@ public function __construct(Handle $handle, int $isolation = self::ISOLATION_COM $this->queue = new Internal\ReferenceQueue; } - public function __destruct() { + public function __destruct() + { if ($this->handle) { $this->rollback(); // Invokes $this->queue->complete(). } @@ -48,7 +51,8 @@ public function __destruct() { /** * {@inheritdoc} */ - public function lastUsedAt(): int { + public function lastUsedAt(): int + { return $this->handle->lastUsedAt(); } @@ -57,7 +61,8 @@ public function lastUsedAt(): int { * * Closes and commits all changes in the transaction. */ - public function close() { + public function close() + { if ($this->handle) { $this->commit(); // Invokes $this->queue->unreference(). } @@ -66,28 +71,32 @@ public function close() { /** * {@inheritdoc} */ - public function onDestruct(callable $onComplete) { + public function onDestruct(callable $onComplete) + { $this->queue->onDestruct($onComplete); } /** * {@inheritdoc} */ - public function isAlive(): bool { + public function isAlive(): bool + { return $this->handle->isAlive(); } /** * @return bool True if the transaction is active, false if it has been committed or rolled back. */ - public function isActive(): bool { + public function isActive(): bool + { return $this->handle !== null; } /** * @return int */ - public function getIsolationLevel(): int { + public function getIsolationLevel(): int + { return $this->isolation; } @@ -96,7 +105,8 @@ public function getIsolationLevel(): int { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function query(string $sql): Promise { + public function query(string $sql): Promise + { if ($this->handle === null) { throw new TransactionError("The transaction has been committed or rolled back"); } @@ -122,7 +132,8 @@ public function query(string $sql): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function prepare(string $sql): Promise { + public function prepare(string $sql): Promise + { if ($this->handle === null) { throw new TransactionError("The transaction has been committed or rolled back"); } @@ -148,7 +159,8 @@ public function prepare(string $sql): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function execute(string $sql, array $params = []): Promise { + public function execute(string $sql, array $params = []): Promise + { if ($this->handle === null) { throw new TransactionError("The transaction has been committed or rolled back"); } @@ -175,7 +187,8 @@ public function execute(string $sql, array $params = []): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function notify(string $channel, string $payload = ""): Promise { + public function notify(string $channel, string $payload = ""): Promise + { if ($this->handle === null) { throw new TransactionError("The transaction has been committed or rolled back"); } @@ -190,7 +203,8 @@ public function notify(string $channel, string $payload = ""): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function commit(): Promise { + public function commit(): Promise + { if ($this->handle === null) { throw new TransactionError("The transaction has been committed or rolled back"); } @@ -209,7 +223,8 @@ public function commit(): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function rollback(): Promise { + public function rollback(): Promise + { if ($this->handle === null) { throw new TransactionError("The transaction has been committed or rolled back"); } @@ -230,7 +245,8 @@ public function rollback(): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function createSavepoint(string $identifier): Promise { + public function createSavepoint(string $identifier): Promise + { return $this->query("SAVEPOINT " . $this->quoteName($identifier)); } @@ -243,7 +259,8 @@ public function createSavepoint(string $identifier): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function rollbackTo(string $identifier): Promise { + public function rollbackTo(string $identifier): Promise + { return $this->query("ROLLBACK TO " . $this->quoteName($identifier)); } @@ -256,7 +273,8 @@ public function rollbackTo(string $identifier): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function releaseSavepoint(string $identifier): Promise { + public function releaseSavepoint(string $identifier): Promise + { return $this->query("RELEASE SAVEPOINT " . $this->quoteName($identifier)); } @@ -265,7 +283,8 @@ public function releaseSavepoint(string $identifier): Promise { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function quoteString(string $data): string { + public function quoteString(string $data): string + { if ($this->handle === null) { throw new TransactionError("The transaction has been committed or rolled back"); } @@ -278,7 +297,8 @@ public function quoteString(string $data): string { * * @throws TransactionError If the transaction has been committed or rolled back. */ - public function quoteName(string $name): string { + public function quoteName(string $name): string + { if ($this->handle === null) { throw new TransactionError("The transaction has been committed or rolled back"); } diff --git a/src/TransactionError.php b/src/TransactionError.php index 7f9c8ec..b497f7a 100644 --- a/src/TransactionError.php +++ b/src/TransactionError.php @@ -2,5 +2,6 @@ namespace Amp\Postgres; -class TransactionError extends \Error { +class TransactionError extends \Error +{ } diff --git a/src/functions.php b/src/functions.php index b799cca..80dd858 100644 --- a/src/functions.php +++ b/src/functions.php @@ -9,7 +9,8 @@ const LOOP_CONNECTOR_IDENTIFIER = Connector::class; -function connector(Connector $connector = null): Connector { +function connector(Connector $connector = null): Connector +{ if ($connector === null) { $connector = Loop::getState(LOOP_CONNECTOR_IDENTIFIER); if ($connector) { @@ -36,7 +37,8 @@ function connector(Connector $connector = null): Connector { * * @codeCoverageIgnore */ -function connect(ConnectionConfig $config): Promise { +function connect(ConnectionConfig $config): Promise +{ return connector()->connect($config); } @@ -48,7 +50,8 @@ function connect(ConnectionConfig $config): Promise { * * @return Pool */ -function pool(string $connectionString, int $maxConnections = Pool::DEFAULT_MAX_CONNECTIONS): Pool { +function pool(string $connectionString, int $maxConnections = Pool::DEFAULT_MAX_CONNECTIONS): Pool +{ return new Pool($connectionString, $maxConnections, connector()); } @@ -61,7 +64,8 @@ function pool(string $connectionString, int $maxConnections = Pool::DEFAULT_MAX_ * * @throws \Error If $value is an object without a __toString() method, a resource, or an unknown type. */ -function cast($value) { +function cast($value) +{ switch ($type = \gettype($value)) { case "NULL": case "integer": @@ -96,7 +100,8 @@ function cast($value) { * * @throws \Error If $array contains an object without a __toString() method, a resource, or an unknown type. */ -function encode(array $array): string { +function encode(array $array): string +{ $array = \array_map(function ($value) { switch (\gettype($value)) { case "NULL": diff --git a/test/AbstractConnectTest.php b/test/AbstractConnectTest.php index 7a79318..7753612 100644 --- a/test/AbstractConnectTest.php +++ b/test/AbstractConnectTest.php @@ -11,7 +11,8 @@ use Amp\TimeoutCancellationToken; use PHPUnit\Framework\TestCase; -abstract class AbstractConnectTest extends TestCase { +abstract class AbstractConnectTest extends TestCase +{ /** * @param ConnectionConfig $connectionConfig * @param CancellationToken|null $token @@ -20,7 +21,8 @@ abstract class AbstractConnectTest extends TestCase { */ abstract public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise; - public function testConnect() { + public function testConnect() + { Loop::run(function () { $connection = yield $this->connect( new \Amp\Postgres\ConnectionConfig(new \Amp\Postgres\ConnectionConfig('host=localhost user=postgres')), @@ -34,7 +36,8 @@ public function testConnect() { * @depends testConnect * @expectedException \Amp\CancelledException */ - public function testConnectCancellationBeforeConnect() { + public function testConnectCancellationBeforeConnect() + { Loop::run(function () { $source = new CancellationTokenSource; $token = $source->getToken(); @@ -46,7 +49,8 @@ public function testConnectCancellationBeforeConnect() { /** * @depends testConnectCancellationBeforeConnect */ - public function testConnectCancellationAfterConnect() { + public function testConnectCancellationAfterConnect() + { Loop::run(function () { $source = new CancellationTokenSource; $token = $source->getToken(); @@ -60,7 +64,8 @@ public function testConnectCancellationAfterConnect() { * @depends testConnectCancellationBeforeConnect * @expectedException \Amp\Sql\FailureException */ - public function testConnectInvalidUser() { + public function testConnectInvalidUser() + { Loop::run(function () { $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('host=localhost user=invalid'), new TimeoutCancellationToken(100)); }); @@ -70,7 +75,8 @@ public function testConnectInvalidUser() { * @depends testConnectCancellationBeforeConnect * @expectedException \Amp\Sql\FailureException */ - public function testConnectInvalidConnectionString() { + public function testConnectInvalidConnectionString() + { Loop::run(function () { $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('invalid connection string'), new TimeoutCancellationToken(100)); }); @@ -80,7 +86,8 @@ public function testConnectInvalidConnectionString() { * @depends testConnectCancellationBeforeConnect * @expectedException \Amp\Sql\FailureException */ - public function testConnectInvalidHost() { + public function testConnectInvalidHost() + { Loop::run(function () { $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('hostaddr=invalid.host user=postgres'), new TimeoutCancellationToken(100)); }); diff --git a/test/AbstractConnectionTest.php b/test/AbstractConnectionTest.php index 6b9d9d7..53032f5 100644 --- a/test/AbstractConnectionTest.php +++ b/test/AbstractConnectionTest.php @@ -2,8 +2,10 @@ namespace Amp\Postgres\Test; -abstract class AbstractConnectionTest extends AbstractLinkTest { - public function testIsAlive() { +abstract class AbstractConnectionTest extends AbstractLinkTest +{ + public function testIsAlive() + { $this->assertTrue($this->connection->isAlive()); } } diff --git a/test/AbstractLinkTest.php b/test/AbstractLinkTest.php index eb4cfe6..b32ecf0 100644 --- a/test/AbstractLinkTest.php +++ b/test/AbstractLinkTest.php @@ -16,14 +16,16 @@ use Amp\Sql\Statement; use PHPUnit\Framework\TestCase; -abstract class AbstractLinkTest extends TestCase { +abstract class AbstractLinkTest extends TestCase +{ /** @var \Amp\Postgres\Connection */ protected $connection; /** * @return array Start test data for database. */ - public function getData() { + public function getData() + { return [ ['amphp', 'org'], ['github', 'com'], @@ -39,11 +41,13 @@ public function getData() { */ abstract public function createLink(string $connectionString): Link; - public function setUp() { + public function setUp() + { $this->connection = $this->createLink('host=localhost user=postgres'); } - public function testQueryWithTupleResult() { + public function testQueryWithTupleResult() + { Loop::run(function () { /** @var \Amp\Postgres\ResultSet $result */ $result = yield $this->connection->query("SELECT * FROM test"); @@ -62,7 +66,8 @@ public function testQueryWithTupleResult() { }); } - public function testQueryWithUnconsumedTupleResult() { + public function testQueryWithUnconsumedTupleResult() + { Loop::run(function () { /** @var \Amp\Postgres\ResultSet $result */ $result = yield $this->connection->query("SELECT * FROM test"); @@ -84,7 +89,8 @@ public function testQueryWithUnconsumedTupleResult() { }); } - public function testQueryWithCommandResult() { + public function testQueryWithCommandResult() + { Loop::run(function () { /** @var CommandResult $result */ $result = yield $this->connection->query("INSERT INTO test VALUES ('canon', 'jp')"); @@ -95,16 +101,18 @@ public function testQueryWithCommandResult() { } /** - * @expectedException QueryError + * @expectedException \QueryError */ - public function testQueryWithEmptyQuery() { + public function testQueryWithEmptyQuery() + { Loop::run(function () { /** @var \Amp\Sql\CommandResult $result */ $result = yield $this->connection->query(''); }); } - public function testQueryWithSyntaxError() { + public function testQueryWithSyntaxError() + { Loop::run(function () { /** @var \Amp\Sql\CommandResult $result */ try { @@ -117,7 +125,8 @@ public function testQueryWithSyntaxError() { }); } - public function testPrepare() { + public function testPrepare() + { Loop::run(function () { $query = "SELECT * FROM test WHERE domain=\$1"; @@ -146,7 +155,8 @@ public function testPrepare() { /** * @depends testPrepare */ - public function testPrepareWithNamedParams() { + public function testPrepareWithNamedParams() + { Loop::run(function () { $query = "SELECT * FROM test WHERE domain=:domain AND tld=:tld"; @@ -175,7 +185,8 @@ public function testPrepareWithNamedParams() { /** * @depends testPrepare */ - public function testPrepareWithUnnamedParams() { + public function testPrepareWithUnnamedParams() + { Loop::run(function () { $query = "SELECT * FROM test WHERE domain=? AND tld=?"; @@ -204,7 +215,8 @@ public function testPrepareWithUnnamedParams() { /** * @depends testPrepare */ - public function testPrepareWithNamedParamsWithDataAppearingAsNamedParam() { + public function testPrepareWithNamedParamsWithDataAppearingAsNamedParam() + { Loop::run(function () { $query = "SELECT * FROM test WHERE domain=:domain OR domain=':domain'"; @@ -235,7 +247,8 @@ public function testPrepareWithNamedParamsWithDataAppearingAsNamedParam() { * @expectedException \Amp\Postgres\QueryExecutionError * @expectedExceptionMessage column "invalid" does not exist */ - public function testPrepareInvalidQuery() { + public function testPrepareInvalidQuery() + { Loop::run(function () { $query = "SELECT * FROM test WHERE invalid=\$1"; @@ -247,7 +260,8 @@ public function testPrepareInvalidQuery() { /** * @depends testPrepare */ - public function testPrepareSameQuery() { + public function testPrepareSameQuery() + { Loop::run(function () { $sql = "SELECT * FROM test WHERE domain=\$1"; @@ -282,7 +296,8 @@ public function testPrepareSameQuery() { /** * @depends testPrepareSameQuery */ - public function testSimultaneousPrepareSameQuery() { + public function testSimultaneousPrepareSameQuery() + { Loop::run(function () { $sql = "SELECT * FROM test WHERE domain=\$1"; @@ -330,7 +345,8 @@ public function testSimultaneousPrepareSameQuery() { }); } - public function testPrepareThenExecuteWithUnconsumedTupleResult() { + public function testPrepareThenExecuteWithUnconsumedTupleResult() + { Loop::run(function () { /** @var Statement $statement */ $statement = yield $this->connection->prepare("SELECT * FROM test"); @@ -355,7 +371,8 @@ public function testPrepareThenExecuteWithUnconsumedTupleResult() { }); } - public function testExecute() { + public function testExecute() + { Loop::run(function () { $data = $this->getData()[0]; @@ -377,7 +394,8 @@ public function testExecute() { /** * @depends testExecute */ - public function testExecuteWithNamedParams() { + public function testExecuteWithNamedParams() + { Loop::run(function () { $data = $this->getData()[0]; @@ -403,7 +421,8 @@ public function testExecuteWithNamedParams() { * @expectedException \Error * @expectedExceptionMessage Value for unnamed parameter at position 0 missing */ - public function testExecuteWithInvalidParams() { + public function testExecuteWithInvalidParams() + { Loop::run(function () { $result = yield $this->connection->execute("SELECT * FROM test WHERE domain=\$1"); }); @@ -414,7 +433,8 @@ public function testExecuteWithInvalidParams() { * @expectedException \Error * @expectedExceptionMessage Value for named parameter 'domain' missing */ - public function testExecuteWithInvalidNamedParams() { + public function testExecuteWithInvalidNamedParams() + { Loop::run(function () { $result = yield $this->connection->execute("SELECT * FROM test WHERE domain=:domain", ['tld' => 'com']); }); @@ -423,7 +443,8 @@ public function testExecuteWithInvalidNamedParams() { /** * @depends testQueryWithTupleResult */ - public function testSimultaneousQuery() { + public function testSimultaneousQuery() + { $callback = \Amp\coroutine(function ($value) { /** @var \Amp\Postgres\ResultSet $result */ $result = yield $this->connection->query("SELECT {$value} as value"); @@ -446,7 +467,8 @@ public function testSimultaneousQuery() { /** * @depends testSimultaneousQuery */ - public function testSimultaneousQueryWithOneFailing() { + public function testSimultaneousQueryWithOneFailing() + { $callback = \Amp\coroutine(function ($query) { /** @var \Amp\Postgres\ResultSet $result */ $result = yield $this->connection->query($query); @@ -478,7 +500,8 @@ public function testSimultaneousQueryWithOneFailing() { $this->fail(\sprintf("Test did not throw an instance of %s", QueryError::class)); } - public function testSimultaneousQueryAndPrepare() { + public function testSimultaneousQueryAndPrepare() + { $promises = []; $promises[] = new Coroutine((function () { /** @var \Amp\Postgres\ResultSet $result */ @@ -514,7 +537,8 @@ public function testSimultaneousQueryAndPrepare() { }); } - public function testSimultaneousPrepareAndExecute() { + public function testSimultaneousPrepareAndExecute() + { $promises[] = new Coroutine((function () { /** @var Statement $statement */ $statement = yield $this->connection->prepare("SELECT * FROM test"); @@ -549,7 +573,8 @@ public function testSimultaneousPrepareAndExecute() { }); } - public function testTransaction() { + public function testTransaction() + { Loop::run(function () { $isolation = Transaction::COMMITTED; @@ -584,7 +609,8 @@ public function testTransaction() { }); } - public function testListen() { + public function testListen() + { Loop::run(function () { $channel = "test"; /** @var \Amp\Postgres\Listener $listener */ @@ -614,7 +640,8 @@ public function testListen() { /** * @depends testListen */ - public function testNotify() { + public function testNotify() + { Loop::run(function () { $channel = "test"; /** @var \Amp\Postgres\Listener $listener */ @@ -640,10 +667,11 @@ public function testNotify() { /** * @depends testListen - * @expectedException QueryError + * @expectedException \QueryError * @expectedExceptionMessage Already listening on channel */ - public function testListenOnSameChannel() { + public function testListenOnSameChannel() + { Loop::run(function () { $channel = "test"; $listener = yield $this->connection->listen($channel); diff --git a/test/ArrayParserTest.php b/test/ArrayParserTest.php index 722e471..3850b38 100644 --- a/test/ArrayParserTest.php +++ b/test/ArrayParserTest.php @@ -5,64 +5,74 @@ use Amp\PHPUnit\TestCase; use Amp\Postgres\Internal\ArrayParser; -class ArrayParserTest extends TestCase { +class ArrayParserTest extends TestCase +{ /** @var \Amp\Postgres\Internal\ArrayParser */ private $parser; - public function setUp() { + public function setUp() + { $this->parser = new ArrayParser; } - public function testSingleDimensionalArray() { + public function testSingleDimensionalArray() + { $array = ["one", "two", "three"]; $string = '{' . \implode(',', $array) . '}'; $this->assertSame($array, $this->parser->parse($string)); } - public function testMultiDimensionalArray() { + public function testMultiDimensionalArray() + { $array = ["one", "two", ["three", "four"], "five"]; $string = '{one, two, {three, four}, five}'; $this->assertSame($array, $this->parser->parse($string)); } - public function testQuotedStrings() { + public function testQuotedStrings() + { $array = ["one", "two", ["three", "four"], "five"]; $string = '{"one", "two", {"three", "four"}, "five"}'; $this->assertSame($array, $this->parser->parse($string)); } - public function testAlternateDelimiter() { + public function testAlternateDelimiter() + { $array = ["1,2,3", "3,4,5"]; $string = '{1,2,3;3,4,5}'; $this->assertSame($array, $this->parser->parse($string, null, ';')); } - public function testEscapedQuoteDelimiter() { + public function testEscapedQuoteDelimiter() + { $array = ['va"lue1', 'value"2']; $string = '{"va\\"lue1", "value\\"2"}'; $this->assertSame($array, $this->parser->parse($string, null, ',')); } - public function testNullValue() { + public function testNullValue() + { $array = ["one", null, "three"]; $string = '{one, NULL, three}'; $this->assertSame($array, $this->parser->parse($string)); } - public function testQuotedNullValue() { + public function testQuotedNullValue() + { $array = ["one", "NULL", "three"]; $string = '{one, "NULL", three}'; $this->assertSame($array, $this->parser->parse($string)); } - public function testCast() { + public function testCast() + { $array = [1, 2, 3]; $string = '{' . \implode(',', $array) . '}'; @@ -73,7 +83,8 @@ public function testCast() { $this->assertSame($array, $this->parser->parse($string, $cast)); } - public function testCastWithNull() { + public function testCastWithNull() + { $array = [1, 2, null, 3]; $string = '{1,2,NULL,3}'; @@ -84,7 +95,8 @@ public function testCastWithNull() { $this->assertSame($array, $this->parser->parse($string, $cast)); } - public function testCastWithMultidimensionalArray() { + public function testCastWithMultidimensionalArray() + { $array = [1, 2, [3, 4], [5], 6, 7, [[8, 9], 10]]; $string = '{1,2,{3,4},{5},6,7,{{8,9},10}}'; @@ -95,7 +107,8 @@ public function testCastWithMultidimensionalArray() { $this->assertSame($array, $this->parser->parse($string, $cast)); } - public function testRandomWhitespace() { + public function testRandomWhitespace() + { $array = [1, 2, [3, 4], [5], 6, 7, [[8, 9], 10]]; $string = " {1, 2, { 3 ,\r 4 },{ 5} \n\t ,6 , 7, { {8,\t 9}, 10} } \n"; @@ -106,7 +119,8 @@ public function testRandomWhitespace() { $this->assertSame($array, $this->parser->parse($string, $cast)); } - public function testEscapedBackslashesInQuotedValue() { + public function testEscapedBackslashesInQuotedValue() + { $array = ["test\\ing", "esca\\ped\\"]; $string = '{"test\\\\ing", "esca\\\\ped\\\\"}'; @@ -117,7 +131,8 @@ public function testEscapedBackslashesInQuotedValue() { * @expectedException \Amp\Postgres\ParseException * @expectedExceptionMessage Missing opening or closing brackets */ - public function testNoClosingBracket() { + public function testNoClosingBracket() + { $string = '{"one", "two"'; $this->parser->parse($string); } @@ -126,7 +141,8 @@ public function testNoClosingBracket() { * @expectedException \Amp\Postgres\ParseException * @expectedExceptionMessage Data left in buffer after parsing */ - public function testTrailingData() { + public function testTrailingData() + { $string = '{"one", "two"} data}'; $this->parser->parse($string); } @@ -135,7 +151,8 @@ public function testTrailingData() { * @expectedException \Amp\Postgres\ParseException * @expectedExceptionMessage Could not find matching quote in quoted value */ - public function testMissingQuote() { + public function testMissingQuote() + { $string = '{"one", "two}'; $this->parser->parse($string); } @@ -144,7 +161,8 @@ public function testMissingQuote() { * @expectedException \Amp\Postgres\ParseException * @expectedExceptionMessage Invalid delimiter */ - public function testInvalidDelimiter() { + public function testInvalidDelimiter() + { $string = '{"one"; "two"}'; $this->parser->parse($string); } diff --git a/test/EncodeTest.php b/test/EncodeTest.php index 9303e2b..1c303a6 100644 --- a/test/EncodeTest.php +++ b/test/EncodeTest.php @@ -5,64 +5,74 @@ use Amp\PHPUnit\TestCase; use function Amp\Postgres\encode; -class EncodeTest extends TestCase { - public function testSingleDimensionalStringArray() { +class EncodeTest extends TestCase +{ + public function testSingleDimensionalStringArray() + { $array = ["one", "two", "three"]; $string = '{"one","two","three"}'; $this->assertSame($string, encode($array)); } - public function testMultiDimensionalStringArray() { + public function testMultiDimensionalStringArray() + { $array = ["one", "two", ["three", "four"], "five"]; $string = '{"one","two",{"three","four"},"five"}'; $this->assertSame($string, encode($array)); } - public function testQuotedStrings() { + public function testQuotedStrings() + { $array = ["one", "two", ["three", "four"], "five"]; $string = '{"one","two",{"three","four"},"five"}'; $this->assertSame($string, encode($array)); } - public function testEscapedQuoteDelimiter() { + public function testEscapedQuoteDelimiter() + { $array = ['va"lue1', 'value"2']; $string = '{"va\\"lue1","value\\"2"}'; $this->assertSame($string, encode($array)); } - public function testNullValue() { + public function testNullValue() + { $array = ["one", null, "three"]; $string = '{"one",NULL,"three"}'; $this->assertSame($string, encode($array)); } - public function testSingleDimensionalIntegerArray() { + public function testSingleDimensionalIntegerArray() + { $array = [1, 2, 3]; $string = '{' . \implode(',', $array) . '}'; $this->assertSame($string, encode($array)); } - public function testIntegerArrayWithNull() { + public function testIntegerArrayWithNull() + { $array = [1, 2, null, 3]; $string = '{1,2,NULL,3}'; $this->assertSame($string, encode($array)); } - public function testMultidimensionalIntegerArray() { + public function testMultidimensionalIntegerArray() + { $array = [1, 2, [3, 4], [5], 6, 7, [[8, 9], 10]]; $string = '{1,2,{3,4},{5},6,7,{{8,9},10}}'; $this->assertSame($string, encode($array)); } - public function testEscapedBackslashesInQuotedValue() { + public function testEscapedBackslashesInQuotedValue() + { $array = ["test\\ing", "esca\\ped\\"]; $string = '{"test\\\\ing","esca\\\\ped\\\\"}'; @@ -73,7 +83,8 @@ public function testEscapedBackslashesInQuotedValue() { * @expectedException \Error * @expectedExceptionMessage Object without a __toString() method in array */ - public function testObjectWithoutToStringMethod() { + public function testObjectWithoutToStringMethod() + { encode([new \stdClass]); } } diff --git a/test/FunctionsTest.php b/test/FunctionsTest.php index 153db1b..8b72b07 100644 --- a/test/FunctionsTest.php +++ b/test/FunctionsTest.php @@ -7,14 +7,17 @@ use PHPUnit\Framework\TestCase; use function Amp\Postgres\connect; -class FunctionsTest extends TestCase { - public function setUp() { +class FunctionsTest extends TestCase +{ + public function setUp() + { if (!\extension_loaded('pgsql') && !\extension_loaded('pq')) { $this->markTestSkipped('This test requires either ext/pgsql or pecl/pq'); } } - public function testConnect() { + public function testConnect() + { Loop::run(function () { $connection = yield connect('host=localhost user=postgres'); $this->assertInstanceOf(Connection::class, $connection); @@ -24,7 +27,8 @@ public function testConnect() { /** * @expectedException \Amp\Sql\FailureException */ - public function testConnectInvalidUser() { + public function testConnectInvalidUser() + { Loop::run(function () { $connection = yield connect('host=localhost user=invalid'); }); @@ -33,7 +37,8 @@ public function testConnectInvalidUser() { /** * @expectedException \Amp\Sql\FailureException */ - public function testConnectInvalidConnectionString() { + public function testConnectInvalidConnectionString() + { Loop::run(function () { $connection = yield connect('invalid connection string'); }); @@ -42,7 +47,8 @@ public function testConnectInvalidConnectionString() { /** * @expectedException \Amp\Sql\FailureException */ - public function testConnectInvalidHost() { + public function testConnectInvalidHost() + { Loop::run(function () { $connection = yield connect('hostaddr=invalid.host user=postgres'); }); diff --git a/test/PgSqlConnectTest.php b/test/PgSqlConnectTest.php index 7532a9d..96a09f0 100644 --- a/test/PgSqlConnectTest.php +++ b/test/PgSqlConnectTest.php @@ -10,8 +10,10 @@ /** * @requires extension pgsql */ -class PgSqlConnectTest extends AbstractConnectTest { - public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise { +class PgSqlConnectTest extends AbstractConnectTest +{ + public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise + { return PgSqlConnection::connect($connectionConfig, $token); } } diff --git a/test/PgSqlConnectionTest.php b/test/PgSqlConnectionTest.php index 70b4b95..eaf90a4 100644 --- a/test/PgSqlConnectionTest.php +++ b/test/PgSqlConnectionTest.php @@ -8,11 +8,13 @@ /** * @requires extension pgsql */ -class PgSqlConnectionTest extends AbstractConnectionTest { +class PgSqlConnectionTest extends AbstractConnectionTest +{ /** @var resource PostgreSQL connection resource. */ protected $handle; - public function createLink(string $connectionString): Link { + public function createLink(string $connectionString): Link + { $this->handle = \pg_connect($connectionString); $socket = \pg_socket($this->handle); @@ -35,7 +37,8 @@ public function createLink(string $connectionString): Link { return new PgSqlConnection($this->handle, $socket); } - public function tearDown() { + public function tearDown() + { \pg_get_result($this->handle); // Consume any leftover results from test. \pg_query($this->handle, "ROLLBACK"); \pg_query($this->handle, "DROP TABLE test"); diff --git a/test/PgSqlPoolTest.php b/test/PgSqlPoolTest.php index 6393d50..e1edc8e 100644 --- a/test/PgSqlPoolTest.php +++ b/test/PgSqlPoolTest.php @@ -2,23 +2,24 @@ namespace Amp\Postgres\Test; -use Amp\Sql\Connector; use Amp\Postgres\Link; -use Amp\Postgres\PgSqlConnection; use Amp\Postgres\Pool; use Amp\Promise; +use Amp\Sql\Connector; use Amp\Success; /** * @requires extension pgsql */ -class PgSqlPoolTest extends AbstractLinkTest { +class PgSqlPoolTest extends AbstractLinkTest +{ const POOL_SIZE = 3; /** @var resource[] PostgreSQL connection resources. */ protected $handles = []; - public function createLink(string $connectionString): Link { + public function createLink(string $connectionString): Link + { for ($i = 0; $i < self::POOL_SIZE; ++$i) { $this->handles[] = \pg_connect($connectionString, \PGSQL_CONNECT_FORCE_NEW); } @@ -57,7 +58,8 @@ public function createLink(string $connectionString): Link { return $pool; } - public function tearDown() { + public function tearDown() + { foreach ($this->handles as $handle) { \pg_get_result($handle); // Consume any leftover results from test. } diff --git a/test/PoolTest.php b/test/PoolTest.php index e50f719..32e826d 100644 --- a/test/PoolTest.php +++ b/test/PoolTest.php @@ -7,16 +7,19 @@ use Amp\Postgres\Pool; use PHPUnit\Framework\TestCase; -class PoolTest extends TestCase { +class PoolTest extends TestCase +{ /** * @expectedException \Error * @expectedExceptionMessage Pool must contain at least one connection */ - public function testInvalidMaxConnections() { + public function testInvalidMaxConnections() + { $pool = new Pool('connection string', 0); } - public function testIdleConnectionsRemovedAfterTimeout() { + public function testIdleConnectionsRemovedAfterTimeout() + { Loop::run(function () { $pool = new Pool('host=localhost user=postgres'); $pool->setIdleTimeout(2); diff --git a/test/PooledStatementTest.php b/test/PooledStatementTest.php index bb02c84..d51d737 100644 --- a/test/PooledStatementTest.php +++ b/test/PooledStatementTest.php @@ -11,8 +11,10 @@ use Amp\Sql\Statement; use Amp\Success; -class PooledStatementTest extends TestCase { - public function testActiveStatementsRemainAfterTimeout() { +class PooledStatementTest extends TestCase +{ + public function testActiveStatementsRemainAfterTimeout() + { Loop::run(function () { $pool = new Pool('host=localhost user=postgres'); @@ -38,7 +40,8 @@ public function testActiveStatementsRemainAfterTimeout() { }); } - public function testIdleStatementsRemovedAfterTimeout() { + public function testIdleStatementsRemovedAfterTimeout() + { Loop::run(function () { $pool = new Pool('host=localhost user=postgres'); diff --git a/test/PqConnectTest.php b/test/PqConnectTest.php index 3d70f23..5349284 100644 --- a/test/PqConnectTest.php +++ b/test/PqConnectTest.php @@ -10,8 +10,10 @@ /** * @requires extension pq */ -class PqConnectTest extends AbstractConnectTest { - public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise { +class PqConnectTest extends AbstractConnectTest +{ + public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise + { return PqConnection::connect($connectionConfig, $token); } } diff --git a/test/PqConnectionTest.php b/test/PqConnectionTest.php index b86a616..8c5273c 100644 --- a/test/PqConnectionTest.php +++ b/test/PqConnectionTest.php @@ -8,11 +8,13 @@ /** * @requires extension pq */ -class PqConnectionTest extends AbstractConnectionTest { +class PqConnectionTest extends AbstractConnectionTest +{ /** @var resource PostgreSQL connection resource. */ protected $handle; - public function createLink(string $connectionString): Link { + public function createLink(string $connectionString): Link + { $this->handle = new \pq\Connection($connectionString); $this->handle->nonblocking = true; $this->handle->unbuffered = true; @@ -36,7 +38,8 @@ public function createLink(string $connectionString): Link { return new PqConnection($this->handle); } - public function tearDown() { + public function tearDown() + { $this->handle->exec("ROLLBACK"); $this->handle->exec("DROP TABLE test"); } diff --git a/test/PqPoolTest.php b/test/PqPoolTest.php index 7967113..1a3f19c 100644 --- a/test/PqPoolTest.php +++ b/test/PqPoolTest.php @@ -12,13 +12,15 @@ /** * @requires extension pq */ -class PqPoolTest extends AbstractLinkTest { +class PqPoolTest extends AbstractLinkTest +{ const POOL_SIZE = 3; /** @var \pq\Connection[] */ protected $handles = []; - public function createLink(string $connectionString): Link { + public function createLink(string $connectionString): Link + { for ($i = 0; $i < self::POOL_SIZE; ++$i) { $this->handles[] = $handle = new \pq\Connection($connectionString); $handle->nonblocking = true; @@ -60,7 +62,8 @@ public function createLink(string $connectionString): Link { return $pool; } - public function tearDown() { + public function tearDown() + { $this->handles[0]->exec("ROLLBACK"); $this->handles[0]->exec("DROP TABLE test"); } From d8f1ed0fdc1250899cf0a08f425f83be43e26449 Mon Sep 17 00:00:00 2001 From: prolic Date: Fri, 29 Jun 2018 18:27:52 +0800 Subject: [PATCH 11/25] update php-cs-fixer --- .php_cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.php_cs b/.php_cs index 06572ee..233c4e9 100644 --- a/.php_cs +++ b/.php_cs @@ -1,6 +1,6 @@ getFinder()->in(__DIR__); $cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__; From 8618d67a91fc2e90570df8faad5dbe4de0129262 Mon Sep 17 00:00:00 2001 From: prolic Date: Fri, 29 Jun 2018 22:00:24 +0800 Subject: [PATCH 12/25] update pool --- src/Pool.php | 13 ++++++------- src/Pool2.php | 46 ---------------------------------------------- 2 files changed, 6 insertions(+), 53 deletions(-) delete mode 100644 src/Pool2.php diff --git a/src/Pool.php b/src/Pool.php index fe59fe1..26ddb19 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -10,17 +10,16 @@ use Amp\Sql\Connector; use Amp\Sql\FailureException; use Amp\Sql\Operation; +use Amp\Sql\Pool as SqlPool; use Amp\Sql\Statement; +use Amp\Sql\Transaction; use function Amp\call; use function Amp\coroutine; -final class Pool implements Pool +final class Pool implements SqlPool { use CallableMaker; - const DEFAULT_MAX_CONNECTIONS = 100; - const DEFAULT_IDLE_TIMEOUT = 60; - /** @var Connector */ private $connector; @@ -58,7 +57,7 @@ final class Pool implements Pool private $resetConnections = true; /** @var int */ - private $idleTimeout = self::DEFAULT_IDLE_TIMEOUT; + private $idleTimeout = SqlPool::DEFAULT_IDLE_TIMEOUT; /** @var string */ private $timeoutWatcher; @@ -71,7 +70,7 @@ final class Pool implements Pool public function __construct( string $connectionString, - int $maxConnections = self::DEFAULT_MAX_CONNECTIONS, + int $maxConnections = SqlPool::DEFAULT_MAX_CONNECTIONS, Connector $connector = null ) { $this->connector = $connector ?? connector(); @@ -471,7 +470,7 @@ public function listen(string $channel): Promise /** * {@inheritdoc} */ - public function transaction(int $isolation = Transaction::COMMITTED): Promise + public function transaction(int $isolation = Transaction::ISOLATION_COMMITTED): Promise { return call(function () use ($isolation) { /** @var Connection $connection */ diff --git a/src/Pool2.php b/src/Pool2.php deleted file mode 100644 index e50a5ed..0000000 --- a/src/Pool2.php +++ /dev/null @@ -1,46 +0,0 @@ - - */ - public function extractConnection(): Promise; - - /** - * @return int Total number of active connections in the pool. - */ - public function getConnectionCount(): int; - - /** - * @return int Total number of idle connections in the pool. - */ - public function getIdleConnectionCount(): int; - - /** - * @return int Maximum number of connections this pool will create. - */ - public function getMaxConnections(): int; - - /** - * @param bool $reset True to automatically reset a connection in the pool before using it for an operation. - */ - public function resetConnections(bool $reset); - - /** - * @return int Number of seconds a connection may remain idle before it is automatically closed. - */ - public function getIdleTimeout(): int; - - /** - * @param int $timeout Number of seconds a connection may remain idle before it is automatically closed. - */ - public function setIdleTimeout(int $timeout); -} From d44cfa814289aaa4cc76702e21ee1c8220e4214d Mon Sep 17 00:00:00 2001 From: prolic Date: Sat, 30 Jun 2018 01:27:03 +0800 Subject: [PATCH 13/25] update travis yml, rename pool => default pool --- .travis.yml | 6 ++++++ src/{Pool.php => DefaultPool.php} | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) rename src/{Pool.php => DefaultPool.php} (99%) diff --git a/.travis.yml b/.travis.yml index 8ab7c33..6661027 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,12 @@ matrix: - php: nightly fast_finish: true +cache: + directories: + - $HOME/.composer/cache + - $HOME/.php-cs-fixer + - $HOME/.local + env: - AMP_DEBUG=true diff --git a/src/Pool.php b/src/DefaultPool.php similarity index 99% rename from src/Pool.php rename to src/DefaultPool.php index 26ddb19..4146e0b 100644 --- a/src/Pool.php +++ b/src/DefaultPool.php @@ -16,7 +16,7 @@ use function Amp\call; use function Amp\coroutine; -final class Pool implements SqlPool +final class DefaultPool implements SqlPool { use CallableMaker; From 1d1e1056a00dd341bc492916103f8d4952427c71 Mon Sep 17 00:00:00 2001 From: prolic Date: Sat, 30 Jun 2018 16:58:08 +0800 Subject: [PATCH 14/25] cleanup after review --- src/DefaultPool.php | 81 ----------------- src/Executor.php | 49 +--------- src/Internal/PooledStatement.php | 148 ------------------------------- src/Link.php | 2 +- src/Pool.php | 76 +++++++++++++++- src/functions.php | 2 +- test/DefaultPoolTest.php | 6 +- test/PgSqlPoolTest.php | 4 +- test/PooledStatementTest.php | 8 +- test/PqPoolTest.php | 4 +- 10 files changed, 88 insertions(+), 292 deletions(-) delete mode 100644 src/DefaultPool.php delete mode 100644 src/Internal/PooledStatement.php diff --git a/src/DefaultPool.php b/src/DefaultPool.php deleted file mode 100644 index 735d7d8..0000000 --- a/src/DefaultPool.php +++ /dev/null @@ -1,81 +0,0 @@ -pop(); - - try { - $result = yield $connection->notify($channel, $payload); - } finally { - $this->push($connection); - } - - return $result; - }); - } - - /** - * {@inheritdoc} - */ - public function listen(string $channel): Promise - { - return call(function () use ($channel) { - ++$this->listenerCount; - - if ($this->listeningConnection === null) { - $this->listeningConnection = new Coroutine($this->pop()); - } - - if ($this->listeningConnection instanceof Promise) { - $this->listeningConnection = yield $this->listeningConnection; - } - - try { - /** @var Listener $listener */ - $listener = yield $this->listeningConnection->listen($channel); - } catch (\Throwable $exception) { - if (--$this->listenerCount === 0) { - $connection = $this->listeningConnection; - $this->listeningConnection = null; - $this->push($connection); - } - throw $exception; - } - - $listener->onDestruct(function () { - if (--$this->listenerCount === 0) { - $connection = $this->listeningConnection; - $this->listeningConnection = null; - $this->push($connection); - } - }); - - return $listener; - }); - } -} diff --git a/src/Executor.php b/src/Executor.php index 50ff4c9..b11bd76 100644 --- a/src/Executor.php +++ b/src/Executor.php @@ -3,45 +3,12 @@ namespace Amp\Postgres; use Amp\Promise; +use Amp\Sql\Executor as SqlExecutor; -interface Executor +interface Executor extends SqlExecutor { const STATEMENT_NAME_PREFIX = "amp_"; - /** - * @param string $sql - * - * @return Promise<\Amp\Sql\CommandResult> - * - * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. - * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). - */ - public function query(string $sql): Promise; - - /** - * @param string $sql - * @param mixed[] $params - * - * @return Promise<\Amp\Sql\CommandResult> - * - * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. - * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). - */ - public function execute(string $sql, array $params = []): Promise; - - /** - * @param string $sql - * - * @return Promise<@return PromiseStatement> - * - * @throws \Amp\Sql\FailureException If the operation fails due to unexpected condition. - * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. - * @throws \Amp\Sql\QueryError If the operation fails due to an error in the query (such as a syntax error). - */ - public function prepare(string $sql): Promise; - /** * @param string $channel Channel name. * @param string $payload Notification payload. @@ -52,16 +19,4 @@ public function prepare(string $sql): Promise; * @throws \Amp\Sql\ConnectionException If the connection to the database is lost. */ public function notify(string $channel, string $payload = ""): Promise; - - /** - * Indicates if the connection to the database is still alive. - * - * @return bool - */ - public function isAlive(): bool; - - /** - * Closes the executor. No further queries may be performed. - */ - public function close(); } diff --git a/src/Internal/PooledStatement.php b/src/Internal/PooledStatement.php deleted file mode 100644 index 67afe0a..0000000 --- a/src/Internal/PooledStatement.php +++ /dev/null @@ -1,148 +0,0 @@ -lastUsedAt = \time(); - $this->statements = $statements = new \SplQueue; - $this->pool = $pool; - $this->prepare = $prepare; - $this->sql = $statement->getQuery(); - - $this->statements->push($statement); - - $this->timeoutWatcher = Loop::repeat(1000, static function () use ($pool, $statements) { - $now = \time(); - $idleTimeout = ((int) ($pool->getIdleTimeout() / 10)) ?: 1; - - while (!$statements->isEmpty()) { - /** @var Statement $statement */ - $statement = $statements->bottom(); - - if ($statement->lastUsedAt() + $idleTimeout > $now) { - return; - } - - $statements->shift(); - } - }); - - Loop::unreference($this->timeoutWatcher); - } - - public function __destruct() - { - Loop::cancel($this->timeoutWatcher); - } - - /** - * {@inheritdoc} - * - * Unlike regular statements, as long as the pool is open this statement will not die. - */ - public function execute(array $params = []): Promise - { - $this->lastUsedAt = \time(); - - return call(function () use ($params) { - if (!$this->statements->isEmpty()) { - do { - /** @var Statement $statement */ - $statement = $this->statements->shift(); - } while (!$statement->isAlive() && !$this->statements->isEmpty()); - } else { - $statement = yield ($this->prepare)($this->sql); - } - - try { - $result = yield $statement->execute($params); - } catch (\Throwable $exception) { - $this->push($statement); - throw $exception; - } - - if ($result instanceof Operation) { - $result->onDestruct(function () use ($statement) { - $this->push($statement); - }); - } else { - $this->push($statement); - } - - return $result; - }); - } - - /** - * Only retains statements if less than 10% of the pool is consumed by this statement and the pool has - * available connections. - * - * @param Statement $statement - */ - private function push(Statement $statement) - { - $maxConnections = $this->pool->getMaxConnections(); - - if ($this->statements->count() > ($maxConnections / 10)) { - return; - } - - if ($maxConnections === $this->pool->getConnectionCount() && $this->pool->getIdleConnectionCount() === 0) { - return; - } - - $this->statements->push($statement); - } - - - /** {@inheritdoc} */ - public function isAlive(): bool - { - return $this->pool->isAlive(); - } - - /** {@inheritdoc} */ - public function getQuery(): string - { - return $this->sql; - } - - /** {@inheritdoc} */ - public function lastUsedAt(): int - { - return $this->lastUsedAt; - } -} diff --git a/src/Link.php b/src/Link.php index 77686e9..98d4df2 100644 --- a/src/Link.php +++ b/src/Link.php @@ -5,7 +5,7 @@ use Amp\Promise; use Amp\Sql\Link as SqlLink; -interface Link extends SqlLink +interface Link extends Executor, SqlLink { /** * @param string $channel Channel name. diff --git a/src/Pool.php b/src/Pool.php index c3c3d63..ae721a0 100644 --- a/src/Pool.php +++ b/src/Pool.php @@ -2,10 +2,80 @@ namespace Amp\Postgres; +use Amp\Coroutine; use Amp\Promise; -use Amp\Sql\Pool as SqlPool; +use Amp\Sql\AbstractPool; +use Amp\Sql\Connector; +use function Amp\call; -interface Pool extends Link, SqlPool +final class Pool extends AbstractPool implements Link { - public function notify(string $channel, string $payload = ""): Promise; + /** @var Connection|Promise|null Connection used for notification listening. */ + private $listeningConnection; + /** @var int Number of listeners on listening connection. */ + private $listenerCount = 0; + + protected function createDefaultConnector(): Connector + { + return connector(); + } + + /** + * {@inheritdoc} + */ + public function notify(string $channel, string $payload = ""): Promise + { + return call(function () use ($channel, $payload) { + /** @var Connection $connection */ + $connection = yield from $this->pop(); + + try { + $result = yield $connection->notify($channel, $payload); + } finally { + $this->push($connection); + } + + return $result; + }); + } + + /** + * {@inheritdoc} + */ + public function listen(string $channel): Promise + { + return call(function () use ($channel) { + ++$this->listenerCount; + + if ($this->listeningConnection === null) { + $this->listeningConnection = new Coroutine($this->pop()); + } + + if ($this->listeningConnection instanceof Promise) { + $this->listeningConnection = yield $this->listeningConnection; + } + + try { + /** @var Listener $listener */ + $listener = yield $this->listeningConnection->listen($channel); + } catch (\Throwable $exception) { + if (--$this->listenerCount === 0) { + $connection = $this->listeningConnection; + $this->listeningConnection = null; + $this->push($connection); + } + throw $exception; + } + + $listener->onDestruct(function () { + if (--$this->listenerCount === 0) { + $connection = $this->listeningConnection; + $this->listeningConnection = null; + $this->push($connection); + } + }); + + return $listener; + }); + } } diff --git a/src/functions.php b/src/functions.php index 8791550..4481111 100644 --- a/src/functions.php +++ b/src/functions.php @@ -53,7 +53,7 @@ function connect(SqlConnectionConfig $config): Promise */ function pool(string $connectionString, int $maxConnections = SqlPool::DEFAULT_MAX_CONNECTIONS): Pool { - return new DefaultPool(new ConnectionConfig($connectionString), $maxConnections, connector()); + return new Pool(new ConnectionConfig($connectionString), $maxConnections, connector()); } /** diff --git a/test/DefaultPoolTest.php b/test/DefaultPoolTest.php index d2576bc..bb9bcab 100644 --- a/test/DefaultPoolTest.php +++ b/test/DefaultPoolTest.php @@ -4,7 +4,7 @@ use Amp\Delayed; use Amp\Loop; -use Amp\Postgres\DefaultPool; +use Amp\Postgres\Pool; use Amp\Postgres\ConnectionConfig; use PHPUnit\Framework\TestCase; @@ -16,13 +16,13 @@ class DefaultPoolTest extends TestCase */ public function testInvalidMaxConnections() { - new DefaultPool(new ConnectionConfig('connection string'), 0); + new Pool(new ConnectionConfig('connection string'), 0); } public function testIdleConnectionsRemovedAfterTimeout() { Loop::run(function () { - $pool = new DefaultPool(new ConnectionConfig('host=localhost user=postgres')); + $pool = new Pool(new ConnectionConfig('host=localhost user=postgres')); $pool->setIdleTimeout(2); $count = 3; diff --git a/test/PgSqlPoolTest.php b/test/PgSqlPoolTest.php index 4534aaa..4e549e1 100644 --- a/test/PgSqlPoolTest.php +++ b/test/PgSqlPoolTest.php @@ -4,7 +4,7 @@ use Amp\Postgres\ConnectionConfig; use Amp\Postgres\Link; -use Amp\Postgres\DefaultPool; +use Amp\Postgres\Pool; use Amp\Promise; use Amp\Sql\Connector; use Amp\Success; @@ -36,7 +36,7 @@ public function createLink(string $connectionString): Link return new Success(); })); - $pool = new DefaultPool(new ConnectionConfig('connection string'), \count($this->handles), $connector); + $pool = new Pool(new ConnectionConfig('connection string'), \count($this->handles), $connector); $handle = \reset($this->handles); diff --git a/test/PooledStatementTest.php b/test/PooledStatementTest.php index f745da0..0a81ceb 100644 --- a/test/PooledStatementTest.php +++ b/test/PooledStatementTest.php @@ -6,9 +6,9 @@ use Amp\Loop; use Amp\PHPUnit\TestCase; use Amp\Postgres\ConnectionConfig; -use Amp\Postgres\Internal\PooledStatement; -use Amp\Postgres\DefaultPool; +use Amp\Postgres\Pool; use Amp\Postgres\ResultSet; +use Amp\Sql\PooledStatement; use Amp\Sql\Statement; use Amp\Success; @@ -17,7 +17,7 @@ class PooledStatementTest extends TestCase public function testActiveStatementsRemainAfterTimeout() { Loop::run(function () { - $pool = new DefaultPool(new ConnectionConfig('host=localhost user=postgres')); + $pool = new Pool(new ConnectionConfig('host=localhost user=postgres')); $statement = $this->createMock(Statement::class); $statement->method('getQuery') @@ -44,7 +44,7 @@ public function testActiveStatementsRemainAfterTimeout() public function testIdleStatementsRemovedAfterTimeout() { Loop::run(function () { - $pool = new DefaultPool(new ConnectionConfig('host=localhost user=postgres')); + $pool = new Pool(new ConnectionConfig('host=localhost user=postgres')); $statement = $this->createMock(Statement::class); $statement->method('getQuery') diff --git a/test/PqPoolTest.php b/test/PqPoolTest.php index 97993d1..ffd853b 100644 --- a/test/PqPoolTest.php +++ b/test/PqPoolTest.php @@ -4,7 +4,7 @@ use Amp\Postgres\ConnectionConfig; use Amp\Postgres\Link; -use Amp\Postgres\DefaultPool; +use Amp\Postgres\Pool; use Amp\Postgres\PqConnection; use Amp\Promise; use Amp\Sql\Connector; @@ -40,7 +40,7 @@ public function createLink(string $connectionString): Link return new Success(new PqConnection($handle)); })); - $pool = new DefaultPool(new ConnectionConfig('connection string'), \count($this->handles), $connector); + $pool = new Pool(new ConnectionConfig('connection string'), \count($this->handles), $connector); $handle = \reset($this->handles); From 4e6e4e4da6b7d6ef42364944f587cc1416511d15 Mon Sep 17 00:00:00 2001 From: prolic Date: Sat, 30 Jun 2018 23:56:28 +0800 Subject: [PATCH 15/25] bugfixes --- src/PgSqlConnection.php | 2 +- src/PqConnection.php | 2 +- test/AbstractConnectTest.php | 13 +++++++------ test/AbstractLinkTest.php | 22 ++++++++++++---------- test/FunctionsTest.php | 9 +++++---- 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/PgSqlConnection.php b/src/PgSqlConnection.php index c92e1b2..b45cfae 100644 --- a/src/PgSqlConnection.php +++ b/src/PgSqlConnection.php @@ -12,7 +12,7 @@ use Amp\Sql\ConnectionConfig; use Amp\Sql\ConnectionException; -final class PgSqlConnection extends Connection +final class PgSqlConnection extends Connection implements Link { use CallableMaker; diff --git a/src/PqConnection.php b/src/PqConnection.php index 9415ae5..1ebae9f 100644 --- a/src/PqConnection.php +++ b/src/PqConnection.php @@ -12,7 +12,7 @@ use Amp\Sql\ConnectionException; use pq; -final class PqConnection extends Connection +final class PqConnection extends Connection implements Link { /** * @param ConnectionConfig $connectionConfig diff --git a/test/AbstractConnectTest.php b/test/AbstractConnectTest.php index 7753612..4a0a612 100644 --- a/test/AbstractConnectTest.php +++ b/test/AbstractConnectTest.php @@ -6,6 +6,7 @@ use Amp\CancellationTokenSource; use Amp\Loop; use Amp\Postgres\Connection; +use Amp\Postgres\ConnectionConfig as PostgresConnectionConfig; use Amp\Promise; use Amp\Sql\ConnectionConfig; use Amp\TimeoutCancellationToken; @@ -25,7 +26,7 @@ public function testConnect() { Loop::run(function () { $connection = yield $this->connect( - new \Amp\Postgres\ConnectionConfig(new \Amp\Postgres\ConnectionConfig('host=localhost user=postgres')), + new PostgresConnectionConfig('host=localhost user=postgres'), new TimeoutCancellationToken(100) ); $this->assertInstanceOf(Connection::class, $connection); @@ -42,7 +43,7 @@ public function testConnectCancellationBeforeConnect() $source = new CancellationTokenSource; $token = $source->getToken(); $source->cancel(); - $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('host=localhost user=postgres'), $token); + $connection = yield $this->connect(new PostgresConnectionConfig('host=localhost user=postgres'), $token); }); } @@ -54,7 +55,7 @@ public function testConnectCancellationAfterConnect() Loop::run(function () { $source = new CancellationTokenSource; $token = $source->getToken(); - $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('host=localhost user=postgres'), $token); + $connection = yield $this->connect(new PostgresConnectionConfig('host=localhost user=postgres'), $token); $this->assertInstanceOf(Connection::class, $connection); $source->cancel(); }); @@ -67,7 +68,7 @@ public function testConnectCancellationAfterConnect() public function testConnectInvalidUser() { Loop::run(function () { - $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('host=localhost user=invalid'), new TimeoutCancellationToken(100)); + $connection = yield $this->connect(new PostgresConnectionConfig('host=localhost user=invalid'), new TimeoutCancellationToken(100)); }); } @@ -78,7 +79,7 @@ public function testConnectInvalidUser() public function testConnectInvalidConnectionString() { Loop::run(function () { - $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('invalid connection string'), new TimeoutCancellationToken(100)); + $connection = yield $this->connect(new PostgresConnectionConfig('invalid connection string'), new TimeoutCancellationToken(100)); }); } @@ -89,7 +90,7 @@ public function testConnectInvalidConnectionString() public function testConnectInvalidHost() { Loop::run(function () { - $connection = yield $this->connect(new \Amp\Postgres\ConnectionConfig('hostaddr=invalid.host user=postgres'), new TimeoutCancellationToken(100)); + $connection = yield $this->connect(new PostgresConnectionConfig('hostaddr=invalid.host user=postgres'), new TimeoutCancellationToken(100)); }); } } diff --git a/test/AbstractLinkTest.php b/test/AbstractLinkTest.php index b32ecf0..67510a7 100644 --- a/test/AbstractLinkTest.php +++ b/test/AbstractLinkTest.php @@ -13,7 +13,9 @@ use Amp\Postgres\TransactionError; use Amp\Sql\CommandResult; use Amp\Sql\QueryError; +use Amp\Sql\ResultSet as SqlResultSet; use Amp\Sql\Statement; +use Amp\Sql\Transaction as SqlTransaction; use PHPUnit\Framework\TestCase; abstract class AbstractLinkTest extends TestCase @@ -81,7 +83,7 @@ public function testQueryWithUnconsumedTupleResult() $data = $this->getData(); - for ($i = 0; yield $result->advance(ResultSet::FETCH_OBJECT); ++$i) { + for ($i = 0; yield $result->advance(SqlResultSet::FETCH_OBJECT); ++$i) { $row = $result->getCurrent(); $this->assertSame($data[$i][0], $row->domain); $this->assertSame($data[$i][1], $row->tld); @@ -101,7 +103,7 @@ public function testQueryWithCommandResult() } /** - * @expectedException \QueryError + * @expectedException QueryError */ public function testQueryWithEmptyQuery() { @@ -144,7 +146,7 @@ public function testPrepare() $this->assertSame(2, $result->numFields()); - while (yield $result->advance(ResultSet::FETCH_ARRAY)) { + while (yield $result->advance(SqlResultSet::FETCH_ARRAY)) { $row = $result->getCurrent(); $this->assertSame($data[0], $row[0]); $this->assertSame($data[1], $row[1]); @@ -174,7 +176,7 @@ public function testPrepareWithNamedParams() $this->assertSame(2, $result->numFields()); - while (yield $result->advance(ResultSet::FETCH_ARRAY)) { + while (yield $result->advance(SqlResultSet::FETCH_ARRAY)) { $row = $result->getCurrent(); $this->assertSame($data[0], $row[0]); $this->assertSame($data[1], $row[1]); @@ -204,7 +206,7 @@ public function testPrepareWithUnnamedParams() $this->assertSame(2, $result->numFields()); - while (yield $result->advance(ResultSet::FETCH_ARRAY)) { + while (yield $result->advance(SqlResultSet::FETCH_ARRAY)) { $row = $result->getCurrent(); $this->assertSame($data[0], $row[0]); $this->assertSame($data[1], $row[1]); @@ -234,7 +236,7 @@ public function testPrepareWithNamedParamsWithDataAppearingAsNamedParam() $this->assertSame(2, $result->numFields()); - while (yield $result->advance(ResultSet::FETCH_ARRAY)) { + while (yield $result->advance(SqlResultSet::FETCH_ARRAY)) { $row = $result->getCurrent(); $this->assertSame($data[0], $row[0]); $this->assertSame($data[1], $row[1]); @@ -363,7 +365,7 @@ public function testPrepareThenExecuteWithUnconsumedTupleResult() $data = $this->getData(); - for ($i = 0; yield $result->advance(ResultSet::FETCH_OBJECT); ++$i) { + for ($i = 0; yield $result->advance(SqlResultSet::FETCH_OBJECT); ++$i) { $row = $result->getCurrent(); $this->assertSame($data[$i][0], $row->domain); $this->assertSame($data[$i][1], $row->tld); @@ -576,7 +578,7 @@ public function testSimultaneousPrepareAndExecute() public function testTransaction() { Loop::run(function () { - $isolation = Transaction::COMMITTED; + $isolation = SqlTransaction::ISOLATION_COMMITTED; /** @var \Amp\Postgres\Transaction $transaction */ $transaction = yield $this->connection->transaction($isolation); @@ -589,7 +591,7 @@ public function testTransaction() $this->assertTrue($transaction->isActive()); $this->assertSame($isolation, $transaction->getIsolationLevel()); - yield $transaction->savepoint('test'); + yield $transaction->createSavepoint('test'); $result = yield $transaction->execute("SELECT * FROM test WHERE domain=\$1 FOR UPDATE", [$data[0]]); @@ -667,7 +669,7 @@ public function testNotify() /** * @depends testListen - * @expectedException \QueryError + * @expectedException QueryError * @expectedExceptionMessage Already listening on channel */ public function testListenOnSameChannel() diff --git a/test/FunctionsTest.php b/test/FunctionsTest.php index 8b72b07..7a91dfa 100644 --- a/test/FunctionsTest.php +++ b/test/FunctionsTest.php @@ -4,6 +4,7 @@ use Amp\Loop; use Amp\Postgres\Connection; +use Amp\Postgres\ConnectionConfig; use PHPUnit\Framework\TestCase; use function Amp\Postgres\connect; @@ -19,7 +20,7 @@ public function setUp() public function testConnect() { Loop::run(function () { - $connection = yield connect('host=localhost user=postgres'); + $connection = yield connect(new ConnectionConfig('host=localhost user=postgres')); $this->assertInstanceOf(Connection::class, $connection); }); } @@ -30,7 +31,7 @@ public function testConnect() public function testConnectInvalidUser() { Loop::run(function () { - $connection = yield connect('host=localhost user=invalid'); + $connection = yield connect(new ConnectionConfig('host=localhost user=invalid')); }); } @@ -40,7 +41,7 @@ public function testConnectInvalidUser() public function testConnectInvalidConnectionString() { Loop::run(function () { - $connection = yield connect('invalid connection string'); + $connection = yield connect(new ConnectionConfig('invalid connection string')); }); } @@ -50,7 +51,7 @@ public function testConnectInvalidConnectionString() public function testConnectInvalidHost() { Loop::run(function () { - $connection = yield connect('hostaddr=invalid.host user=postgres'); + $connection = yield connect(new ConnectionConfig('hostaddr=invalid.host user=postgres')); }); } } From a9c6ad563aedcf76f6816d4f4b2837d24951e476 Mon Sep 17 00:00:00 2001 From: prolic Date: Sun, 1 Jul 2018 00:05:10 +0800 Subject: [PATCH 16/25] fix functions --- src/functions.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/functions.php b/src/functions.php index 4481111..41c8c31 100644 --- a/src/functions.php +++ b/src/functions.php @@ -28,7 +28,7 @@ function connector(Connector $connector = null): Connector /** * Create a connection using the global Connector instance. * - * @param string $connectionString + * @param SqlConnectionConfig $config * * @return Promise * @@ -46,14 +46,14 @@ function connect(SqlConnectionConfig $config): Promise /** * Create a pool using the global Connector instance. * - * @param string $connectionString + * @param SqlConnectionConfig $config * @param int $maxConnections * * @return Pool */ -function pool(string $connectionString, int $maxConnections = SqlPool::DEFAULT_MAX_CONNECTIONS): Pool +function pool(SqlConnectionConfig $config, int $maxConnections = SqlPool::DEFAULT_MAX_CONNECTIONS): Pool { - return new Pool(new ConnectionConfig($connectionString), $maxConnections, connector()); + return new Pool($config, $maxConnections, connector()); } /** From 0de3881f2c052a84a720fb5a440bd2a88760e667 Mon Sep 17 00:00:00 2001 From: prolic Date: Sun, 1 Jul 2018 00:10:57 +0800 Subject: [PATCH 17/25] update examples --- examples/basic.php | 2 +- examples/listen.php | 2 +- examples/multi-listen.php | 2 +- examples/transaction.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/basic.php b/examples/basic.php index dd7d465..d342e74 100644 --- a/examples/basic.php +++ b/examples/basic.php @@ -7,7 +7,7 @@ Amp\Loop::run(function () { /** @var \Amp\Postgres\Connection $connection */ - $connection = yield Postgres\connect('host=localhost user=postgres'); + $connection = yield Postgres\connect(new Postgres\ConnectionConfig('host=localhost user=postgres')); /** @var \Amp\Postgres\ResultSet $result */ $result = yield $connection->query('SHOW ALL'); diff --git a/examples/listen.php b/examples/listen.php index e8dd793..56ef6f6 100644 --- a/examples/listen.php +++ b/examples/listen.php @@ -7,7 +7,7 @@ use Amp\Postgres; Loop::run(function () { - $pool = Postgres\pool('host=localhost user=postgres'); + $pool = Postgres\pool(new Postgres\ConnectionConfig('host=localhost user=postgres')); $channel = "test"; diff --git a/examples/multi-listen.php b/examples/multi-listen.php index 957f9c1..5851987 100644 --- a/examples/multi-listen.php +++ b/examples/multi-listen.php @@ -8,7 +8,7 @@ use Amp\Postgres; Loop::run(function () { - $pool = Postgres\pool('host=localhost user=postgres'); + $pool = Postgres\pool(new Postgres\ConnectionConfig('host=localhost user=postgres')); $channel1 = "test1"; $channel2 = "test2"; diff --git a/examples/transaction.php b/examples/transaction.php index 6e3b64f..129bd47 100644 --- a/examples/transaction.php +++ b/examples/transaction.php @@ -6,7 +6,7 @@ use Amp\Postgres; Amp\Loop::run(function () { - $pool = Postgres\pool('host=localhost user=postgres'); + $pool = Postgres\pool(new Postgres\ConnectionConfig('host=localhost user=postgres')); yield $pool->query('DROP TABLE IF EXISTS test'); From 0d7f338d739ed7a821d595bef4ac8a9d082ecc0c Mon Sep 17 00:00:00 2001 From: prolic Date: Sun, 1 Jul 2018 00:16:51 +0800 Subject: [PATCH 18/25] fix transaction class --- src/Transaction.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Transaction.php b/src/Transaction.php index e274320..3cd704d 100644 --- a/src/Transaction.php +++ b/src/Transaction.php @@ -23,13 +23,13 @@ final class Transaction implements Handle, SqlTransaction * * @throws \Error If the isolation level is invalid. */ - public function __construct(Handle $handle, int $isolation = self::ISOLATION_COMMITTED) + public function __construct(Handle $handle, int $isolation = SqlTransaction::ISOLATION_COMMITTED) { switch ($isolation) { - case self::ISOLATION_UNCOMMITTED: - case self::ISOLATION_COMMITTED: - case self::ISOLATION_REPEATABLE: - case self::ISOLATION_SERIALIZABLE: + case SqlTransaction::ISOLATION_UNCOMMITTED: + case SqlTransaction::ISOLATION_COMMITTED: + case SqlTransaction::ISOLATION_REPEATABLE: + case SqlTransaction::ISOLATION_SERIALIZABLE: $this->isolation = $isolation; break; From 0694bbded9934e7cf6eb0e8cf56abf4bd9c94026 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Sun, 1 Jul 2018 00:53:05 +0100 Subject: [PATCH 19/25] @expectedException refs must be fully qualified --- test/AbstractLinkTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/AbstractLinkTest.php b/test/AbstractLinkTest.php index 67510a7..712cd69 100644 --- a/test/AbstractLinkTest.php +++ b/test/AbstractLinkTest.php @@ -103,7 +103,7 @@ public function testQueryWithCommandResult() } /** - * @expectedException QueryError + * @expectedException \Amp\Sql\QueryError */ public function testQueryWithEmptyQuery() { @@ -669,7 +669,7 @@ public function testNotify() /** * @depends testListen - * @expectedException QueryError + * @expectedException \Amp\Sql\QueryError * @expectedExceptionMessage Already listening on channel */ public function testListenOnSameChannel() From b78db5c226712c3cdce799413d2702da83bbc5f7 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Sun, 1 Jul 2018 00:59:23 +0100 Subject: [PATCH 20/25] Guard against null handle in transaction liveness check --- src/Transaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Transaction.php b/src/Transaction.php index 3cd704d..1e8e713 100644 --- a/src/Transaction.php +++ b/src/Transaction.php @@ -81,7 +81,7 @@ public function onDestruct(callable $onComplete) */ public function isAlive(): bool { - return $this->handle->isAlive(); + return $this->handle && $this->handle->isAlive(); } /** From 899eff9702d4f260ad5ef943be6233560642da76 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Sun, 1 Jul 2018 02:16:53 +0100 Subject: [PATCH 21/25] Fix imports in PqHandle --- src/PqHandle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PqHandle.php b/src/PqHandle.php index b2e1407..8fad831 100644 --- a/src/PqHandle.php +++ b/src/PqHandle.php @@ -10,8 +10,8 @@ use Amp\Promise; use Amp\Sql\ConnectionException; use Amp\Sql\FailureException; +use Amp\Sql\QueryError; use Amp\Success; -use pq; use function Amp\call; use function Amp\coroutine; From 8162ac549ffd44fbbd5d2f81c476f33a9b28fa0c Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Sun, 1 Jul 2018 02:26:22 +0100 Subject: [PATCH 22/25] Fix connect impl for mock ext/pg pool --- test/PgSqlPoolTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/PgSqlPoolTest.php b/test/PgSqlPoolTest.php index 4e549e1..ada0903 100644 --- a/test/PgSqlPoolTest.php +++ b/test/PgSqlPoolTest.php @@ -4,6 +4,7 @@ use Amp\Postgres\ConnectionConfig; use Amp\Postgres\Link; +use Amp\Postgres\PgSqlConnection; use Amp\Postgres\Pool; use Amp\Promise; use Amp\Sql\Connector; @@ -32,8 +33,9 @@ public function createLink(string $connectionString): Link if (!isset($this->handles[$count])) { $this->fail("createConnection called too many times"); } + $handle = $this->handles[$count]; ++$count; - return new Success(); + return new Success(new PgSqlConnection($handle, \pg_socket($handle))); })); $pool = new Pool(new ConnectionConfig('connection string'), \count($this->handles), $connector); From a38a506caa63a8e3e77bcdac6fa7ee829d376f48 Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Sun, 1 Jul 2018 02:28:02 +0100 Subject: [PATCH 23/25] Re-add mistakenly removed import --- src/PqHandle.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PqHandle.php b/src/PqHandle.php index 8fad831..74cc27b 100644 --- a/src/PqHandle.php +++ b/src/PqHandle.php @@ -12,6 +12,7 @@ use Amp\Sql\FailureException; use Amp\Sql\QueryError; use Amp\Success; +use pq; use function Amp\call; use function Amp\coroutine; From 6401df21f26f0e7076468d770d13a4d3adbf93be Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Sun, 1 Jul 2018 02:42:35 +0100 Subject: [PATCH 24/25] Remove extension repo directories after install on travis --- travis/install-pq.sh | 1 + travis/install-raphf.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/travis/install-pq.sh b/travis/install-pq.sh index 152d319..54e0a49 100755 --- a/travis/install-pq.sh +++ b/travis/install-pq.sh @@ -8,3 +8,4 @@ make; make install; popd; echo "extension=pq.so" >> "$(php -r 'echo php_ini_loaded_file();')"; +rm -rf ext-pq diff --git a/travis/install-raphf.sh b/travis/install-raphf.sh index 8347f04..222f34c 100755 --- a/travis/install-raphf.sh +++ b/travis/install-raphf.sh @@ -8,3 +8,4 @@ make; make install; popd; echo "extension=raphf.so" >> "$(php -r 'echo php_ini_loaded_file();')"; +rm -rf ext-raphf From 6339332a0c86e3485f390e1abd6521eeb1bc657f Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Sun, 1 Jul 2018 02:43:07 +0100 Subject: [PATCH 25/25] Fix import order in DefaultPoolTest --- test/DefaultPoolTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/DefaultPoolTest.php b/test/DefaultPoolTest.php index bb9bcab..f295d96 100644 --- a/test/DefaultPoolTest.php +++ b/test/DefaultPoolTest.php @@ -4,8 +4,8 @@ use Amp\Delayed; use Amp\Loop; -use Amp\Postgres\Pool; use Amp\Postgres\ConnectionConfig; +use Amp\Postgres\Pool; use PHPUnit\Framework\TestCase; class DefaultPoolTest extends TestCase