packages/ztd-query-sqlite/src/Rewrite/Returning/SqliteReturningProjectionParser.php

1<?php
2
3declare(strict_types=1);
4
5namespace ZtdQuery\Platform\Sqlite\Rewrite\Returning;
6
7use ZtdQuery\Exception\UnsupportedSqlException;
8use ZtdQuery\Platform\Sqlite\Sql\Returning\ReturningItemParser;
9use ZtdQuery\Rewrite\ReturningProjection;
10use ZtdQuery\Sql\SqlTokenStream;
11
12/**
13 * Extracts RETURNING expressions and their output column names.
14 */
15final class SqliteReturningProjectionParser
16{
17    /**
18     * Parses the supplied SQL into its supported structured representation.
19     * @throws UnsupportedSqlException
20     */
21    public function parse(string $sql): ?ReturningProjection
22    {
23        $clause = SqlTokenStream::tokenize($sql, \ZtdQuery\Platform\Sqlite\Sql\SqliteLexerProfile::create())->topLevelClause(['RETURNING']);
24        if ($clause === null) {
25            return null;
26        }
27
28        $items = [];
29        foreach (SqlTokenStream::tokenize(rtrim($clause, "; \t\n\r\0\x0B"), \ZtdQuery\Platform\Sqlite\Sql\SqliteLexerProfile::create())->splitTopLevel() as $expression) {
30            $item = (new ReturningItemParser())->parseItem($expression);
31            if ($item === null) {
32                throw new UnsupportedSqlException(
33                    $sql,
34                    'RETURNING supports columns, qualified columns, aliases, and wildcard projections',
35                );
36            }
37            $items[] = $item;
38        }
39
40        if ($items === []) {
41            throw new UnsupportedSqlException($sql, 'RETURNING requires a projection');
42        }
43
44        return ReturningProjection::fromItems($items);
45    }
46
47}
48