diff --git a/README.md b/README.md index 1f6c008..e63f668 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ given event loop instance. #### query() -The `query(string $query, array $params = []): PromiseInterface` method can be used to +The `query(string $query, list $params = []): PromiseInterface` method can be used to perform an async query. This method returns a promise that will resolve with a `MysqlResult` on @@ -258,7 +258,7 @@ suited for exposing multiple possible results. #### queryStream() -The `queryStream(string $sql, array $params = []): ReadableStreamInterface` method can be used to +The `queryStream(string $sql, list $params = []): ReadableStreamInterface` method can be used to perform an async query and stream the rows of the result set. This method returns a readable stream that will emit each row of the diff --git a/src/Io/Connection.php b/src/Io/Connection.php index 74be321..df6f50d 100644 --- a/src/Io/Connection.php +++ b/src/Io/Connection.php @@ -90,16 +90,8 @@ public function isBusy() return $this->parser->isBusy() || !$this->executor->isIdle(); } - /** - * {@inheritdoc} - */ - public function query($sql, array $params = []) + public function query(Query $query) { - $query = new Query($sql); - if ($params) { - $query->bindParamsFromArray($params); - } - $command = new QueryCommand(); $command->setQuery($query); try { @@ -146,13 +138,8 @@ public function query($sql, array $params = []) return $deferred->promise(); } - public function queryStream($sql, $params = []) + public function queryStream(Query $query) { - $query = new Query($sql); - if ($params) { - $query->bindParamsFromArray($params); - } - $command = new QueryCommand(); $command->setQuery($query); $this->_doCommand($command); diff --git a/src/Io/Query.php b/src/Io/Query.php index d89af78..0c6ad43 100644 --- a/src/Io/Query.php +++ b/src/Io/Query.php @@ -41,46 +41,22 @@ class Query //"_" => "\\_", ]; - public function __construct($sql) - { - $this->sql = $this->builtSql = $sql; - } - - /** - * Binding params for the query, multiple arguments support. - * - * @param mixed $param - * @return self - */ - public function bindParams() - { - $this->builtSql = null; - $this->params = func_get_args(); - - return $this; - } - - public function bindParamsFromArray(array $params) - { - $this->builtSql = null; - $this->params = $params; - - return $this; - } - /** - * Binding params for the query, multiple arguments support. - * - * @param mixed $param - * @return self - * @deprecated + * @param string $sql + * @param list $params + * @throws \InvalidArgumentException if given $params are invalid */ - public function params() + public function __construct($sql, array $params = []) { - $this->params = func_get_args(); - $this->builtSql = null; + foreach ($params as $param) { + if (!\is_scalar($param) && $param !== null) { + throw new \InvalidArgumentException('Query param must be of type string|int|float|bool|null, ' . (\is_object($param) ? \get_class($param) : \gettype($param)) . ' given'); + } + } - return $this; + $this->sql = $sql; + $this->builtSql = $params ? null : $sql; + $this->params = $params; } public function escape($str) @@ -105,19 +81,9 @@ protected function resolveValueForSql($value) case 'string': $value = "'" . $this->escape($value) . "'"; break; - case 'array': - $nvalue = []; - foreach ($value as $v) { - $nvalue[] = $this->resolveValueForSql($v); - } - $value = implode(',', $nvalue); - break; case 'NULL': $value = 'NULL'; break; - default: - throw new \InvalidArgumentException(sprintf('Not supported value type of %s.', $type)); - break; } return $value; diff --git a/src/MysqlClient.php b/src/MysqlClient.php index 20a9aa8..df3e4da 100644 --- a/src/MysqlClient.php +++ b/src/MysqlClient.php @@ -6,6 +6,7 @@ use React\EventLoop\LoopInterface; use React\Mysql\Io\Connection; use React\Mysql\Io\Factory; +use React\Mysql\Io\Query; use React\Promise\Deferred; use React\Promise\Promise; use React\Promise\PromiseInterface; @@ -152,19 +153,22 @@ public function __construct( * could allow for possible SQL injection attacks and this API is not * suited for exposing multiple possible results. * - * @param string $sql SQL statement - * @param array $params Parameters which should be bound to query + * @param string $sql SQL statement + * @param list $params Parameters which should be bound to query * @return PromiseInterface * Resolves with a `MysqlResult` on success or rejects with an `Exception` on error. + * @throws \InvalidArgumentException if given $params are invalid */ public function query($sql, array $params = []) { + $query = new Query($sql, $params); + if ($this->closed || $this->quitting) { return \React\Promise\reject(new Exception('Connection closed')); } - return $this->getConnection()->then(function (Connection $connection) use ($sql, $params) { - return $connection->query($sql, $params)->then(function (MysqlResult $result) use ($connection) { + return $this->getConnection()->then(function (Connection $connection) use ($query) { + return $connection->query($query)->then(function (MysqlResult $result) use ($connection) { $this->handleConnectionReady($connection); return $result; }, function (\Exception $e) use ($connection) { @@ -229,19 +233,23 @@ public function query($sql, array $params = []) * could allow for possible SQL injection attacks and this API is not * suited for exposing multiple possible results. * - * @param string $sql SQL statement - * @param array $params Parameters which should be bound to query + * @param string $sql SQL statement + * @param list $params Parameters which should be bound to query * @return ReadableStreamInterface + * @throws \InvalidArgumentException if given $params are invalid + * @throws Exception if connection is already closed/closing */ - public function queryStream($sql, $params = []) + public function queryStream($sql, array $params = []) { + $query = new Query($sql, $params); + if ($this->closed || $this->quitting) { throw new Exception('Connection closed'); } return \React\Promise\Stream\unwrapReadable( - $this->getConnection()->then(function (Connection $connection) use ($sql, $params) { - $stream = $connection->queryStream($sql, $params); + $this->getConnection()->then(function (Connection $connection) use ($query) { + $stream = $connection->queryStream($query); $stream->on('end', function () use ($connection) { $this->handleConnectionReady($connection); diff --git a/tests/Io/ConnectionTest.php b/tests/Io/ConnectionTest.php index 5a0a5ff..2940574 100644 --- a/tests/Io/ConnectionTest.php +++ b/tests/Io/ConnectionTest.php @@ -3,6 +3,7 @@ namespace React\Tests\Mysql\Io; use React\Mysql\Io\Connection; +use React\Mysql\Io\Query; use React\Tests\Mysql\BaseTestCase; class ConnectionTest extends BaseTestCase @@ -22,7 +23,7 @@ public function testIsBusyReturnsTrueWhenParserIsBusy() $connection = new Connection($stream, $executor, $parser, $loop, null); - $connection->query('SELECT 1'); + $connection->query(new Query('SELECT 1')); $this->assertTrue($connection->isBusy()); } @@ -57,7 +58,7 @@ public function testQueryWillEnqueueOneCommand() $loop->expects($this->never())->method('addTimer'); $conn = new Connection($stream, $executor, $parser, $loop, null); - $conn->query('SELECT 1'); + $conn->query(new Query('SELECT 1')); } public function testQueryWillReturnResolvedPromiseAndStartIdleTimerWhenQueryCommandEmitsSuccess() @@ -81,7 +82,7 @@ public function testQueryWillReturnResolvedPromiseAndStartIdleTimerWhenQueryComm $this->assertNull($currentCommand); - $promise = $connection->query('SELECT 1'); + $promise = $connection->query(new Query('SELECT 1')); $promise->then($this->expectCallableOnceWith($this->isInstanceOf('React\Mysql\MysqlResult'))); @@ -110,7 +111,7 @@ public function testQueryWillReturnResolvedPromiseAndStartIdleTimerWhenQueryComm $this->assertNull($currentCommand); - $promise = $connection->query('SELECT 1'); + $promise = $connection->query(new Query('SELECT 1')); $promise->then($this->expectCallableOnceWith($this->isInstanceOf('React\Mysql\MysqlResult'))); @@ -139,7 +140,7 @@ public function testQueryWillReturnResolvedPromiseAndStartIdleTimerWhenIdlePerio $this->assertNull($currentCommand); - $promise = $connection->query('SELECT 1'); + $promise = $connection->query(new Query('SELECT 1')); $promise->then($this->expectCallableOnceWith($this->isInstanceOf('React\Mysql\MysqlResult'))); @@ -166,7 +167,7 @@ public function testQueryWillReturnResolvedPromiseAndNotStartIdleTimerWhenIdlePe $this->assertNull($currentCommand); - $promise = $connection->query('SELECT 1'); + $promise = $connection->query(new Query('SELECT 1')); $promise->then($this->expectCallableOnceWith($this->isInstanceOf('React\Mysql\MysqlResult'))); @@ -195,7 +196,7 @@ public function testQueryWillReturnRejectedPromiseAndStartIdleTimerWhenQueryComm $this->assertNull($currentCommand); - $promise = $connection->query('SELECT 1'); + $promise = $connection->query(new Query('SELECT 1')); $promise->then(null, $this->expectCallableOnce()); @@ -230,7 +231,7 @@ public function testQueryFollowedByIdleTimerWillQuitUnderlyingConnectionAndEmitC $this->assertNull($currentCommand); - $connection->query('SELECT 1'); + $connection->query(new Query('SELECT 1')); $this->assertNotNull($currentCommand); $currentCommand->emit('success'); @@ -269,7 +270,7 @@ public function testQueryFollowedByIdleTimerWillQuitUnderlyingConnectionAndEmitC $this->assertNull($currentCommand); - $connection->query('SELECT 1'); + $connection->query(new Query('SELECT 1')); $this->assertNotNull($currentCommand); $currentCommand->emit('success'); @@ -300,8 +301,8 @@ public function testQueryTwiceWillEnqueueSecondQueryWithoutStartingIdleTimerWhen $this->assertNull($currentCommand); - $connection->query('SELECT 1'); - $connection->query('SELECT 2'); + $connection->query(new Query('SELECT 1')); + $connection->query(new Query('SELECT 2')); $this->assertNotNull($currentCommand); $currentCommand->emit('success'); @@ -328,12 +329,12 @@ public function testQueryTwiceAfterIdleTimerWasStartedWillCancelIdleTimerAndEnqu $this->assertNull($currentCommand); - $connection->query('SELECT 1'); + $connection->query(new Query('SELECT 1')); $this->assertNotNull($currentCommand); $currentCommand->emit('success'); - $connection->query('SELECT 2'); + $connection->query(new Query('SELECT 2')); } public function testQueryStreamWillEnqueueOneCommand() @@ -350,7 +351,7 @@ public function testQueryStreamWillEnqueueOneCommand() $loop->expects($this->never())->method('addTimer'); $conn = new Connection($stream, $executor, $parser, $loop, null); - $conn->queryStream('SELECT 1'); + $conn->queryStream(new Query('SELECT 1')); } public function testQueryStreamWillReturnStreamThatWillEmitEndEventAndStartIdleTimerWhenQueryCommandEmitsSuccess() @@ -374,7 +375,7 @@ public function testQueryStreamWillReturnStreamThatWillEmitEndEventAndStartIdleT $this->assertNull($currentCommand); - $stream = $connection->queryStream('SELECT 1'); + $stream = $connection->queryStream(new Query('SELECT 1')); $stream->on('end', $this->expectCallableOnce()); $stream->on('close', $this->expectCallableOnce()); @@ -404,7 +405,7 @@ public function testQueryStreamWillReturnStreamThatWillEmitErrorEventAndStartIdl $this->assertNull($currentCommand); - $stream = $connection->queryStream('SELECT 1'); + $stream = $connection->queryStream(new Query('SELECT 1')); $stream->on('error', $this->expectCallableOnceWith($this->isInstanceOf('RuntimeException'))); $stream->on('close', $this->expectCallableOnce()); @@ -641,7 +642,7 @@ public function testQueryAfterQuitRejectsImmediately() $conn = new Connection($stream, $executor, $parser, $loop, null); $conn->quit(); - $promise = $conn->query('SELECT 1'); + $promise = $conn->query(new Query('SELECT 1')); $promise->then(null, $this->expectCallableOnceWith( $this->logicalAnd( @@ -668,7 +669,7 @@ public function testQueryAfterCloseRejectsImmediately() $conn = new Connection($stream, $executor, $parser, $loop, null); $conn->close(); - $promise = $conn->query('SELECT 1'); + $promise = $conn->query(new Query('SELECT 1')); $promise->then(null, $this->expectCallableOnceWith( $this->logicalAnd( @@ -697,7 +698,7 @@ public function testQueryStreamAfterQuitThrows() $conn->quit(); try { - $conn->queryStream('SELECT 1'); + $conn->queryStream(new Query('SELECT 1')); } catch (\RuntimeException $e) { $this->assertEquals('Connection closing (ENOTCONN)', $e->getMessage()); $this->assertEquals(defined('SOCKET_ENOTCONN') ? SOCKET_ENOTCONN : 107, $e->getCode()); diff --git a/tests/Io/QueryTest.php b/tests/Io/QueryTest.php index 420c650..6ca2e25 100644 --- a/tests/Io/QueryTest.php +++ b/tests/Io/QueryTest.php @@ -2,64 +2,55 @@ namespace React\Tests\Mysql\Io; -use PHPUnit\Framework\TestCase; use React\Mysql\Io\Query; +use React\Tests\Mysql\BaseTestCase; -class QueryTest extends TestCase +class QueryTest extends BaseTestCase { + public function testCtorThrowsForInvalidParams() + { + $this->setExpectedException('InvalidArgumentException', 'Query param must be of type string|int|float|bool|null, resource given'); + new Query('SELECT ?', [tmpfile()]); + } + public function testBindParams() { - $query = new Query('select * from test where id = ? and name = ?'); - $sql = $query->bindParams(100, 'test')->getSql(); - $this->assertEquals("select * from test where id = 100 and name = 'test'", $sql); + $query = new Query('select * from test where id = ? and name = ?', [100, 'test']); + $this->assertEquals("select * from test where id = 100 and name = 'test'", $query->getSql()); - $query = new Query('select * from test where id in (?) and name = ?'); - $sql = $query->bindParams([1, 2], 'test')->getSql(); - $this->assertEquals("select * from test where id in (1,2) and name = 'test'", $sql); + $query = new Query('select * from test where id in (?,?) and name = ?', [1, 2, 'test']); + $this->assertEquals("select * from test where id in (1,2) and name = 'test'", $query->getSql()); /* - $query = new Query('select * from test where id = :id and name = :name'); - $sql = $query->params([':id' => 100, ':name' => 'test'])->getSql(); - $this->assertEquals("select * from test where id = 100 and name = 'test'", $sql); + $query = new Query('select * from test where id = :id and name = :name', [':id' => 100, ':name' => 'test']); + $this->assertEquals("select * from test where id = 100 and name = 'test'", $query->getSql()); - $query = new Query('select * from test where id = :id and name = ?'); - $sql = $query->params('test', [':id' => 100])->getSql(); - $this->assertEquals("select * from test where id = 100 and name = 'test'", $sql); + $query = new Query('select * from test where id = :id and name = ?', ['test', ':id' => 100]); + $this->assertEquals("select * from test where id = 100 and name = 'test'", $query->getSql()); */ } public function testGetSqlReturnsQuestionMarkReplacedWhenBound() { - $query = new Query('select ?'); - $sql = $query->bindParams('hello')->getSql(); - $this->assertEquals("select 'hello'", $sql); - } - - public function testGetSqlReturnsQuestionMarkReplacedWhenBoundFromLastCall() - { - $query = new Query('select ?'); - $sql = $query->bindParams('foo')->bindParams('bar')->getSql(); - $this->assertEquals("select 'bar'", $sql); + $query = new Query('select ?', ['hello']); + $this->assertEquals("select 'hello'", $query->getSql()); } public function testGetSqlReturnsQuestionMarkReplacedWithNullValueWhenBound() { - $query = new Query('select ?'); - $sql = $query->bindParams(null)->getSql(); - $this->assertEquals("select NULL", $sql); + $query = new Query('select ?', [null]); + $this->assertEquals("select NULL", $query->getSql()); } public function testGetSqlReturnsQuestionMarkReplacedFromBoundWhenBound() { - $query = new Query('select CONCAT(?, ?)'); - $sql = $query->bindParams('hello??', 'world??')->getSql(); - $this->assertEquals("select CONCAT('hello??', 'world??')", $sql); + $query = new Query('select CONCAT(?, ?)', ['hello??', 'world??']); + $this->assertEquals("select CONCAT('hello??', 'world??')", $query->getSql()); } public function testGetSqlReturnsQuestionMarksAsIsWhenNotBound() { $query = new Query('select "hello?"'); - $sql = $query->getSql(); - $this->assertEquals("select \"hello?\"", $sql); + $this->assertEquals("select \"hello?\"", $query->getSql()); } public function testEscapeChars() diff --git a/tests/MysqlClientTest.php b/tests/MysqlClientTest.php index 1df526f..ec5340b 100644 --- a/tests/MysqlClientTest.php +++ b/tests/MysqlClientTest.php @@ -3,6 +3,7 @@ namespace React\Tests\Mysql; use React\Mysql\Io\Connection; +use React\Mysql\Io\Query; use React\Mysql\MysqlClient; use React\Mysql\MysqlResult; use React\Promise\Deferred; @@ -191,7 +192,7 @@ public function testQueryWillCreateNewConnectionAndReturnPendingPromiseWhenConne public function testQueryWillCreateNewConnectionAndReturnPendingPromiseWhenConnectionResolvesAndQueryOnConnectionIsPending() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $connection->expects($this->once())->method('query')->with('SELECT 1')->willReturn(new Promise(function () { })); + $connection->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn(new Promise(function () { })); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); $factory->expects($this->once())->method('createConnection')->willReturn(\React\Promise\resolve($connection)); @@ -212,7 +213,7 @@ public function testQueryWillReturnResolvedPromiseWhenQueryOnConnectionResolves( { $result = new MysqlResult(); $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $connection->expects($this->once())->method('query')->with('SELECT 1')->willReturn(\React\Promise\resolve($result)); + $connection->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn(\React\Promise\resolve($result)); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); $factory->expects($this->once())->method('createConnection')->willReturn(\React\Promise\resolve($connection)); @@ -249,7 +250,7 @@ public function testQueryWillReturnRejectedPromiseWhenCreateConnectionRejects() public function testQueryWillReturnRejectedPromiseWhenQueryOnConnectionRejectsAfterCreateConnectionResolves() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $connection->expects($this->once())->method('query')->with('SELECT 1')->willReturn(\React\Promise\reject(new \RuntimeException())); + $connection->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn(\React\Promise\reject(new \RuntimeException())); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); $factory->expects($this->once())->method('createConnection')->willReturn(\React\Promise\resolve($connection)); @@ -289,7 +290,7 @@ public function testQueryTwiceWillCreateSingleConnectionAndReturnPendingPromiseW public function testQueryTwiceWillCallQueryOnConnectionOnlyOnceWhenQueryIsStillPending() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $connection->expects($this->once())->method('query')->with('SELECT 1')->willReturn(new Promise(function () { })); + $connection->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn(new Promise(function () { })); $connection->expects($this->once())->method('isBusy')->willReturn(true); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); @@ -313,8 +314,8 @@ public function testQueryTwiceWillReuseConnectionForSecondQueryWhenFirstQueryIsA { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); $connection->expects($this->exactly(2))->method('query')->withConsecutive( - ['SELECT 1'], - ['SELECT 2'] + [new Query('SELECT 1')], + [new Query('SELECT 2')] )->willReturnOnConsecutiveCalls( \React\Promise\resolve(new MysqlResult()), new Promise(function () { }) @@ -342,8 +343,8 @@ public function testQueryTwiceWillCallSecondQueryOnConnectionAfterFirstQueryReso { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); $connection->expects($this->exactly(2))->method('query')->withConsecutive( - ['SELECT 1'], - ['SELECT 2'] + [new Query('SELECT 1')], + [new Query('SELECT 2')] )->willReturnOnConsecutiveCalls( \React\Promise\resolve(new MysqlResult()), new Promise(function () { }) @@ -373,7 +374,7 @@ public function testQueryTwiceWillCallSecondQueryOnConnectionAfterFirstQueryReso public function testQueryTwiceWillCreateNewConnectionForSecondQueryWhenFirstConnectionIsClosedAfterFirstQueryIsResolved() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->setMethods(['query', 'isBusy'])->getMock(); - $connection->expects($this->once())->method('query')->with('SELECT 1')->willReturn(\React\Promise\resolve(new MysqlResult())); + $connection->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn(\React\Promise\resolve(new MysqlResult())); $connection->expects($this->never())->method('isBusy'); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); @@ -402,7 +403,7 @@ public function testQueryTwiceWillCreateNewConnectionForSecondQueryWhenFirstConn public function testQueryTwiceWillCloseFirstConnectionAndCreateNewConnectionForSecondQueryWhenFirstConnectionIsInClosingStateDueToIdleTimerAfterFirstQueryIsResolved() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->setMethods(['query', 'isBusy', 'close'])->getMock(); - $connection->expects($this->once())->method('query')->with('SELECT 1')->willReturn(\React\Promise\resolve(new MysqlResult())); + $connection->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn(\React\Promise\resolve(new MysqlResult())); $connection->expects($this->once())->method('close'); $connection->expects($this->never())->method('isBusy'); @@ -511,8 +512,8 @@ public function testQueryTwiceWillCallSecondQueryOnConnectionAfterFirstQueryReje { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); $connection->expects($this->exactly(2))->method('query')->withConsecutive( - ['SELECT 1'], - ['SELECT 2'] + [new Query('SELECT 1')], + [new Query('SELECT 2')] )->willReturnOnConsecutiveCalls( \React\Promise\reject(new \RuntimeException()), new Promise(function () { }) @@ -561,7 +562,7 @@ public function testQueryStreamWillCreateNewConnectionAndReturnReadableStreamWhe public function testQueryStreamWillCreateNewConnectionAndReturnReadableStreamWhenConnectionResolvesAndQueryStreamOnConnectionReturnsReadableStream() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $connection->expects($this->once())->method('queryStream')->with('SELECT 1')->willReturn(new ThroughStream()); + $connection->expects($this->once())->method('queryStream')->with(new Query('SELECT 1'))->willReturn(new ThroughStream()); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); $factory->expects($this->once())->method('createConnection')->willReturn(\React\Promise\resolve($connection)); @@ -581,7 +582,7 @@ public function testQueryStreamWillCreateNewConnectionAndReturnReadableStreamWhe public function testQueryStreamTwiceWillCallQueryStreamOnConnectionOnlyOnceWhenQueryStreamIsStillReadable() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $connection->expects($this->once())->method('queryStream')->with('SELECT 1')->willReturn(new ThroughStream()); + $connection->expects($this->once())->method('queryStream')->with(new Query('SELECT 1'))->willReturn(new ThroughStream()); $connection->expects($this->once())->method('isBusy')->willReturn(true); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); @@ -605,8 +606,8 @@ public function testQueryStreamTwiceWillReuseConnectionForSecondQueryStreamWhenF { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); $connection->expects($this->exactly(2))->method('queryStream')->withConsecutive( - ['SELECT 1'], - ['SELECT 2'] + [new Query('SELECT 1')], + [new Query('SELECT 2')] )->willReturnOnConsecutiveCalls( $base = new ThroughStream(), new ThroughStream() @@ -636,8 +637,8 @@ public function testQueryStreamTwiceWillReuseConnectionForSecondQueryStreamWhenF { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); $connection->expects($this->exactly(2))->method('queryStream')->withConsecutive( - ['SELECT 1'], - ['SELECT 2'] + [new Query('SELECT 1')], + [new Query('SELECT 2')] )->willReturnOnConsecutiveCalls( $base = new ThroughStream(), new ThroughStream() @@ -669,7 +670,7 @@ public function testQueryStreamTwiceWillReuseConnectionForSecondQueryStreamWhenF public function testQueryStreamTwiceWillWaitForFirstQueryStreamToEndBeforeStartingSecondQueryStreamWhenFirstQueryStreamIsExplicitlyClosed() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $connection->expects($this->once())->method('queryStream')->with('SELECT 1')->willReturn(new ThroughStream()); + $connection->expects($this->once())->method('queryStream')->with(new Query('SELECT 1'))->willReturn(new ThroughStream()); $connection->expects($this->once())->method('isBusy')->willReturn(true); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); @@ -698,8 +699,8 @@ public function testQueryStreamTwiceWillCallSecondQueryStreamOnConnectionAfterFi { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); $connection->expects($this->exactly(2))->method('queryStream')->withConsecutive( - ['SELECT 1'], - ['SELECT 2'] + [new Query('SELECT 1')], + [new Query('SELECT 2')] )->willReturnOnConsecutiveCalls( $base = new ThroughStream(), new ThroughStream() @@ -730,7 +731,7 @@ public function testQueryStreamTwiceWillCallSecondQueryStreamOnConnectionAfterFi public function testQueryStreamTwiceWillCreateNewConnectionForSecondQueryStreamWhenFirstConnectionIsClosedAfterFirstQueryStreamIsClosed() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->setMethods(['queryStream', 'isBusy'])->getMock(); - $connection->expects($this->once())->method('queryStream')->with('SELECT 1')->willReturn($base = new ThroughStream()); + $connection->expects($this->once())->method('queryStream')->with(new Query('SELECT 1'))->willReturn($base = new ThroughStream()); $connection->expects($this->never())->method('isBusy'); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); @@ -760,7 +761,7 @@ public function testQueryStreamTwiceWillCreateNewConnectionForSecondQueryStreamW public function testQueryStreamTwiceWillCloseFirstConnectionAndCreateNewConnectionForSecondQueryStreamWhenFirstConnectionIsInClosingStateDueToIdleTimerAfterFirstQueryStreamIsClosed() { $connection = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->setMethods(['queryStream', 'isBusy', 'close'])->getMock(); - $connection->expects($this->once())->method('queryStream')->with('SELECT 1')->willReturn($base = new ThroughStream()); + $connection->expects($this->once())->method('queryStream')->with(new Query('SELECT 1'))->willReturn($base = new ThroughStream()); $connection->expects($this->once())->method('close'); $connection->expects($this->never())->method('isBusy'); @@ -1207,7 +1208,7 @@ public function testQueryWillResolveWhenQueryFromUnderlyingConnectionResolves() $result = new MysqlResult(); $base = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $base->expects($this->once())->method('query')->with('SELECT 1')->willReturn(\React\Promise\resolve($result)); + $base->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn(\React\Promise\resolve($result)); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); $factory->expects($this->once())->method('createConnection')->willReturn(\React\Promise\resolve($base)); @@ -1230,7 +1231,7 @@ public function testPingAfterQueryWillPassPingToConnectionWhenQueryResolves() $deferred = new Deferred(); $base = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $base->expects($this->once())->method('query')->with('SELECT 1')->willReturn($deferred->promise()); + $base->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn($deferred->promise()); $base->expects($this->once())->method('ping')->willReturn(new Promise(function () { })); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); @@ -1257,7 +1258,7 @@ public function testQueryWillRejectWhenQueryFromUnderlyingConnectionRejects() $error = new \RuntimeException(); $base = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $base->expects($this->once())->method('query')->with('SELECT 1')->willReturn(\React\Promise\reject($error)); + $base->expects($this->once())->method('query')->with(new Query('SELECT 1'))->willReturn(\React\Promise\reject($error)); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); $factory->expects($this->once())->method('createConnection')->willReturn(\React\Promise\resolve($base)); @@ -1317,7 +1318,7 @@ public function testQueryStreamWillReturnStreamFromUnderlyingConnectionWhenResol { $stream = new ThroughStream(); $base = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $base->expects($this->once())->method('queryStream')->with('SELECT 1')->willReturn($stream); + $base->expects($this->once())->method('queryStream')->with(new Query('SELECT 1'))->willReturn($stream); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); $factory->expects($this->once())->method('createConnection')->willReturn(\React\Promise\resolve($base)); @@ -1342,7 +1343,7 @@ public function testQueryStreamWillReturnStreamFromUnderlyingConnectionWhenResol { $stream = new ThroughStream(); $base = $this->getMockBuilder('React\Mysql\Io\Connection')->disableOriginalConstructor()->getMock(); - $base->expects($this->once())->method('queryStream')->with('SELECT 1')->willReturn($stream); + $base->expects($this->once())->method('queryStream')->with(new Query('SELECT 1'))->willReturn($stream); $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); $factory->expects($this->once())->method('createConnection')->willReturn(\React\Promise\resolve($base)); @@ -1920,6 +1921,40 @@ public function testQueryReturnsRejectedPromiseAfterConnectionIsClosed() $ret->then($this->expectCallableNever(), $this->expectCallableOnce()); } + public function testQueryThrowsForInvalidQueryParamsWithoutCreatingNewConnection() + { + $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); + $factory->expects($this->never())->method('createConnection'); + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + + $connection = new MysqlClient('', null, $loop); + + $ref = new \ReflectionProperty($connection, 'factory'); + $ref->setAccessible(true); + $ref->setValue($connection, $factory); + + $this->setExpectedException('InvalidArgumentException', 'Query param must be of type string|int|float|bool|null, array given'); + $connection->query('SELECT ?', [[]]); + } + + public function testQueryThrowsForInvalidQueryParamsWhenConnectionIsAlreadyClosed() + { + $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); + $factory->expects($this->never())->method('createConnection'); + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + + $connection = new MysqlClient('', null, $loop); + + $ref = new \ReflectionProperty($connection, 'factory'); + $ref->setAccessible(true); + $ref->setValue($connection, $factory); + + $connection->close(); + + $this->setExpectedException('InvalidArgumentException', 'Query param must be of type string|int|float|bool|null, array given'); + $connection->query('SELECT ?', [[]]); + } + public function testQueryStreamThrowsAfterConnectionIsClosed() { $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); @@ -1938,6 +1973,40 @@ public function testQueryStreamThrowsAfterConnectionIsClosed() $connection->queryStream('SELECT 1'); } + public function testQueryStreamThrowsForInvalidQueryParamsWithoutCreatingNewConnection() + { + $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); + $factory->expects($this->never())->method('createConnection'); + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + + $connection = new MysqlClient('', null, $loop); + + $ref = new \ReflectionProperty($connection, 'factory'); + $ref->setAccessible(true); + $ref->setValue($connection, $factory); + + $this->setExpectedException('InvalidArgumentException', 'Query param must be of type string|int|float|bool|null, stdClass given'); + $connection->queryStream('SELECT ?', [new \stdClass()]); + } + + public function testQueryStreamThrowsForInvalidQueryParamsWhenConnectionIsAlreadyClosed() + { + $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); + $factory->expects($this->never())->method('createConnection'); + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + + $connection = new MysqlClient('', null, $loop); + + $ref = new \ReflectionProperty($connection, 'factory'); + $ref->setAccessible(true); + $ref->setValue($connection, $factory); + + $connection->close(); + + $this->setExpectedException('InvalidArgumentException', 'Query param must be of type string|int|float|bool|null, stdClass given'); + $connection->queryStream('SELECT ?', [new \stdClass()]); + } + public function testPingReturnsRejectedPromiseAfterConnectionIsClosed() { $factory = $this->getMockBuilder('React\Mysql\Io\Factory')->disableOriginalConstructor()->getMock(); diff --git a/tests/NoResultQueryTest.php b/tests/NoResultQueryTest.php index faf9271..065d271 100644 --- a/tests/NoResultQueryTest.php +++ b/tests/NoResultQueryTest.php @@ -3,6 +3,7 @@ namespace React\Tests\Mysql; use React\EventLoop\Loop; +use React\Mysql\Io\Query; use React\Mysql\MysqlClient; use React\Mysql\MysqlResult; @@ -16,8 +17,8 @@ public function setUpDataTable() $connection = $this->createConnection(Loop::get()); // re-create test "book" table - $connection->query('DROP TABLE IF EXISTS book'); - $connection->query($this->getDataTable()); + $connection->query(new Query('DROP TABLE IF EXISTS book')); + $connection->query(new Query($this->getDataTable())); $connection->quit(); Loop::run(); @@ -27,7 +28,7 @@ public function testUpdateSimpleNonExistentReportsNoAffectedRows() { $connection = $this->createConnection(Loop::get()); - $connection->query('update book set created=999 where id=999')->then(function (MysqlResult $command) { + $connection->query(new Query('update book set created=999 where id=999'))->then(function (MysqlResult $command) { $this->assertEquals(0, $command->affectedRows); }); @@ -39,7 +40,7 @@ public function testInsertSimpleReportsFirstInsertId() { $connection = $this->createConnection(Loop::get()); - $connection->query("insert into book (`name`) values ('foo')")->then(function (MysqlResult $command) { + $connection->query(new Query("insert into book (`name`) values ('foo')"))->then(function (MysqlResult $command) { $this->assertEquals(1, $command->affectedRows); $this->assertEquals(1, $command->insertId); }); @@ -52,8 +53,8 @@ public function testUpdateSimpleReportsAffectedRow() { $connection = $this->createConnection(Loop::get()); - $connection->query("insert into book (`name`) values ('foo')"); - $connection->query('update book set created=999 where id=1')->then(function (MysqlResult $command) { + $connection->query(new Query("insert into book (`name`) values ('foo')")); + $connection->query(new Query('update book set created=999 where id=1'))->then(function (MysqlResult $command) { $this->assertEquals(1, $command->affectedRows); }); @@ -75,7 +76,7 @@ public function testCreateTableAgainWillAddWarning() PRIMARY KEY (`id`) )'; - $connection->query($sql)->then(function (MysqlResult $command) { + $connection->query(new Query($sql))->then(function (MysqlResult $command) { // 3 warnings on MySQL 8+, 1 warning on legacy MySQL 5 $this->assertGreaterThanOrEqual(1, $command->warningCount); }); diff --git a/tests/ResultQueryTest.php b/tests/ResultQueryTest.php index c779c9c..a288058 100644 --- a/tests/ResultQueryTest.php +++ b/tests/ResultQueryTest.php @@ -4,6 +4,7 @@ use React\EventLoop\Loop; use React\Mysql\Io\Constants; +use React\Mysql\Io\Query; use React\Mysql\MysqlClient; use React\Mysql\MysqlResult; @@ -13,7 +14,7 @@ public function testSelectStaticText() { $connection = $this->createConnection(Loop::get()); - $connection->query('select \'foo\'')->then(function (MysqlResult $command) { + $connection->query(new Query('select \'foo\''))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); $this->assertSame('foo', reset($command->resultRows[0])); @@ -51,7 +52,7 @@ public function testSelectStaticValueWillBeReturnedAsIs($value) $expected = $value; - $connection->query('select ?', [$value])->then(function (MysqlResult $command) use ($expected) { + $connection->query(new Query('select ?', [$value]))->then(function (MysqlResult $command) use ($expected) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); $this->assertSame($expected, reset($command->resultRows[0])); @@ -75,8 +76,8 @@ public function testSelectStaticValueWillBeReturnedAsIsWithNoBackslashEscapesSql $expected = $value; - $connection->query('SET SQL_MODE="NO_BACKSLASH_ESCAPES"'); - $connection->query('select ?', [$value])->then(function (MysqlResult $command) use ($expected) { + $connection->query(new Query('SET SQL_MODE="NO_BACKSLASH_ESCAPES"')); + $connection->query(new Query('select ?', [$value]))->then(function (MysqlResult $command) use ($expected) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); $this->assertSame($expected, reset($command->resultRows[0])); @@ -103,7 +104,7 @@ public function testSelectStaticValueWillBeConvertedToString($value, $expected) { $connection = $this->createConnection(Loop::get()); - $connection->query('select ?', [$value])->then(function (MysqlResult $command) use ($expected) { + $connection->query(new Query('select ?', [$value]))->then(function (MysqlResult $command) use ($expected) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); $this->assertSame($expected, reset($command->resultRows[0])); @@ -117,7 +118,7 @@ public function testSelectStaticTextWithQuestionMark() { $connection = $this->createConnection(Loop::get()); - $connection->query('select \'hello?\'')->then(function (MysqlResult $command) { + $connection->query(new Query('select \'hello?\''))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); $this->assertEquals('hello?', reset($command->resultRows[0])); @@ -134,7 +135,7 @@ public function testSelectLongStaticTextHasTypeStringWithValidLength() $length = 40000; $value = str_repeat('.', $length); - $connection->query('SELECT ?', [$value])->then(function (MysqlResult $command) use ($length) { + $connection->query(new Query('SELECT ?', [$value]))->then(function (MysqlResult $command) use ($length) { $this->assertCount(1, $command->resultFields); $this->assertEquals($length * 4, $command->resultFields[0]['length']); $this->assertSame(Constants::FIELD_TYPE_VAR_STRING, $command->resultFields[0]['type']); @@ -148,7 +149,7 @@ public function testSelectStaticTextWithEmptyLabel() { $connection = $this->createConnection(Loop::get()); - $connection->query('select \'foo\' as ``')->then(function (MysqlResult $command) { + $connection->query(new Query('select \'foo\' as ``'))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); $this->assertSame('foo', reset($command->resultRows[0])); @@ -166,7 +167,7 @@ public function testSelectStaticNullHasTypeNull() { $connection = $this->createConnection(Loop::get()); - $connection->query('select null')->then(function (MysqlResult $command) { + $connection->query(new Query('select null'))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); $this->assertNull(reset($command->resultRows[0])); @@ -183,7 +184,7 @@ public function testSelectStaticTextTwoRows() { $connection = $this->createConnection(Loop::get()); - $connection->query('select "foo" UNION select "bar"')->then(function (MysqlResult $command) { + $connection->query(new Query('select "foo" UNION select "bar"'))->then(function (MysqlResult $command) { $this->assertCount(2, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); @@ -199,7 +200,7 @@ public function testSelectStaticTextTwoRowsWithNullHasTypeString() { $connection = $this->createConnection(Loop::get()); - $connection->query('select "foo" UNION select null')->then(function (MysqlResult $command) { + $connection->query(new Query('select "foo" UNION select null'))->then(function (MysqlResult $command) { $this->assertCount(2, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); @@ -218,7 +219,7 @@ public function testSelectStaticIntegerTwoRowsWithNullHasTypeLongButReturnsIntAs { $connection = $this->createConnection(Loop::get()); - $connection->query('select 0 UNION select null')->then(function (MysqlResult $command) { + $connection->query(new Query('select 0 UNION select null'))->then(function (MysqlResult $command) { $this->assertCount(2, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); @@ -237,7 +238,7 @@ public function testSelectStaticTextTwoRowsWithIntegerHasTypeString() { $connection = $this->createConnection(Loop::get()); - $connection->query('select "foo" UNION select 1')->then(function (MysqlResult $command) { + $connection->query(new Query('select "foo" UNION select 1'))->then(function (MysqlResult $command) { $this->assertCount(2, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); @@ -256,7 +257,7 @@ public function testSelectStaticTextTwoRowsWithEmptyRow() { $connection = $this->createConnection(Loop::get()); - $connection->query('select "foo" UNION select ""')->then(function (MysqlResult $command) { + $connection->query(new Query('select "foo" UNION select ""'))->then(function (MysqlResult $command) { $this->assertCount(2, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); @@ -272,7 +273,7 @@ public function testSelectStaticTextNoRows() { $connection = $this->createConnection(Loop::get()); - $connection->query('select "foo" LIMIT 0')->then(function (MysqlResult $command) { + $connection->query(new Query('select "foo" LIMIT 0'))->then(function (MysqlResult $command) { $this->assertCount(0, $command->resultRows); $this->assertCount(1, $command->resultFields); @@ -287,7 +288,7 @@ public function testSelectStaticTextTwoColumns() { $connection = $this->createConnection(Loop::get()); - $connection->query('select "foo","bar"')->then(function (MysqlResult $command) { + $connection->query(new Query('select "foo","bar"'))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(2, $command->resultRows[0]); @@ -303,7 +304,7 @@ public function testSelectStaticTextTwoColumnsWithOneEmptyColumn() { $connection = $this->createConnection(Loop::get()); - $connection->query('select "foo",""')->then(function (MysqlResult $command) { + $connection->query(new Query('select "foo",""'))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(2, $command->resultRows[0]); @@ -319,7 +320,7 @@ public function testSelectStaticTextTwoColumnsWithBothEmpty() { $connection = $this->createConnection(Loop::get()); - $connection->query('select \'\' as `first`, \'\' as `second`')->then(function (MysqlResult $command) { + $connection->query(new Query('select \'\' as `first`, \'\' as `second`'))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(2, $command->resultRows[0]); $this->assertSame(['', ''], array_values($command->resultRows[0])); @@ -337,7 +338,7 @@ public function testSelectStaticTextTwoColumnsWithSameNameOverwritesValue() { $connection = $this->createConnection(Loop::get()); - $connection->query('select "foo" as `col`,"bar" as `col`')->then(function (MysqlResult $command) { + $connection->query(new Query('select "foo" as `col`,"bar" as `col`'))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); @@ -356,7 +357,7 @@ public function testSelectCharsetDefaultsToUtf8() { $connection = $this->createConnection(Loop::get()); - $connection->query('SELECT @@character_set_client')->then(function (MysqlResult $command) { + $connection->query(new Query('SELECT @@character_set_client'))->then(function (MysqlResult $command) { $this->assertCount(1, $command->resultRows); $this->assertCount(1, $command->resultRows[0]); $this->assertSame('utf8mb4', reset($command->resultRows[0])); @@ -386,12 +387,12 @@ public function testSimpleSelect() $connection = $this->createConnection(Loop::get()); // re-create test "book" table - $connection->query('DROP TABLE IF EXISTS book'); - $connection->query($this->getDataTable()); - $connection->query("insert into book (`name`) values ('foo')"); - $connection->query("insert into book (`name`) values ('bar')"); + $connection->query(new Query('DROP TABLE IF EXISTS book')); + $connection->query(new Query($this->getDataTable())); + $connection->query(new Query("insert into book (`name`) values ('foo')")); + $connection->query(new Query("insert into book (`name`) values ('bar')")); - $connection->query('select * from book')->then(function (MysqlResult $command) { + $connection->query(new Query('select * from book'))->then(function (MysqlResult $command) { $this->assertCount(2, $command->resultRows); }); @@ -422,7 +423,7 @@ public function testInvalidSelectShouldFail() $options = $this->getConnectionOptions(); $db = $options['dbname']; - $connection->query('select * from invalid_table')->then( + $connection->query(new Query('select * from invalid_table'))->then( $this->expectCallableNever(), function (\Exception $error) use ($db) { $this->assertEquals("Table '$db.invalid_table' doesn't exist", $error->getMessage()); @@ -437,7 +438,7 @@ public function testInvalidMultiStatementsShouldFailToPreventSqlInjections() { $connection = $this->createConnection(Loop::get()); - $connection->query('select 1;select 2;')->then( + $connection->query(new Query('select 1;select 2;'))->then( $this->expectCallableNever(), function (\Exception $error) { if (method_exists($this, 'assertStringContainsString')) { @@ -459,7 +460,7 @@ public function testSelectAfterDelay() $connection = $this->createConnection(Loop::get()); Loop::addTimer(0.1, function () use ($connection) { - $connection->query('select 1+1')->then(function (MysqlResult $command) { + $connection->query(new Query('select 1+1'))->then(function (MysqlResult $command) { $this->assertEquals([['1+1' => 2]], $command->resultRows); }); $connection->quit(); @@ -480,7 +481,7 @@ public function testQueryStreamStaticEmptyEmitsSingleRow() { $connection = $this->createConnection(Loop::get()); - $stream = $connection->queryStream('SELECT 1'); + $stream = $connection->queryStream(new Query('SELECT 1')); $stream->on('data', $this->expectCallableOnceWith(['1' => '1'])); $stream->on('end', $this->expectCallableOnce()); $stream->on('close', $this->expectCallableOnce()); @@ -493,7 +494,7 @@ public function testQueryStreamBoundVariableEmitsSingleRow() { $connection = $this->createConnection(Loop::get()); - $stream = $connection->queryStream('SELECT ? as value', ['test']); + $stream = $connection->queryStream(new Query('SELECT ? as value', ['test'])); $stream->on('data', $this->expectCallableOnceWith(['value' => 'test'])); $stream->on('end', $this->expectCallableOnce()); $stream->on('close', $this->expectCallableOnce()); @@ -506,7 +507,7 @@ public function testQueryStreamZeroRowsEmitsEndWithoutData() { $connection = $this->createConnection(Loop::get()); - $stream = $connection->queryStream('SELECT 1 LIMIT 0'); + $stream = $connection->queryStream(new Query('SELECT 1 LIMIT 0')); $stream->on('data', $this->expectCallableNever()); $stream->on('end', $this->expectCallableOnce()); $stream->on('close', $this->expectCallableOnce()); @@ -519,7 +520,7 @@ public function testQueryStreamInvalidStatementEmitsError() { $connection = $this->createConnection(Loop::get()); - $stream = $connection->queryStream('SELECT'); + $stream = $connection->queryStream(new Query('SELECT')); $stream->on('data', $this->expectCallableNever()); $stream->on('end', $this->expectCallableNever()); $stream->on('error', $this->expectCallableOnce()); @@ -533,7 +534,7 @@ public function testQueryStreamDropStatementEmitsEndWithoutData() { $connection = $this->createConnection(Loop::get()); - $stream = $connection->queryStream('DROP TABLE IF exists helloworldtest1'); + $stream = $connection->queryStream(new Query('DROP TABLE IF exists helloworldtest1')); $stream->on('data', $this->expectCallableNever()); $stream->on('end', $this->expectCallableOnce()); $stream->on('close', $this->expectCallableOnce()); @@ -546,7 +547,7 @@ public function testQueryStreamExplicitCloseEmitsCloseEventWithoutData() { $connection = $this->createConnection(Loop::get()); - $stream = $connection->queryStream('SELECT 1'); + $stream = $connection->queryStream(new Query('SELECT 1')); $stream->on('data', $this->expectCallableNever()); $stream->on('end', $this->expectCallableNever()); $stream->on('close', $this->expectCallableOnce());