Skip to content

Commit b55e08f

Browse files
authored
Merge pull request #21 from WyriHaximus/extended-middleware
Extended Middleware
2 parents e09eea4 + fc0f8fc commit b55e08f

13 files changed

+372
-126
lines changed

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
"react/dns": "^0.4.17 || ^1.0.0",
2222
"roave/better-reflection": "^3.5",
2323
"voryx/pgasync": "^2.0",
24+
"wyrihaximus/constants": "^1.1",
2425
"wyrihaximus/doctrine-annotation-autoloader": "^1.0",
2526
"wyrihaximus/iterator-or-array-to-array": "^1.1"
2627
},
2728
"require-dev": {
2829
"robmorgan/phinx": "^0.10.7 || ^0.11.0",
30+
"thecodingmachine/safe": "^0.1.16",
2931
"vlucas/phpdotenv": "^3.3",
3032
"wyrihaximus/async-test-utilities": "^1.1"
3133
},

composer.lock

Lines changed: 38 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

infection.json.dist

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
"WyriHaximus\\React\\SimpleORM\\Repository::translateFieldName"
3434
]
3535
},
36+
"Increment": {
37+
"ignore": [
38+
"WyriHaximus\\React\\SimpleORM\\Middleware\\QueryCountMiddleware::query"
39+
]
40+
},
3641
"OneZeroInteger": {
3742
"ignore": [
3843
"WyriHaximus\\React\\SimpleORM\\Repository::count",

src/Client.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
use PgAsync\Client as PgClient;
88
use Plasma\SQL\Grammar\PostgreSQL;
99
use Plasma\SQL\QueryBuilder;
10+
use React\Promise\PromiseInterface;
1011
use Rx\Observable;
1112
use WyriHaximus\React\SimpleORM\Middleware\ExecuteQueryMiddleware;
1213
use WyriHaximus\React\SimpleORM\Middleware\GrammarMiddleware;
1314
use function ApiClients\Tools\Rx\unwrapObservableFromPromise;
15+
use function React\Promise\resolve;
1416

1517
final class Client implements ClientInterface
1618
{
@@ -51,7 +53,6 @@ private function __construct(PgClient $client, Reader $annotationReader, Middlew
5153
$this->entityInspector = new EntityInspector($annotationReader);
5254

5355
$middleware[] = new GrammarMiddleware(new PostgreSQL());
54-
$middleware[] = new ExecuteQueryMiddleware($this->client);
5556

5657
$this->middlewareRunner = new MiddlewareRunner(...$middleware);
5758
}
@@ -67,6 +68,12 @@ public function getRepository(string $entity): RepositoryInterface
6768

6869
public function query(QueryBuilder $query): Observable
6970
{
70-
return unwrapObservableFromPromise($this->middlewareRunner->query($query));
71+
return unwrapObservableFromPromise($this->middlewareRunner->query(
72+
$query,
73+
function (QueryBuilder $query): PromiseInterface
74+
{
75+
return resolve($this->client->executeStatement($query->getQuery(), $query->getParameters()));
76+
}
77+
));
7178
}
7279
}

src/Middleware/ExecuteQueryMiddleware.php

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/Middleware/GrammarMiddleware.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ public function __construct(GrammarInterface $grammer)
1818
$this->grammer = $grammer;
1919
}
2020

21-
public function query(QueryBuilder $query): PromiseInterface
21+
public function query(QueryBuilder $query, callable $next): PromiseInterface
2222
{
23-
return resolve($query->withGrammar($this->grammer));
23+
return resolve($next($query->withGrammar($this->grammer)));
2424
}
2525
}

src/Middleware/QueryCountMiddleware.php

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,74 @@
55
use PgAsync\Client as PgClient;
66
use Plasma\SQL\QueryBuilder;
77
use React\Promise\PromiseInterface;
8+
use Rx\Observable;
9+
use Throwable;
810
use WyriHaximus\React\SimpleORM\MiddlewareInterface;
11+
use function React\Promise\reject;
912
use function React\Promise\resolve;
1013

1114
final class QueryCountMiddleware implements MiddlewareInterface
1215
{
1316
private const ZERO = 0;
1417

1518
/** @var int */
16-
private $count = self::ZERO;
19+
private $initiatedCount = self::ZERO;
1720

18-
public function query(QueryBuilder $query): PromiseInterface
21+
/** @var int */
22+
private $successfulCount = self::ZERO;
23+
24+
/** @var int */
25+
private $erroredCount = self::ZERO;
26+
27+
/** @var int */
28+
private $slowCount = self::ZERO;
29+
30+
/** @var int */
31+
private $slowQueryTime;
32+
33+
public function __construct(int $slowQueryTime)
1934
{
20-
$this->count++;
35+
$this->slowQueryTime = $slowQueryTime;
36+
}
37+
38+
public function query(QueryBuilder $query, callable $next): PromiseInterface
39+
{
40+
$this->initiatedCount++;
41+
42+
$startTime = hrtime()[0];
43+
44+
return resolve($next($query))->then(function (Observable $observable) use ($startTime): PromiseInterface {
45+
$this->successfulCount++;
46+
47+
if (hrtime()[0] - $startTime > $this->slowQueryTime) {
48+
$this->slowCount++;
49+
}
50+
51+
return resolve($observable);
52+
}, function (Throwable $throwable) use ($startTime): PromiseInterface {
53+
$this->erroredCount++;
54+
55+
if (hrtime()[0] - $startTime > $this->slowQueryTime) {
56+
$this->slowCount++;
57+
}
2158

22-
return resolve($query);
59+
return reject($throwable);
60+
});
2361
}
2462

25-
public function getCount(): int
63+
public function getCounters(): iterable
2664
{
27-
return $this->count;
65+
yield 'initiated' => $this->initiatedCount;
66+
yield 'successful' => $this->successfulCount;
67+
yield 'errored' => $this->erroredCount;
68+
yield 'slow' => $this->slowCount;
2869
}
2970

30-
public function resetCount(): void
71+
public function resetCounters(): void
3172
{
32-
$this->count = 0;
73+
$this->initiatedCount = self::ZERO;
74+
$this->successfulCount = self::ZERO;
75+
$this->erroredCount = self::ZERO;
76+
$this->slowCount = self::ZERO;
3377
}
3478
}

src/MiddlewareInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ interface MiddlewareInterface
1111
* Returns the (modified) query through a promise.
1212
*
1313
* @param QueryBuilder $query
14+
* @param callable $next
1415
*
1516
* @return PromiseInterface
1617
*/
17-
public function query(QueryBuilder $query): PromiseInterface;
18+
public function query(QueryBuilder $query, callable $next): PromiseInterface;
1819
}

src/MiddlewareRunner.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
use Plasma\SQL\QueryBuilder;
66
use Psr\Http\Message\ServerRequestInterface;
77
use React\Promise\PromiseInterface;
8+
use const WyriHaximus\Constants\Numeric\ONE;
9+
use const WyriHaximus\Constants\Numeric\ZERO;
10+
11+
/**
12+
* @internal
13+
*/
814

915
final class MiddlewareRunner
1016
{
@@ -19,20 +25,20 @@ public function __construct(MiddlewareInterface ...$middleware)
1925
$this->middleware = $middleware;
2026
}
2127

22-
public function query(QueryBuilder $query): PromiseInterface
28+
public function query(QueryBuilder $query, callable $last): PromiseInterface
2329
{
24-
return $this->call($query, 0);
30+
return $this->call($query, ZERO, $last);
2531
}
2632

27-
private function call(QueryBuilder $query, int $position): PromiseInterface
33+
private function call(QueryBuilder $query, int $position, callable $last): PromiseInterface
2834
{
2935
// final request handler will be invoked without hooking into the promise
30-
if (!array_key_exists($position + 1, $this->middleware)) {
31-
return $this->middleware[$position]->query($query);
36+
if (!array_key_exists($position + ONE, $this->middleware)) {
37+
return $this->middleware[$position]->query($query, $last);
3238
}
3339

34-
return $this->middleware[$position]->query($query)->then(function (QueryBuilder $query) use ($position) {
35-
return $this->call($query, $position + 1);
40+
return $this->middleware[$position]->query($query, function (QueryBuilder $query) use ($position, $last) {
41+
return $this->call($query, $position + ONE, $last);
3642
});
3743
}
3844
}

0 commit comments

Comments
 (0)