packages/ztd-query-sqlite/tests/Unit/Schema/Create/ColumnDefinitionParserTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Schema\Create;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use ZtdQuery\Platform\Sqlite\Schema\Create\ColumnDefinitionParser;
11
12#[CoversClass(ColumnDefinitionParser::class)]
13#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Dml\Expression\AssignmentColumnParser::class)]
14#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Dml\Expression\AssignmentParser::class)]
15#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Dml\Expression\ValueListParser::class)]
16#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Dml\Insert\InsertClauseParser::class)]
17#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Lexing\ExpressionSpan::class)]
18#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Lexing\IdentifierDecoder::class)]
19#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Lexing\LiteralMasker::class)]
20#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Lexing\OpaqueSqlSpan::class)]
21#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Lexing\QuotedSpan::class)]
22#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Lexing\TopLevelKeywordScanner::class)]
23#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Relation\RelationSourceParser::class)]
24#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Statement\StatementClassifier::class)]
25#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Statement\StatementStructure::class)]
26#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Statement\TargetTableParser::class)]
27#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Dml\Update\UpdateClauseParser::class)]
28#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\SqliteLexerProfile::class)]
29#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\SqliteLexicalMasker::class)]
30#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\SqliteParser::class)]
31#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\Relation\SqliteSelectRelationParser::class)]
32final class ColumnDefinitionParserTest extends TestCase
33{
34    public function testParseColumnDefinitionPreservesColumnMetadata(): void
35    {
36        self::assertSame([
37            'name' => 'full name', 'type' => 'TEXT', 'notNull' => true,
38            'primaryKey' => false, 'unique' => true, 'default' => "'guest'", 'generatedExpression' => null,
39        ], (new ColumnDefinitionParser())->parseColumnDefinition('"full name" TEXT NOT NULL UNIQUE DEFAULT \'guest\''));
40        self::assertNull((new ColumnDefinitionParser())->parseColumnDefinition(''));
41        self::assertNull((new ColumnDefinitionParser())->parseColumnDefinition('"" TEXT'));
42    }
43
44    public function testLeadingKeywordStopsAtPunctuation(): void
45    {
46        self::assertSame('CONSTRAINT', (new ColumnDefinitionParser())->leadingKeyword('constraint c'));
47        self::assertSame('DECIMAL', (new ColumnDefinitionParser())->leadingKeyword('decimal(10,2)'));
48        self::assertSame('', (new ColumnDefinitionParser())->leadingKeyword('"name"'));
49    }
50
51    public function testExtractColumnTypeRetainsPrecisionAndMultiwordNames(): void
52    {
53        $parser = new ColumnDefinitionParser();
54        self::assertSame('DECIMAL(10, 2)', $parser->extractColumnType('decimal(10, 2) DEFAULT 0'));
55        self::assertSame('DOUBLE PRECISION', $parser->extractColumnType('double precision NOT NULL'));
56        self::assertNull($parser->extractColumnType('PRIMARY KEY'));
57        self::assertNull($parser->extractColumnType(''));
58    }
59
60    public function testParseColumnNameListUnquotesNames(): void
61    {
62        self::assertSame(['id', 'full name', 'age'], (new ColumnDefinitionParser())->parseColumnNameList('id, "full name",, `age`'));
63    }
64
65    public function testDeclaredTypeDistinguishesOmittedTypeAndConstraints(): void
66    {
67        $parser = new ColumnDefinitionParser();
68        self::assertSame('INTEGER', $parser->declaredType('INTEGER PRIMARY KEY'));
69        self::assertNull($parser->declaredType('PRIMARY KEY'));
70        self::assertNull($parser->declaredType('GENERATED ALWAYS AS (1)'));
71        self::assertNull($parser->declaredType(''));
72    }
73
74}
75