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