packages/ztd-query-core/tests/Unit/Sql/TransactionStatementTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Sql;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use ZtdQuery\Shadow\ShadowStore;
11use ZtdQuery\Shadow\ShadowTransactions;
12use ZtdQuery\Sql\TransactionStatement;
13
14#[CoversClass(TransactionStatement::class)]
15#[UsesClass(ShadowStore::class)]
16#[UsesClass(ShadowTransactions::class)]
17#[UsesClass(\ZtdQuery\Shadow\ShadowSavepoint::class)]
18#[UsesClass(\ZtdQuery\Schema\RowSet::class)]
19final class TransactionStatementTest extends TestCase
20{
21 public function testReleaseCommitAppliesNamedTransactionLifecycleWithoutSql(): void
22 {
23 $store = new ShadowStore();
24 $store->set('items', [['id' => 1]]);
25 $transactions = new ShadowTransactions($store);
26
27 TransactionStatement::begin()->apply($transactions);
28 $store->insert('items', [['id' => 2]]);
29 TransactionStatement::savepoint('order item')->apply($transactions);
30 $store->insert('items', [['id' => 3]]);
31 TransactionStatement::rollbackTo('order item')->apply($transactions);
32 TransactionStatement::release('order item')->apply($transactions);
33 TransactionStatement::commit()->apply($transactions);
34
35 self::assertSame([['id' => 1], ['id' => 2]], $store->get('items'));
36 }
37
38 public function testRollbackAppliesRollback(): void
39 {
40 $store = new ShadowStore();
41 $store->set('items', [['id' => 1]]);
42 $transactions = new ShadowTransactions($store);
43
44 TransactionStatement::begin()->apply($transactions);
45 $store->insert('items', [['id' => 2]]);
46 TransactionStatement::rollback()->apply($transactions);
47
48 self::assertSame([['id' => 1]], $store->get('items'));
49 }
50
51 public function testBeginStartsATransactionARollbackCanGoBackTo(): void
52 {
53 $store = new ShadowStore();
54 $store->set('order', [['id' => 1]]);
55 $transactions = new ShadowTransactions($store);
56
57 TransactionStatement::begin()->apply($transactions);
58 $store->set('order', []);
59 TransactionStatement::rollback()->apply($transactions);
60
61 self::assertSame([['id' => 1]], $store->get('order'));
62 }
63
64 public function testCommitKeepsEverythingTheTransactionDid(): void
65 {
66 $store = new ShadowStore();
67 $store->set('order', [['id' => 1]]);
68 $transactions = new ShadowTransactions($store);
69
70 TransactionStatement::begin()->apply($transactions);
71 $store->set('order', []);
72 TransactionStatement::commit()->apply($transactions);
73 TransactionStatement::rollback()->apply($transactions);
74
75 self::assertSame([], $store->get('order'));
76 }
77
78 public function testRollbackToGoesBackToTheSavepointAndLeavesItDeclared(): void
79 {
80 $store = new ShadowStore();
81 $transactions = new ShadowTransactions($store);
82 TransactionStatement::begin()->apply($transactions);
83 $store->set('order', [['id' => 1]]);
84 TransactionStatement::savepoint('sp1')->apply($transactions);
85 $store->set('order', []);
86
87 TransactionStatement::rollbackTo('sp1')->apply($transactions);
88
89 self::assertSame([['id' => 1]], $store->get('order'));
90 self::assertNotNull($transactions->positionOf('sp1'));
91 }
92
93 public function testApplyDoesWhatEachOperationSays(): void
94 {
95 $store = new ShadowStore();
96 $transactions = new ShadowTransactions($store);
97 TransactionStatement::begin()->apply($transactions);
98 TransactionStatement::savepoint('sp1')->apply($transactions);
99
100 TransactionStatement::release('sp1')->apply($transactions);
101
102 self::assertNull($transactions->positionOf('sp1'));
103 }
104 public function testRequiredNameAnswersTheNameTheStatementCarried(): void
105 {
106 self::assertSame('sp1', TransactionStatement::requiredName('sp1'));
107 }
108
109 public function testSavepointPreservesTheNamedTransactionBoundary(): void
110 {
111 $statement = TransactionStatement::savepoint('before_update');
112
113 $transactions = new ShadowTransactions(new ShadowStore());
114 $transactions->begin();
115 $statement->apply($transactions);
116
117 self::assertSame(1, $transactions->positionOf('before_update'));
118 }
119
120}
121