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