packages/ztd-query-postgres/src/Schema/Key/DefinitionTokens.php
1<?php
2
3declare(strict_types=1);
4
5namespace ZtdQuery\Platform\Postgres\Schema\Key;
6
7use ZtdQuery\Platform\Postgres\Sql\PgSqlLexerProfile;
8use ZtdQuery\Sql\SqlToken;
9use ZtdQuery\Sql\SqlTokenKind;
10use ZtdQuery\Sql\SqlTokenStream;
11
12/**
13 * Definition tokens operations for PostgreSQL foreignkey.
14 *
15 * @visibility root
16 */
17final class DefinitionTokens
18{
19 /**
20 * Table body.
21 */
22 public function tableBody(string $sql): ?string
23 {
24 $tokens = SqlTokenStream::tokenize($sql, PgSqlLexerProfile::create())->significantTokens();
25 $first = $tokens[0] ?? null;
26 if ($first === null || !$first->isKeyword('CREATE')) {
27 return null;
28 }
29
30 $tableFound = false;
31 $opening = null;
32 foreach ($tokens as $token) {
33 if (!$token->isTopLevel()) {
34 continue;
35 }
36 if (!$tableFound) {
37 if ($token->isKeyword('TABLE')) {
38 $tableFound = true;
39 }
40 continue;
41 }
42 if ($opening === null) {
43 if (self::isSymbol($token, '(')) {
44 $opening = $token;
45 }
46 continue;
47 }
48 if (self::isSymbol($token, ')')) {
49 return substr($sql, $opening->endOffset(), $token->offset - $opening->endOffset());
50 }
51 }
52
53 return null;
54 }
55
56 /**
57 * @param list<SqlToken> $tokens
58 */
59 public static function keywordIndex(array $tokens, string $keyword): ?int
60 {
61 foreach ($tokens as $index => $token) {
62 if ($token->isTopLevel() && $token->isKeyword($keyword)) {
63 return $index;
64 }
65 }
66
67 return null;
68 }
69
70 /**
71 * @param list<SqlToken> $tokens
72 */
73 public static function symbolIndex(array $tokens, string $symbol, int $start): ?int
74 {
75 foreach ($tokens as $index => $token) {
76 if ($index >= $start && $token->isTopLevel() && self::isSymbol($token, $symbol)) {
77 return $index;
78 }
79 }
80
81 return null;
82 }
83
84 /**
85 * Is symbol.
86 */
87 public static function isSymbol(?SqlToken $token, string $symbol): bool
88 {
89 if ($token === null) {
90 return false;
91 }
92
93 return $token->kind === SqlTokenKind::Symbol && $token->text === $symbol;
94 }
95}
96