packages/sql-faker/tests/Unit/PostgreSql/Generation/Rewrite/Routine/RangeFunctionOrdinalityRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\PostgreSql\Generation\Rewrite\Routine;
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\Routine\RangeFunctionOrdinalityRule;
15
16#[CoversClass(RangeFunctionOrdinalityRule::class)]
17#[UsesClass(ProductionOccurrence::class)]
18#[UsesClass(TerminalOccurrence::class)]
19#[UsesClass(TerminalSequence::class)]
20final class RangeFunctionOrdinalityRuleTest extends TestCase
21{
22    #[DataProvider('providerScopes')]
23    public function testRewriteOnlyRemovesOrdinalityBesideItsOwnTypedColumnList(string $function, string $alias, string $columns, int $columnParent, bool $ordinality, bool $remove): void
24    {
25        $call = new TerminalOccurrence('IDENT', 10, [0, 1], ['table_ref', $function]);
26        $with = new TerminalOccurrence('WITH_LA', 11, [0, 1, 2], ['table_ref', $function, 'opt_ordinality']);
27        $ordinal = new TerminalOccurrence('ORDINALITY', 12, [0, 1, 2], ['table_ref', $function, 'opt_ordinality']);
28        $column = new TerminalOccurrence('IDENT', 13, [0, 3, 4], ['table_ref', $alias, $columns]);
29        $terminals = [$call, ...($ordinality ? [$with, $ordinal] : []), $column];
30        $input = new TerminalSequence($terminals, $terminals, [], [
31            new ProductionOccurrence(0, null, 'table_ref', 2),
32            new ProductionOccurrence(1, 0, $function, 0),
33            new ProductionOccurrence(2, 1, 'opt_ordinality', $ordinality ? 0 : 1),
34            new ProductionOccurrence(3, 0, $alias, 2),
35            new ProductionOccurrence(4, $columnParent, $columns, 0),
36        ]);
37        $rule = new RangeFunctionOrdinalityRule();
38        $result = $rule->rewrite($input);
39        self::assertSame($remove ? [$call, $column] : $terminals, $result->terminals);
40        self::assertSame($input->original, $result->original);
41        self::assertSame($input->productions, $result->productions);
42        self::assertSame($result, $rule->rewrite($result));
43    }
44
45    /**
46     * @return iterable<string, array{string, string, string, int, bool, bool}>
47     */
48    public static function providerScopes(): iterable
49    {
50        yield 'typed alias' => ['func_table', 'func_alias_clause', 'TableFuncElementList', 3, true, true];
51        yield 'no ordinality' => ['func_table', 'func_alias_clause', 'TableFuncElementList', 3, false, false];
52        yield 'plain relation' => ['relation_expr', 'func_alias_clause', 'TableFuncElementList', 3, true, false];
53        yield 'other alias scope' => ['func_table', 'opt_alias_clause', 'TableFuncElementList', 3, true, false];
54        yield 'column names only' => ['func_table', 'func_alias_clause', 'name_list', 3, true, false];
55        yield 'definitions inside rows from' => ['func_table', 'func_alias_clause', 'TableFuncElementList', 1, true, false];
56    }
57}
58