packages/ztd-query-core/tests/Unit/SessionTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use ZtdQuery\Schema\TableDefinition;
11use ZtdQuery\Schema\TableDefinitionRegistry;
12use ZtdQuery\Schema\ViewDefinitionSet;
13use ZtdQuery\Session;
14use ZtdQuery\Shadow\ShadowStore;
15use ZtdQuery\Shadow\ShadowTransactions;
16use ZtdQuery\Sql\TransactionStatement;
17
18#[CoversClass(Session::class)]
19#[UsesClass(\ZtdQuery\Schema\RowSet::class)]
20#[UsesClass(ShadowStore::class)]
21#[UsesClass(ShadowTransactions::class)]
22#[UsesClass(TableDefinitionRegistry::class)]
23#[UsesClass(ViewDefinitionSet::class)]
24#[UsesClass(TableDefinition::class)]
25#[UsesClass(\ZtdQuery\Schema\Key\CandidateKeySet::class)]
26#[UsesClass(\ZtdQuery\Shadow\ShadowSavepoint::class)]
27#[UsesClass(TransactionStatement::class)]
28final class SessionTest extends TestCase
29{
30 public function testStoreRegistryViewsAndTableDefinitionBelongToOneSession(): void
31 {
32 $first = new Session();
33 $second = new Session();
34 $definition = new TableDefinition(['id'], ['id' => 'INTEGER'], ['id'], ['id'], []);
35 $first->registry()->register('items', $definition);
36 $first->store()->set('items', [['id' => 1]]);
37 self::assertSame($definition, $first->tableDefinition('items'));
38 self::assertNull($second->tableDefinition('items'));
39 self::assertSame([], $second->store()->get('items'));
40 self::assertNotSame($first->views(), $second->views());
41 }
42
43 public function testEnableDisableAndIsEnabledDoNotDiscardFixtures(): void
44 {
45 $session = new Session();
46 $session->store()->set('items', [['id' => 1]]);
47 $session->disable();
48 self::assertFalse($session->isEnabled());
49 $session->enable();
50 self::assertTrue($session->isEnabled());
51 self::assertSame([['id' => 1]], $session->store()->get('items'));
52 }
53
54 public function testBeginTransactionAndRollBackTransactionRestoreRowsAndSchema(): void
55 {
56 $session = new Session();
57 $definition = new TableDefinition(['id'], ['id' => 'INTEGER'], ['id'], ['id'], []);
58 $session->registry()->register('items', $definition);
59 $session->store()->set('items', [['id' => 1]]);
60 $session->beginTransaction();
61 $session->registry()->unregister('items');
62 $session->store()->set('items', [['id' => 2]]);
63 $session->rollBackTransaction();
64 self::assertSame($definition, $session->tableDefinition('items'));
65 self::assertSame([['id' => 1]], $session->store()->get('items'));
66 }
67
68 public function testCommitTransactionKeepsVirtualWrites(): void
69 {
70 $session = new Session();
71 $session->beginTransaction();
72 $session->store()->set('items', [['id' => 1]]);
73 $session->commitTransaction();
74 $session->rollBackTransaction();
75 self::assertSame([['id' => 1]], $session->store()->get('items'));
76 }
77
78 public function testTransactionsAndApplyTransactionStatementShareTheSameSnapshots(): void
79 {
80 $session = new Session();
81 $session->applyTransactionStatement(TransactionStatement::begin());
82 $session->transactions()->savepoint('before_write');
83 $session->store()->set('items', [['id' => 1]]);
84 $session->transactions()->rollBackTo('before_write');
85 self::assertSame([], $session->store()->get('items'));
86 }
87
88 public function testRememberInsertIdAndLastInsertIdRetainTheLastGeneratedIdentity(): void
89 {
90 $session = new Session();
91 self::assertFalse($session->lastInsertId());
92 $session->rememberInsertId('42');
93 $session->rememberInsertId(null);
94 self::assertSame('42', $session->lastInsertId());
95 }
96
97 public function testRegistryReturnsTheSuppliedVirtualCatalog(): void
98 {
99 $registry = new TableDefinitionRegistry();
100 self::assertSame($registry, (new Session(registry: $registry))->registry());
101 }
102
103 public function testViewsReturnsTheSuppliedViewDefinitions(): void
104 {
105 $views = new ViewDefinitionSet();
106 self::assertSame($views, (new Session(views: $views))->views());
107 }
108
109 public function testTableDefinitionSeesCatalogChanges(): void
110 {
111 $session = new Session();
112 $definition = new TableDefinition(['id'], ['id' => 'INTEGER'], ['id'], ['id'], []);
113 $session->registry()->register('items', $definition);
114 self::assertSame($definition, $session->tableDefinition('items'));
115 $session->registry()->unregister('items');
116 self::assertNull($session->tableDefinition('items'));
117 }
118
119 public function testDisableLeavesOtherSessionsEnabled(): void
120 {
121 $first = new Session();
122 $second = new Session();
123 $first->disable();
124 self::assertFalse($first->isEnabled());
125 self::assertTrue($second->isEnabled());
126 }
127
128 public function testIsEnabledStartsTrueForNewSessions(): void
129 {
130 self::assertTrue((new Session())->isEnabled());
131 }
132
133 public function testRollBackTransactionWithoutATransactionKeepsFixtures(): void
134 {
135 $session = new Session();
136 $session->store()->set('items', [['id' => 1]]);
137 $session->rollBackTransaction();
138 self::assertSame([['id' => 1]], $session->store()->get('items'));
139 }
140
141 public function testApplyTransactionStatementRollsBackVirtualWrites(): void
142 {
143 $session = new Session();
144 $session->applyTransactionStatement(TransactionStatement::begin());
145 $session->store()->set('items', [['id' => 1]]);
146 $session->applyTransactionStatement(TransactionStatement::rollback());
147 self::assertSame([], $session->store()->get('items'));
148 }
149
150 public function testLastInsertIdDoesNotLeakBetweenSessions(): void
151 {
152 $first = new Session();
153 $second = new Session();
154 $first->rememberInsertId('7');
155 self::assertFalse($second->lastInsertId());
156 }
157}
158