Skip to content

Commit 6fcbb06

Browse files
exaby73transistive
authored andcommitted
feat: Add transaction state
1 parent 108ccb6 commit 6fcbb06

File tree

5 files changed

+110
-56
lines changed

5 files changed

+110
-56
lines changed

docker-compose.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: '3.8'
2-
31
x-definitions:
42
x-shared-env:
53
&common-env

src/Bolt/BoltUnmanagedTransaction.php

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
use Laudis\Neo4j\Databags\SessionConfiguration;
2121
use Laudis\Neo4j\Databags\Statement;
2222
use Laudis\Neo4j\Databags\TransactionConfiguration;
23+
use Laudis\Neo4j\Enum\TransactionState;
24+
use Laudis\Neo4j\Exception\ClientException;
2325
use Laudis\Neo4j\Exception\Neo4jException;
2426
use Laudis\Neo4j\ParameterHelper;
2527
use Laudis\Neo4j\Types\AbstractCypherSequence;
@@ -40,9 +42,7 @@
4042
*/
4143
final class BoltUnmanagedTransaction implements UnmanagedTransactionInterface
4244
{
43-
private bool $isRolledBack = false;
44-
45-
private bool $isCommitted = false;
45+
private TransactionState $state = TransactionState::ACTIVE;
4646

4747
/**
4848
* @param FormatterInterface<T> $formatter
@@ -59,10 +59,26 @@ public function __construct(
5959
private readonly SessionConfiguration $config,
6060
private readonly TransactionConfiguration $tsxConfig,
6161
private readonly BookmarkHolder $bookmarkHolder
62-
) {}
62+
) {
63+
}
6364

65+
/**
66+
* @throws ClientException|Throwable
67+
*/
6468
public function commit(iterable $statements = []): CypherList
6569
{
70+
if ($this->isFinished()) {
71+
switch ($this->state) {
72+
case TransactionState::TERMINATED:
73+
throw new ClientException("Can't commit, transaction has been terminated");
74+
case TransactionState::COMMITTED:
75+
throw new ClientException("Can't commit, transaction has already been committed");
76+
case TransactionState::ROLLED_BACK:
77+
throw new ClientException("Can't commit, transaction has already been rolled back");
78+
default:
79+
}
80+
}
81+
6682
// Force the results to pull all the results.
6783
// After a commit, the connection will be in the ready state, making it impossible to use PULL
6884
$tbr = $this->runStatements($statements)->each(static function ($list) {
@@ -72,15 +88,15 @@ public function commit(iterable $statements = []): CypherList
7288
});
7389

7490
$this->connection->commit();
75-
$this->isCommitted = true;
91+
$this->state = TransactionState::COMMITTED;
7692

7793
return $tbr;
7894
}
7995

8096
public function rollback(): void
8197
{
8298
$this->connection->rollback();
83-
$this->isRolledBack = true;
99+
$this->state = TransactionState::ROLLED_BACK;
84100
}
85101

86102
/**
@@ -109,7 +125,7 @@ public function runStatement(Statement $statement)
109125
$this->config->getAccessMode()
110126
);
111127
} catch (Throwable $e) {
112-
$this->isRolledBack = true;
128+
$this->state = TransactionState::TERMINATED;
113129
throw $e;
114130
}
115131
$run = microtime(true);
@@ -140,35 +156,40 @@ public function runStatements(iterable $statements): CypherList
140156
}
141157

142158
/**
143-
* @throws Neo4jException
159+
* @param Neo4jException $e
144160
*
145161
* @return never
162+
* @throws Neo4jException
163+
*
146164
*/
147-
private function handleMessageException(Neo4jException $e): void
165+
private function handleMessageException(Neo4jException $e): never
148166
{
149167
$exception = $e->getErrors()[0];
150168
if (!($exception->getClassification() === 'ClientError' && $exception->getCategory() === 'Request')) {
151169
$this->connection->reset();
152170
}
153-
if (!$this->isFinished() && in_array($exception->getClassification(), TransactionHelper::ROLLBACK_CLASSIFICATIONS)) {
154-
$this->isRolledBack = true;
171+
if (!$this->isFinished() && in_array(
172+
$exception->getClassification(),
173+
TransactionHelper::ROLLBACK_CLASSIFICATIONS
174+
)) {
175+
$this->state = TransactionState::ROLLED_BACK;
155176
}
156177

157178
throw $e;
158179
}
159180

160181
public function isRolledBack(): bool
161182
{
162-
return $this->isRolledBack;
183+
return $this->state == TransactionState::ROLLED_BACK;
163184
}
164185

165186
public function isCommitted(): bool
166187
{
167-
return $this->isCommitted;
188+
return $this->state == TransactionState::COMMITTED;
168189
}
169190

170191
public function isFinished(): bool
171192
{
172-
return $this->isRolledBack() || $this->isCommitted();
193+
return $this->state != TransactionState::ACTIVE;
173194
}
174195
}

src/Enum/TransactionEffect.php

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

src/Enum/TransactionState.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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\Enum;
15+
16+
/**
17+
* The state of a transaction.
18+
*/
19+
enum TransactionState {
20+
/**
21+
* The transaction is running with no explicit success or failure marked
22+
*/
23+
case ACTIVE;
24+
25+
/**
26+
* This transaction has been terminated because of a fatal connection error.
27+
*/
28+
case TERMINATED;
29+
30+
/**
31+
* This transaction has successfully committed
32+
*/
33+
case COMMITTED;
34+
35+
/**
36+
* This transaction has been rolled back
37+
*/
38+
case ROLLED_BACK;
39+
}

src/Exception/ClientException.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
use Throwable;
18+
19+
/**
20+
* Exception when a Client Error occurs.
21+
*
22+
* @psalm-immutable
23+
*
24+
* @psalm-suppress MutableDependency
25+
*/
26+
final class ClientException extends RuntimeException
27+
{
28+
/**
29+
* @param string $message
30+
* @param Throwable|null $previous
31+
*/
32+
public function __construct(string $message, ?Throwable $previous = null)
33+
{
34+
parent::__construct($message, 0, $previous);
35+
}
36+
}

0 commit comments

Comments
 (0)