packages/sql-faker/tests/Unit/PostgreSql/Generation/Rewrite/Query/IntoClauseRuleTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\PostgreSql\Generation\Rewrite\Query;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFaker\Generation\Token\ProductionOccurrence;
12use SqlFaker\Generation\Token\TerminalOccurrence;
13use SqlFaker\Generation\Token\TerminalSequence;
14use SqlFaker\PostgreSql\Generation\Rewrite\Query\IntoClauseRule;
15
16#[CoversClass(IntoClauseRule::class)]
17#[UsesClass(ProductionOccurrence::class)]
18#[UsesClass(TerminalOccurrence::class)]
19#[UsesClass(TerminalSequence::class)]
20final class IntoClauseRuleTest extends TestCase
21{
22 #[DataProvider('providerContexts')]
23 public function testRewritePreservesOnlyTopLevelSelectDestinations(string $scope, bool $kept): void
24 {
25 $select = new TerminalOccurrence('SELECT', 10, [0, 1], [$scope, 'simple_select']);
26 $into = new TerminalOccurrence('INTO', 11, [0, 1, 2], [$scope, 'simple_select', 'into_clause']);
27 $name = new TerminalOccurrence('IDENT', 12, [0, 1, 2], [$scope, 'simple_select', 'into_clause']);
28 $tail = new TerminalOccurrence('TAIL', 13);
29 $terminals = [$select, $into, $name, $tail];
30 $input = new TerminalSequence($terminals, $terminals, [], [
31 new ProductionOccurrence(0, null, $scope, 0), new ProductionOccurrence(1, 0, 'simple_select', 0),
32 new ProductionOccurrence(2, 1, 'into_clause', 0),
33 ]);
34 $rule = new IntoClauseRule();
35 $result = $rule->rewrite($input);
36 self::assertSame($kept ? $terminals : [$select, $tail], $result->terminals);
37 self::assertSame($input->original, $result->original);
38 self::assertSame($input->productions, $result->productions);
39 self::assertSame($result, $rule->rewrite($result));
40 }
41
42 /**
43 * @return iterable<array{string, bool}>
44 */
45 public static function providerContexts(): iterable
46 {
47 foreach (['parse_toplevel', 'stmtmulti', 'toplevel_stmt', 'stmt', 'SelectStmt', 'select_no_parens', 'select_with_parens', 'select_clause', 'simple_select', 'ExplainStmt', 'ExplainableStmt'] as $scope) {
48 yield [$scope, true];
49 }
50 foreach (['common_table_expr', 'c_expr', 'table_ref', 'DeclareCursorStmt', 'InsertStmt', 'CreateTableAsStmt', 'PrepareStmt', 'rule_action_stmt'] as $scope) {
51 yield [$scope, false];
52 }
53 }
54
55 public function testRewriteRetainsOnlyTheLeftmostSetOperandDestination(): void
56 {
57 $left = new TerminalOccurrence('INTO', 10, [0, 1, 2, 3], ['simple_select', 'select_clause', 'simple_select', 'into_clause']);
58 $right = new TerminalOccurrence('INTO', 11, [0, 4, 5, 6], ['simple_select', 'select_clause', 'simple_select', 'into_clause']);
59 $input = new TerminalSequence([$left, $right], [$left, $right], [], [
60 new ProductionOccurrence(0, null, 'simple_select', 0),
61 new ProductionOccurrence(1, 0, 'select_clause', 0), new ProductionOccurrence(2, 1, 'simple_select', 0),
62 new ProductionOccurrence(3, 2, 'into_clause', 0), new ProductionOccurrence(4, 0, 'select_clause', 0),
63 new ProductionOccurrence(5, 4, 'simple_select', 0), new ProductionOccurrence(6, 5, 'into_clause', 0),
64 ]);
65 $result = (new IntoClauseRule())->rewrite($input);
66 self::assertSame([$left], $result->terminals);
67 self::assertSame($input->original, $result->original);
68 }
69}
70