Skip to content

Commit 00ff633

Browse files
committed
Fixed major bug in database.
- A rejected promise was not passed back from the connection to the command. Improved unit tests, cleared skipped tests. Improved code coverage. Added testing on actual loop->run callbacks. Looks like code formatter formats sql differently than phpmyadmin exports.
1 parent 75ebd1f commit 00ff633

File tree

9 files changed

+222
-116
lines changed

9 files changed

+222
-116
lines changed

src/Command.php

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ class Command
1717
*/
1818
protected $params = [];
1919

20+
/**
21+
* @var array
22+
*/
23+
protected $reserved_words = [
24+
'NOW()',
25+
];
26+
2027
public function __construct(Database $database, $sql = null)
2128
{
2229
$this->db = $database;
@@ -63,15 +70,17 @@ public function bindValues($params)
6370
*/
6471
public function getPreparedQuery(Connection $connection)
6572
{
66-
$quotedSql = $this->quoteIntoSql($connection);
73+
$quotedSql = $this->quoteIntoSql($connection);
6774

6875
return $quotedSql;
6976
}
7077

78+
// TODO: Find all of these...
79+
7180
/**
7281
* TODO: This is exactly what I don't want to do. "Roll my own" SQL handler.
7382
* However, the requirements for this package have led to this point for now.
74-
*
83+
*
7584
* @param Connection $connection
7685
* @return mixed
7786
*/
@@ -80,7 +89,7 @@ protected function quoteIntoSql(Connection $connection)
8089
$quotedSql = $this->sql;
8190
$quotedParams = [];
8291

83-
foreach($this->params as $key => $value)
92+
foreach ($this->params as $key => $value)
8493
{
8594
if (is_null($value))
8695
{
@@ -96,23 +105,20 @@ protected function quoteIntoSql(Connection $connection)
96105
}
97106
else
98107
{
99-
$quotedParams[$key] = '\''.$connection->escape($value).'\'';
108+
$quotedParams[$key] = '\'' . $connection->escape($value) . '\'';
100109
}
101110
}
102111

103112
return strtr($quotedSql, $quotedParams);
104113
}
105114

106-
// TODO: Find all of these...
107-
protected $reserved_words = [
108-
'NOW()'
109-
];
110-
111115
/**
112-
* @return \React\Promise\PromiseInterface
116+
* @return \React\Promise\Promise
113117
*/
114118
public function execute()
115119
{
116-
return $this->db->executeCommand($this);
120+
$thing = $this->db->executeCommand($this);
121+
122+
return $thing;
117123
}
118124
}

src/Connection.php

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,60 @@
77
class Connection
88
{
99
/**
10-
* @var \mysqli
10+
* @var LoopInterface
1111
*/
12-
protected $mysqli;
12+
public $loop;
1313

1414
/**
15-
* @var LoopInterface
15+
* @var \mysqli
1616
*/
17-
protected $loop;
17+
protected $mysqli;
1818

1919
/**
2020
* @var float
2121
*/
2222
protected $pollInterval = 0.01;
2323

24+
/**
25+
* @var bool|string
26+
*/
27+
protected $currentQuery = false;
28+
2429
public function __construct(\mysqli $mysqli, LoopInterface $loop)
2530
{
2631
$this->mysqli = $mysqli;
2732
$this->loop = $loop;
2833
}
2934

30-
public function escape($data)
35+
/**
36+
* Proxy to the mysqli connection object.
37+
*
38+
* @param $string
39+
* @return string
40+
*/
41+
public function escape($string)
3142
{
32-
if (is_array($data))
33-
{
34-
$data = array_map([
35-
$this,
36-
'escape',
37-
], $data);
38-
}
39-
else
40-
{
41-
$data = $this->mysqli->real_escape_string($data);
42-
}
43-
44-
return $data;
43+
return $this->mysqli->real_escape_string($string);
44+
}
45+
46+
/**
47+
* Close the mysqli connection.
48+
*/
49+
public function close()
50+
{
51+
$this->mysqli->close();
4552
}
4653

4754
public function execute(Command $command)
4855
{
49-
$query = $command->getPreparedQuery($this);
56+
if ($this->currentQuery)
57+
{
58+
throw new \Exception('Another query is already pending for this connection.');
59+
}
60+
61+
$this->currentQuery = $command->getPreparedQuery($this);
5062

51-
$status = $this->mysqli->query($query, MYSQLI_ASYNC);
63+
$status = $this->mysqli->query($this->currentQuery, MYSQLI_ASYNC);
5264
if ($status === false)
5365
{
5466
throw new \Exception($this->mysqli->error);
@@ -74,7 +86,7 @@ function (TimerInterface $timer) use ($deferred)
7486
$result = $this->mysqli->reap_async_query();
7587
if ($result === false)
7688
{
77-
$deferred->reject(new \Exception($this->mysqli->error));
89+
$deferred->reject($this->mysqli->error);
7890
}
7991
else
8092
{
@@ -86,20 +98,21 @@ function (TimerInterface $timer) use ($deferred)
8698
{
8799
if ($error)
88100
{
89-
$deferred->reject(new \Exception($this->mysqli->error));
101+
$deferred->reject($this->mysqli->error);
90102
}
91103
else
92104
{
93105
if ($reject)
94106
{
95-
$deferred->reject(new \Exception($this->mysqli->error));
107+
$deferred->reject($this->mysqli->error);
96108
}
97109
}
98110
}
99111

100112
// If poll yielded something for this connection, we're done!
101113
if ($read || $error || $reject)
102114
{
115+
$this->currentQuery = false;
103116
$timer->cancel();
104117
}
105118
}

src/ConnectionFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class ConnectionFactory
77
/**
88
* @var LoopInterface
99
*/
10-
protected static $loop;
10+
public static $loop;
1111

1212
/**
1313
* @var array

src/ConnectionPool.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function __construct()
3636
/**
3737
* We use a promise in case all connections are busy.
3838
*
39-
* @return \React\Promise\PromiseInterface
39+
* @return \React\Promise\Promise
4040
*/
4141
public function getConnection()
4242
{

src/Database.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
class Database
66
{
7+
/**
8+
* @var ConnectionPool
9+
*/
710
protected $pool;
811

912
public function __construct()
@@ -25,7 +28,7 @@ public function createCommand($sql = null, $params = [])
2528

2629
/**
2730
* @param Command $command
28-
* @return \React\Promise\PromiseInterface
31+
* @return \React\Promise\Promise
2932
*/
3033
public function executeCommand(Command $command)
3134
{
@@ -44,6 +47,11 @@ public function executeCommand(Command $command)
4447
// Doesn't hurt to close it again.
4548
$result->close();
4649
})
50+
->otherwise(function ($reason) use ($deferred)
51+
{
52+
// If the connection execution fails, pass the failure back to the command.
53+
$deferred->reject($reason);
54+
})
4755
->always(function () use ($connection)
4856
{
4957
// Ensure we always return the connection to the pool.
@@ -53,4 +61,12 @@ public function executeCommand(Command $command)
5361

5462
return $deferred->promise();
5563
}
64+
65+
/**
66+
* @return ConnectionPool
67+
*/
68+
public function getPool()
69+
{
70+
return $this->pool;
71+
}
5672
}

0 commit comments

Comments
 (0)