packages/ztd-query-core/tests/Unit/Rewrite/RewritePlanTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Rewrite;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use RuntimeException;
11use ZtdQuery\Exception\UnsupportedSqlException;
12use ZtdQuery\Rewrite\AffectedRowsMode;
13use ZtdQuery\Rewrite\QueryKind;
14use ZtdQuery\Rewrite\ReturningProjection;
15use ZtdQuery\Rewrite\RewritePlan;
16use ZtdQuery\Schema\Key\CandidateKeySet;
17use ZtdQuery\Shadow\Mutation\Row\InsertMutation;
18
19#[UsesClass(InsertMutation::class)]
20#[UsesClass(CandidateKeySet::class)]
21#[UsesClass(ReturningProjection::class)]
22#[CoversClass(RewritePlan::class)]
23#[UsesClass(UnsupportedSqlException::class)]
24#[UsesClass(\ZtdQuery\Shadow\Mutation\ConflictSearch::class)]
25#[UsesClass(\ZtdQuery\Shadow\Mutation\RowConstraints::class)]
26final class RewritePlanTest extends TestCase
27{
28    public function testKindSqlKindPlanHoldsSqlKindAndMutation(): void
29    {
30        $mutation = new InsertMutation('users');
31        $plan = new RewritePlan('SELECT 1', QueryKind::READ, $mutation);
32
33        self::assertSame('SELECT 1', $plan->sql());
34        self::assertSame(QueryKind::READ, $plan->kind());
35        self::assertSame($mutation, $plan->mutation());
36    }
37
38    public function testMutationPlanWithoutMutation(): void
39    {
40        $plan = new RewritePlan('SELECT 1', QueryKind::READ);
41
42        self::assertNull($plan->mutation());
43    }
44
45    public function testAffectedRowsModeReturningProjectionAffectedRowsModePlanCarriesReturningAndAffectedRowsMetadata(): void
46    {
47        $projection = ReturningProjection::fromItems([['source' => 'id', 'output' => null]]);
48        $plan = new RewritePlan(
49            'SELECT 1 AS id',
50            QueryKind::WRITE_SIMULATED,
51            new InsertMutation('users'),
52            $projection,
53            AffectedRowsMode::Matched,
54        );
55
56        self::assertSame($projection, $plan->returningProjection());
57        self::assertSame(AffectedRowsMode::Matched, $plan->affectedRowsMode());
58    }
59
60    public function testSqlKeepsTheStatementThePlanIsFor(): void
61    {
62        self::assertSame('SELECT 1', (new RewritePlan('SELECT 1', QueryKind::READ))->sql());
63    }
64
65    public function testReturningProjectionIsNothingWherePlanCarriesNone(): void
66    {
67        self::assertNull((new RewritePlan('SELECT 1', QueryKind::READ))->returningProjection());
68    }
69
70    public function testRequireMutationAnswersTheMutationTheWriteWasSimulatedAs(): void
71    {
72        $mutation = new InsertMutation('users');
73        $plan = new RewritePlan('SELECT 1', QueryKind::WRITE_SIMULATED, $mutation);
74
75        self::assertSame($mutation, $plan->requireMutation());
76    }
77
78    public function testRequireMutationRefusesAPlanThatCarriesNone(): void
79    {
80        $this->expectException(RuntimeException::class);
81
82        (new RewritePlan('SELECT 1', QueryKind::WRITE_SIMULATED))->requireMutation();
83    }
84}
85