packages/sql-faker/tests/Unit/MySql/Generation/Rewrite/Query/JoinGroupingRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\MySql\Generation\Rewrite\Query;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\Generation\Token\ProductionOccurrence;
11use SqlFaker\Generation\Token\TerminalOccurrence;
12use SqlFaker\Generation\Token\TerminalSequence;
13use SqlFaker\MySql\Generation\Rewrite\Query\JoinGroupingRule;
14
15#[CoversClass(JoinGroupingRule::class)]
16#[UsesClass(ProductionOccurrence::class)]
17#[UsesClass(TerminalOccurrence::class)]
18#[UsesClass(TerminalSequence::class)]
19final class JoinGroupingRuleTest extends TestCase
20{
21    public function testRewriteKeepsNestedJoinConditionsWithTheirOwnOperands(): void
22    {
23        $a = new TerminalOccurrence('A', 10, [0], ['joined_table']);
24        $outer = new TerminalOccurrence('LEFT', 11, [0], ['joined_table']);
25        $b = new TerminalOccurrence('B', 12, [0, 1], ['joined_table', 'joined_table']);
26        $inner = new TerminalOccurrence('JOIN_SYM', 13, [0, 1], ['joined_table', 'joined_table']);
27        $c = new TerminalOccurrence('C', 14, [0, 1], ['joined_table', 'joined_table']);
28        $using = new TerminalOccurrence('USING', 15, [0], ['joined_table']);
29        $tokens = [$a, $outer, $b, $inner, $c, $using];
30        $input = new TerminalSequence($tokens, $tokens, [], [new ProductionOccurrence(0, null, 'joined_table', 3), new ProductionOccurrence(1, 0, 'joined_table', 4), new ProductionOccurrence(9, null, 'joined_table', 0)]);
31        $rule = new JoinGroupingRule();
32        $result = $rule->rewrite($input);
33        self::assertSame(['(', 'A', 'LEFT', '(', 'B', 'JOIN_SYM', 'C', ')', 'USING', ')'], $result->names());
34        self::assertSame($input->original, $result->original);
35        self::assertSame($input->productions, $result->productions);
36        self::assertCount(count($result->terminals), array_unique(array_map(static fn ($terminal): int => $terminal->id, $result->terminals)));
37        self::assertSame($result, $rule->rewrite($result));
38    }
39
40    public function testRewriteGroupsAnOuterJoinEvenWhenItsLeftChildIsAlreadyGrouped(): void
41    {
42        $a = new TerminalOccurrence('A', 10, [0, 1], ['joined_table', 'joined_table']);
43        $b = new TerminalOccurrence('B', 11, [0], ['joined_table']);
44        $input = new TerminalSequence([$a, $b], [$a, $b], [], [new ProductionOccurrence(0, null, 'joined_table', 0), new ProductionOccurrence(1, 0, 'joined_table', 0)]);
45        $rule = new JoinGroupingRule();
46        $result = $rule->rewrite($input);
47        self::assertSame(['(', '(', 'A', ')', 'B', ')'], $result->names());
48        self::assertSame($result, $rule->rewrite($result));
49        self::assertCount(count($result->terminals), array_unique(array_map(static fn ($terminal): int => $terminal->id, $result->terminals)));
50    }
51
52    public function testRewritePreservesTokensWithoutJoinProductions(): void
53    {
54        $input = TerminalSequence::fromNames(['A', 'JOIN_SYM', 'B']);
55        self::assertSame($input, (new JoinGroupingRule())->rewrite($input));
56    }
57}
58