packages/ztd-query-sqlite/tests/Unit/Shadow/Mutation/Table/Alter/RenameResolverTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Shadow\Mutation\Table\Alter;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use ZtdQuery\Platform\Sqlite\Shadow\Mutation\Table\Alter\RenameResolver;
11use ZtdQuery\Platform\Sqlite\Shadow\Mutation\Table\AlterTableMutation;
12use ZtdQuery\Schema\Key\ForeignKeyDefinition;
13use ZtdQuery\Schema\Key\ReferentialAction;
14use ZtdQuery\Schema\TableDefinition;
15use ZtdQuery\Schema\TableDefinitionRegistry;
16use ZtdQuery\Shadow\ShadowStore;
17
18#[CoversClass(RenameResolver::class)]
19#[UsesClass(AlterTableMutation::class)]
20#[UsesClass(\ZtdQuery\Platform\Sqlite\Shadow\Mutation\Table\Alter\AlteredTableProjection::class)]
21#[UsesClass(\ZtdQuery\Platform\Sqlite\Shadow\Mutation\Table\Alter\ColumnDefinitionEditor::class)]
22#[UsesClass(\ZtdQuery\Platform\Sqlite\Shadow\Resolution\MutationTableLookup::class)]
23#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Alter\AlterOperationParser::class)]
24#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\SqliteIdentifierQuoter::class)]
25#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\SqliteLexerProfile::class)]
26final class RenameResolverTest extends TestCase
27{
28    public function testResolveAlterRenameTableMovesSchemaAndRowsAtApply(): void
29    {
30        $registry = new TableDefinitionRegistry();
31        $definition = new TableDefinition(['id', 'name'], ['id' => 'INTEGER', 'name' => 'TEXT'], ['id'], ['id'], []);
32        $registry->register('users', $definition);
33        $store = new ShadowStore();
34        $store->set('users', [['id' => 1, 'name' => 'Alice']]);
35        $mutation = (new RenameResolver($registry))->resolveAlterRenameTable('ALTER TABLE users RENAME TO people', 'users', 'people');
36        self::assertInstanceOf(AlterTableMutation::class, $mutation);
37        self::assertSame('SELECT "id", "name" FROM "users"', $mutation->resultSelect());
38        $mutation->apply($store, [['id' => 1, 'name' => 'Alice']]);
39        self::assertFalse($registry->has('users'));
40        self::assertTrue($registry->has('people'));
41        self::assertFalse($store->has('users'));
42        self::assertSame([['id' => 1, 'name' => 'Alice']], $store->get('people'));
43    }
44
45    public function testResolveAlterRenameColumnProjectsNewName(): void
46    {
47        $registry = new TableDefinitionRegistry();
48        $definition = new TableDefinition(['id', 'name'], ['id' => 'INTEGER', 'name' => 'TEXT'], ['id'], ['id'], []);
49        $registry->register('users', $definition);
50        $store = new ShadowStore();
51        $store->set('users', [['id' => 1, 'name' => 'Alice']]);
52        $mutation = (new RenameResolver($registry))->resolveAlterRenameColumn('ALTER TABLE users RENAME COLUMN NAME TO label', 'users', 'NAME TO label');
53        self::assertInstanceOf(AlterTableMutation::class, $mutation);
54        self::assertSame('SELECT "id", "name" AS "label" FROM "users"', $mutation->resultSelect());
55        $mutation->apply($store, [['id' => 1, 'label' => 'Alice']]);
56        self::assertSame(['id', 'label'], $registry->get('users')?->columns);
57    }
58
59    public function testResolveAlterRenameColumnRejectsExistingTargetName(): void
60    {
61        $registry = new TableDefinitionRegistry();
62        $definition = new TableDefinition(['id', 'name'], ['id' => 'INTEGER', 'name' => 'TEXT'], ['id'], ['id'], []);
63        $registry->register('users', $definition);
64        $store = new ShadowStore();
65        $store->set('users', [['id' => 1, 'name' => 'Alice']]);
66        $this->expectException(\ZtdQuery\Exception\ColumnAlreadyExistsException::class);
67        (new RenameResolver($registry))->resolveAlterRenameColumn('ALTER TABLE users RENAME COLUMN name TO id', 'users', 'name TO id');
68    }
69
70    public function testDefinitionWithRenamedColumnUpdatesKeyAndValueMaps(): void
71    {
72        $definition = new TableDefinition(
73            ['parent', 'label'],
74            ['parent' => 'INTEGER', 'label' => 'TEXT'],
75            ['parent'],
76            ['parent'],
77            ['unique_parent' => ['parent']],
78            ['parent' => new \ZtdQuery\Schema\ColumnDeclaration(\ZtdQuery\Schema\ColumnTypeFamily::INTEGER, 'INTEGER')],
79            ['parent' => '0'],
80            ['parent' => \ZtdQuery\Schema\Key\IdentityGenerationStrategy::MaxValue],
81            ['parent' => '(1)'],
82            ['fk' => new ForeignKeyDefinition(['parent'], 'other', ['id'], ReferentialAction::Cascade, ReferentialAction::SetNull)],
83        );
84        $result = (new RenameResolver(new TableDefinitionRegistry()))->definitionWithRenamedColumn($definition, 'parent', 'parent_id');
85        self::assertSame(['parent_id', 'label'], $result->columns);
86        self::assertSame(['parent_id'], $result->primaryKeys);
87        self::assertSame(['parent_id'], $result->notNullColumns);
88        self::assertSame(['unique_parent' => ['parent_id']], $result->uniqueConstraints);
89        self::assertSame(['parent_id' => '0'], $result->columnDefaults);
90        self::assertSame(['parent_id' => '(1)'], $result->generatedExpressions);
91        self::assertSame(['parent_id'], array_keys($result->typedColumns));
92        self::assertSame(['parent_id'], array_keys($result->identityStrategies));
93        self::assertSame(['parent_id'], $result->foreignKeys['fk']->columns);
94        self::assertSame(['id'], $result->foreignKeys['fk']->referencedColumns);
95        self::assertSame(ReferentialAction::Cascade, $result->foreignKeys['fk']->onDelete);
96    }
97
98}
99