packages/ztd-query-postgres/src/Sql/Transaction/KeywordForm.php

1<?php
2
3declare(strict_types=1);
4
5namespace ZtdQuery\Platform\Postgres\Sql\Transaction;
6
7use ZtdQuery\Sql\SqlToken;
8use ZtdQuery\Sql\SqlTokenKind;
9
10/**
11 * Keyword form operations for PostgreSQL transaction.
12 *
13 * @visibility root
14 */
15final class KeywordForm
16{
17    /**
18     * @param list<SqlToken> $tokens
19     * @param list<list<string>> $forms
20     */
21    public function matchesAny(array $tokens, array $forms): bool
22    {
23        foreach ($forms as $form) {
24            if ($this->matches($tokens, $form)) {
25                return true;
26            }
27        }
28
29        return false;
30    }
31
32    /**
33     * @param list<SqlToken> $tokens
34     * @param list<list<string>> $prefixes
35     */
36    public function nameAfter(array $tokens, array $prefixes): ?string
37    {
38        foreach ($prefixes as $prefix) {
39            if (count($tokens) !== count($prefix) + 1 || !$this->matches(array_slice($tokens, 0, -1), $prefix)) {
40                continue;
41            }
42            $name = $tokens[count($prefix)];
43            if (!in_array($name->kind, [SqlTokenKind::Word, SqlTokenKind::QuotedIdentifier], true)) {
44                return null;
45            }
46
47            return $this->unquote($name->text);
48        }
49
50        return null;
51    }
52
53    /**
54     * @param list<SqlToken> $tokens
55     * @param list<string> $keywords
56     */
57    public function matches(array $tokens, array $keywords): bool
58    {
59        if (count($tokens) !== count($keywords)) {
60            return false;
61        }
62        foreach ($keywords as $index => $keyword) {
63            if (!$tokens[$index]->isKeyword($keyword)) {
64                return false;
65            }
66        }
67
68        return true;
69    }
70
71    /**
72     * Unquote.
73     */
74    public function unquote(string $identifier): ?string
75    {
76        $first = $identifier[0] ?? '';
77        if ($first === '`') {
78            return null;
79        }
80        if ($first !== '"') {
81            return $identifier;
82        }
83        if (($identifier[strlen($identifier) - 1] ?? '') !== '"') {
84            return null;
85        }
86
87        return str_replace('""', '"', substr($identifier, 1, -1));
88    }
89}
90