packages/ztd-query-postgres/tests/Unit/Sql/Transaction/PgSqlTransactionStatementParserTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Sql\Transaction;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use ZtdQuery\Platform\Postgres\Sql\PgSqlLexerProfile;
12use ZtdQuery\Platform\Postgres\Sql\Transaction\PgSqlTransactionStatementParser;
13use ZtdQuery\Shadow\ShadowStore;
14use ZtdQuery\Shadow\ShadowTransactions;
15
16#[CoversClass(PgSqlTransactionStatementParser::class)]
17#[UsesClass(PgSqlLexerProfile::class)]
18#[CoversClass(\ZtdQuery\Platform\Postgres\Sql\Transaction\KeywordForm::class)]
19final class PgSqlTransactionStatementParserTest extends TestCase
20{
21 #[DataProvider('providerPostgresTransactionForms')]
22 public function testParsesPostgresTransactionForms(string $sql): void
23 {
24 self::assertNotNull((new PgSqlTransactionStatementParser())->parse($sql));
25 }
26
27 /**
28 * @return array<string, array{string}>
29 */
30 public static function providerPostgresTransactionForms(): array
31 {
32 return [
33 'begin' => ['BEGIN;'],
34 'begin work' => ['BEGIN WORK'],
35 'begin transaction' => ['BEGIN TRANSACTION'],
36 'start' => ['START TRANSACTION'],
37 'commit' => ['COMMIT'],
38 'commit work' => ['COMMIT WORK'],
39 'commit transaction' => ['COMMIT TRANSACTION'],
40 'end' => ['END'],
41 'end work' => ['END WORK'],
42 'end transaction' => ['END TRANSACTION'],
43 'rollback' => ['ROLLBACK'],
44 'rollback work' => ['ROLLBACK WORK'],
45 'rollback transaction' => ['ROLLBACK TRANSACTION'],
46 'savepoint' => ['SAVEPOINT "a""b"'],
47 'rollback to' => ['ROLLBACK TO point'],
48 'rollback to savepoint' => ['ROLLBACK TO SAVEPOINT point'],
49 'release' => ['RELEASE point'],
50 'release savepoint' => ['RELEASE SAVEPOINT point'],
51 ];
52 }
53
54 public function testRejectsNonPostgresAndMalformedForms(): void
55 {
56 $parser = new PgSqlTransactionStatementParser();
57
58 self::assertNull($parser->parse(''));
59 self::assertNull($parser->parse('BEGIN IMMEDIATE'));
60 self::assertNull($parser->parse('SAVEPOINT `point`'));
61 self::assertNull($parser->parse('SAVEPOINT point extra'));
62 self::assertNull($parser->parse('SAVEPOINT "broken'));
63 }
64
65 public function testAppliesUnescapedPostgresSavepointName(): void
66 {
67 $store = new ShadowStore();
68 $store->set('items', [['id' => 1]]);
69 $transactions = new ShadowTransactions($store);
70 $transactions->begin();
71 $statement = (new PgSqlTransactionStatementParser())->parse('SAVEPOINT "a""b"');
72 self::assertNotNull($statement);
73 $statement->apply($transactions);
74 $store->insert('items', [['id' => 2]]);
75
76 $transactions->rollBackTo('a"b');
77
78 self::assertSame([['id' => 1]], $store->get('items'));
79 }
80}
81