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