packages/ztd-query-sqlite/src/Shadow/Mutation/Upsert/ComparisonExpressionParser.php

1<?php
2
3declare(strict_types=1);
4
5namespace ZtdQuery\Platform\Sqlite\Shadow\Mutation\Upsert;
6
7use ZtdQuery\Shadow\Mutation\UpsertExpression;
8use ZtdQuery\Shadow\Mutation\UpsertExpressionKind;
9
10/**
11 * Parses relational operators in upsert predicates.
12 *
13 * @visibility ZtdQuery\Platform\Sqlite
14 */
15final class ComparisonExpressionParser
16{
17    /**
18     * Binds the collaborators used by this operation.
19     */
20    public function __construct(private ExpressionCursor $cursor)
21    {
22    }
23
24    /**
25     * Parses relational operators in upsert predicates.
26     */
27    public function parseComparison(): UpsertExpression
28    {
29        $left = (new ArithmeticExpressionParser($this->cursor))->parseAdditive();
30        $operator = $this->comparisonOperator();
31
32        return $operator === null
33            ? $left
34            : UpsertExpression::binary($operator, $left, (new ArithmeticExpressionParser($this->cursor))->parseAdditive());
35    }
36
37    /**
38     * Parses relational operators in upsert predicates.
39     * @throws \ZtdQuery\Exception\UnsupportedSqlException
40     */
41    public function comparisonOperator(): ?UpsertExpressionKind
42    {
43        $first = $this->cursor->tokens[$this->cursor->index] ?? null;
44        if ($first === null || !(new ExpressionTokenDecoder($this->cursor->sql))->isSymbol($first, ['=', '!', '<', '>'])) {
45            return null;
46        }
47        $operator = $first->text;
48        $second = $this->cursor->tokens[$this->cursor->index + 1] ?? null;
49        if ($second !== null && (new ExpressionTokenDecoder($this->cursor->sql))->isSymbol($second, ['=', '>']) && $operator !== '=') {
50            $operator .= $second->text;
51            $this->cursor->index++;
52        }
53        $this->cursor->index++;
54
55        return match ($operator) {
56            '=' => UpsertExpressionKind::Equal,
57            '!=', '<>' => UpsertExpressionKind::NotEqual,
58            '<' => UpsertExpressionKind::Less,
59            '<=' => UpsertExpressionKind::LessOrEqual,
60            '>' => UpsertExpressionKind::Greater,
61            '>=' => UpsertExpressionKind::GreaterOrEqual,
62            default => throw (new ExpressionTokenDecoder($this->cursor->sql))->unsupported(),
63        };
64    }
65}
66