Skip to content

Commit 630f12c

Browse files
committed
temp commit
1 parent 85ced5a commit 630f12c

File tree

12 files changed

+361
-194
lines changed

12 files changed

+361
-194
lines changed

src/Bolt/Session.php

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
use Exception;
1717
use Laudis\Neo4j\Common\GeneratorHelper;
1818
use Laudis\Neo4j\Common\Neo4jLogger;
19-
use Laudis\Neo4j\Common\TransactionHelper;
2019
use Laudis\Neo4j\Contracts\ConnectionPoolInterface;
20+
use Laudis\Neo4j\Contracts\CypherSequence;
2121
use Laudis\Neo4j\Contracts\SessionInterface;
2222
use Laudis\Neo4j\Contracts\TransactionInterface;
2323
use Laudis\Neo4j\Contracts\UnmanagedTransactionInterface;
@@ -39,6 +39,8 @@
3939
*/
4040
final class Session implements SessionInterface
4141
{
42+
private const ROLLBACK_CLASSIFICATIONS = ['ClientError', 'TransientError', 'DatabaseError'];
43+
4244
/** @var list<BoltConnection> */
4345
private array $usedConnections = [];
4446
/** @psalm-readonly */
@@ -101,23 +103,58 @@ public function writeTransaction(callable $tsxHandler, ?TransactionConfiguration
101103
$this->getLogger()?->log(LogLevel::INFO, 'Beginning write transaction', ['config' => $config]);
102104
$config = $this->mergeTsxConfig($config);
103105

104-
return TransactionHelper::retry(
105-
fn () => $this->startTransaction($config, $this->config->withAccessMode(AccessMode::WRITE())),
106-
$tsxHandler
107-
);
106+
return $this->retry($tsxHandler, false, $config);
108107
}
109108

110109
public function readTransaction(callable $tsxHandler, ?TransactionConfiguration $config = null)
111110
{
112111
$this->getLogger()?->log(LogLevel::INFO, 'Beginning read transaction', ['config' => $config]);
113112
$config = $this->mergeTsxConfig($config);
114113

115-
return TransactionHelper::retry(
116-
fn () => $this->startTransaction($config, $this->config->withAccessMode(AccessMode::READ())),
117-
$tsxHandler
118-
);
114+
return $this->retry($tsxHandler, false, $config);
115+
}
116+
/**
117+
* @template U
118+
*
119+
* @param callable(TransactionInterface):U $tsxHandler
120+
*
121+
* @return U
122+
*/
123+
private function retry(callable $tsxHandler, bool $read, TransactionConfiguration $config)
124+
{
125+
while (true) {
126+
$transaction = null;
127+
try {
128+
if ($read) {
129+
$transaction = $this->startTransaction($config, $this->config->withAccessMode(AccessMode::READ()));
130+
} else {
131+
$transaction = $this->startTransaction($config, $this->config->withAccessMode(AccessMode::WRITE()));
132+
}
133+
$tbr = $tsxHandler($transaction);
134+
self::triggerLazyResult($tbr);
135+
$transaction->commit();
136+
137+
return $tbr;
138+
} catch (Neo4jException $e) {
139+
if ($transaction && !in_array($e->getClassification(), self::ROLLBACK_CLASSIFICATIONS)) {
140+
$transaction->rollback();
141+
}
142+
143+
if ($e->getTitle() === 'NotALeader') {
144+
// By closing the pool, we force the connection to be re-acquired and the routing table to be refetched
145+
$this->pool->close();
146+
} elseif ($e->getClassification() !== 'TransientError') {
147+
throw $e;
148+
}
149+
}
150+
}
151+
}
152+
private static function triggerLazyResult(mixed $tbr): void
153+
{
154+
if ($tbr instanceof CypherSequence) {
155+
$tbr->preload();
156+
}
119157
}
120-
121158
public function transaction(callable $tsxHandler, ?TransactionConfiguration $config = null)
122159
{
123160
return $this->writeTransaction($tsxHandler, $config);

src/Common/TransactionHelper.php

Lines changed: 0 additions & 62 deletions
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Neo4j PHP Client and Driver package.
7+
*
8+
* (c) Nagels <https://nagels.tech>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Laudis\Neo4j\Exception;
15+
16+
use RuntimeException;
17+
18+
final class SSLConnectionException extends RuntimeException
19+
{
20+
}

src/Exception/TimeoutException.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Neo4j PHP Client and Driver package.
7+
*
8+
* (c) Nagels <https://nagels.tech>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Laudis\Neo4j\Exception;
15+
16+
use RuntimeException;
17+
18+
class TimeoutException extends RuntimeException
19+
{
20+
}

testkit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 9057529dbc3f71c05dd557caa0e2245267100413

testkit-backend/src/Handlers/AbstractRunner.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function handle($request): ResultResponse|DriverErrorResponse
5959
$params = [];
6060
if ($request->getParams() !== null) {
6161
foreach ($request->getParams() as $key => $value) {
62-
$params[$key] = $this->decodeToValue($value);
62+
$params[$key] = self::decodeToValue($value);
6363
}
6464
}
6565

@@ -68,7 +68,7 @@ public function handle($request): ResultResponse|DriverErrorResponse
6868
$actualMeta = [];
6969
if ($metaData !== null) {
7070
foreach ($metaData as $key => $meta) {
71-
$actualMeta[$key] = $this->decodeToValue($meta);
71+
$actualMeta[$key] = self::decodeToValue($meta);
7272
}
7373
}
7474
$config = TransactionConfiguration::default()->withMetadata($actualMeta)->withTimeout($request->getTimeout());
@@ -105,7 +105,7 @@ public function handle($request): ResultResponse|DriverErrorResponse
105105
*
106106
* @return scalar|AbstractCypherObject|iterable|null
107107
*/
108-
private function decodeToValue(array $param)
108+
public static function decodeToValue(array $param)
109109
{
110110
$value = $param['data']['value'];
111111
if (is_iterable($value)) {
@@ -118,7 +118,7 @@ private function decodeToValue(array $param)
118118
*/
119119
foreach ($value as $k => $v) {
120120
/** @psalm-suppress MixedArgument */
121-
$map[(string) $k] = $this->decodeToValue($v);
121+
$map[(string) $k] = self::decodeToValue($v);
122122
}
123123

124124
return new CypherMap($map);
@@ -131,7 +131,7 @@ private function decodeToValue(array $param)
131131
*/
132132
foreach ($value as $v) {
133133
/** @psalm-suppress MixedArgument */
134-
$list[] = $this->decodeToValue($v);
134+
$list[] = self::decodeToValue($v);
135135
}
136136

137137
return new CypherList($list);

testkit-backend/src/Handlers/SessionBeginTransaction.php

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function handle($request): TestkitResponseInterface
5959
$actualMeta = [];
6060
if ($metaData !== null) {
6161
foreach ($metaData as $key => $meta) {
62-
$actualMeta[$key] = $this->decodeToValue($meta);
62+
$actualMeta[$key] = AbstractRunner::decodeToValue($meta);
6363
}
6464
}
6565
$config = $config->withMetaData($actualMeta);
@@ -80,45 +80,4 @@ public function handle($request): TestkitResponseInterface
8080

8181
return new TransactionResponse($id);
8282
}
83-
84-
/**
85-
* @param array{name: string, data: array{value: iterable|scalar|null}} $param
86-
*
87-
* @return scalar|AbstractCypherObject|iterable|null
88-
*/
89-
private function decodeToValue(array $param)
90-
{
91-
$value = $param['data']['value'];
92-
if (is_iterable($value)) {
93-
if ($param['name'] === 'CypherMap') {
94-
/** @psalm-suppress MixedArgumentTypeCoercion */
95-
$map = [];
96-
/**
97-
* @var numeric $k
98-
* @var mixed $v
99-
*/
100-
foreach ($value as $k => $v) {
101-
/** @psalm-suppress MixedArgument */
102-
$map[(string) $k] = $this->decodeToValue($v);
103-
}
104-
105-
return new CypherMap($map);
106-
}
107-
108-
if ($param['name'] === 'CypherList') {
109-
$list = [];
110-
/**
111-
* @var mixed $v
112-
*/
113-
foreach ($value as $v) {
114-
/** @psalm-suppress MixedArgument */
115-
$list[] = $this->decodeToValue($v);
116-
}
117-
118-
return new CypherList($list);
119-
}
120-
}
121-
122-
return $value;
123-
}
12483
}

testkit-backend/src/Handlers/SessionReadTransaction.php

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function handle($request): TestkitResponseInterface
5555
$actualMeta = [];
5656
if ($metaData !== null) {
5757
foreach ($metaData as $key => $meta) {
58-
$actualMeta[$key] = $this->decodeToValue($meta);
58+
$actualMeta[$key] = AbstractRunner::decodeToValue($meta);
5959
}
6060
}
6161
$config = $config->withMetaData($actualMeta);
@@ -79,41 +79,4 @@ public function handle($request): TestkitResponseInterface
7979

8080
return new RetryableTryResponse($id);
8181
}
82-
83-
// f1aa000cede64d6a8879513c97633777
84-
private function decodeToValue(array $param)
85-
{
86-
$value = $param['data']['value'];
87-
if (is_iterable($value)) {
88-
if ($param['name'] === 'CypherMap') {
89-
/** @psalm-suppress MixedArgumentTypeCoercion */
90-
$map = [];
91-
/**
92-
* @var numeric $k
93-
* @var mixed $v
94-
*/
95-
foreach ($value as $k => $v) {
96-
/** @psalm-suppress MixedArgument */
97-
$map[(string) $k] = $this->decodeToValue($v);
98-
}
99-
100-
return new CypherMap($map);
101-
}
102-
103-
if ($param['name'] === 'CypherList') {
104-
$list = [];
105-
/**
106-
* @var mixed $v
107-
*/
108-
foreach ($value as $v) {
109-
/** @psalm-suppress MixedArgument */
110-
$list[] = $this->decodeToValue($v);
111-
}
112-
113-
return new CypherList($list);
114-
}
115-
}
116-
117-
return $value;
118-
}
11982
}

testkit-backend/src/Handlers/SessionWriteTransaction.php

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function handle($request): TestkitResponseInterface
5555
$actualMeta = [];
5656
if ($metaData !== null) {
5757
foreach ($metaData as $key => $meta) {
58-
$actualMeta[$key] = $this->decodeToValue($meta);
58+
$actualMeta[$key] = AbstractRunner::decodeToValue($meta);
5959
}
6060
}
6161
$config = $config->withMetaData($actualMeta);
@@ -79,40 +79,4 @@ public function handle($request): TestkitResponseInterface
7979

8080
return new RetryableTryResponse($id);
8181
}
82-
83-
private function decodeToValue(array $param)
84-
{
85-
$value = $param['data']['value'];
86-
if (is_iterable($value)) {
87-
if ($param['name'] === 'CypherMap') {
88-
/** @psalm-suppress MixedArgumentTypeCoercion */
89-
$map = [];
90-
/**
91-
* @var numeric $k
92-
* @var mixed $v
93-
*/
94-
foreach ($value as $k => $v) {
95-
/** @psalm-suppress MixedArgument */
96-
$map[(string) $k] = $this->decodeToValue($v);
97-
}
98-
99-
return new CypherMap($map);
100-
}
101-
102-
if ($param['name'] === 'CypherList') {
103-
$list = [];
104-
/**
105-
* @var mixed $v
106-
*/
107-
foreach ($value as $v) {
108-
/** @psalm-suppress MixedArgument */
109-
$list[] = $this->decodeToValue($v);
110-
}
111-
112-
return new CypherList($list);
113-
}
114-
}
115-
116-
return $value;
117-
}
11882
}

0 commit comments

Comments
 (0)