packages/ztd-query-mysql/tests/Unit/Sql/Transaction/MySqlTransactionStatementParserTest.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\MySql\Sql\MySqlLexerProfile;
12use ZtdQuery\Platform\MySql\Sql\Transaction\MySqlTransactionStatementParser;
13use ZtdQuery\Shadow\ShadowStore;
14use ZtdQuery\Shadow\ShadowTransactions;
15
16#[CoversClass(MySqlTransactionStatementParser::class)]
17#[UsesClass(MySqlLexerProfile::class)]
18#[CoversClass(\ZtdQuery\Platform\MySql\Sql\Transaction\TokenReader::class)]
19final class MySqlTransactionStatementParserTest extends TestCase
20{
21    #[DataProvider('providerMySqlTransactionForms')]
22    public function testParsesMySqlTransactionForms(string $sql): void
23    {
24        self::assertNotNull((new MySqlTransactionStatementParser())->parse($sql));
25    }
26
27    /**
28
29     * @return array<string, array{string}>
30
31     */
32    public static function providerMySqlTransactionForms(): array
33    {
34        return [
35            'begin' => ['BEGIN;'],
36            'begin work' => ['BEGIN WORK'],
37            'start' => ['START TRANSACTION'],
38            'commit' => ['COMMIT'],
39            'commit work' => ['COMMIT WORK'],
40            'rollback' => ['ROLLBACK'],
41            'rollback work' => ['ROLLBACK WORK'],
42            'savepoint' => ['SAVEPOINT `a``b`'],
43            'rollback to' => ['ROLLBACK TO `a``b`'],
44            'rollback to savepoint' => ['ROLLBACK TO SAVEPOINT point'],
45            'release' => ['RELEASE SAVEPOINT point'],
46        ];
47    }
48
49    public function testRejectsNonMySqlAndMalformedForms(): void
50    {
51        $parser = new MySqlTransactionStatementParser();
52
53        self::assertNull($parser->parse(''));
54        self::assertNull($parser->parse('BEGIN IMMEDIATE'));
55        self::assertNull($parser->parse('END TRANSACTION'));
56        self::assertNull($parser->parse('RELEASE point'));
57        self::assertNull($parser->parse('SAVEPOINT point extra'));
58        self::assertNull($parser->parse('SAVEPOINT `broken'));
59    }
60
61    public function testAppliesUnescapedMySqlSavepointName(): void
62    {
63        $store = new ShadowStore();
64        $store->set('items', [['id' => 1]]);
65        $transactions = new ShadowTransactions($store);
66        $transactions->begin();
67        $statement = (new MySqlTransactionStatementParser())->parse('SAVEPOINT `a``b`');
68        self::assertNotNull($statement);
69        $statement->apply($transactions);
70        $store->insert('items', [['id' => 2]]);
71
72        $transactions->rollBackTo('a`b');
73
74        self::assertSame([['id' => 1]], $store->get('items'));
75    }
76}
77