Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.50% covered (success)
97.50%
39 / 40
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Expression
97.50% covered (success)
97.50%
39 / 40
75.00% covered (warning)
75.00%
3 / 4
32
0.00% covered (danger)
0.00%
0 / 1
 getOperator
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
18
 getOperand
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
9
 localeIds
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
3.02
 translateKeyword
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Finder\Output;
6
7use Celemas\Quma\Database;
8use Cosray\Context;
9use Cosray\Exception\ParserException;
10use Cosray\Finder\CompilesField;
11use Cosray\Finder\Input\Token;
12use Cosray\Finder\Input\TokenType;
13
14abstract readonly class Expression
15{
16    use CompilesField;
17
18    protected function getOperator(TokenType $type): string
19    {
20        return match ($type) {
21            TokenType::LeftParen => '(',
22            TokenType::RightParen => ')',
23            TokenType::Equal => '=',
24            TokenType::Greater => '>',
25            TokenType::GreaterEqual => '>=',
26            TokenType::Less => '<',
27            TokenType::LessEqual => '<=',
28            TokenType::Like => 'LIKE',
29            TokenType::ILike => 'ILIKE',
30            TokenType::Unequal => '!=',
31            TokenType::Unlike => 'NOT LIKE',
32            TokenType::IUnlike => 'NOT ILIKE',
33            TokenType::And => 'AND',
34            TokenType::Or => 'OR',
35            TokenType::In => 'IN',
36            TokenType::NotIn => 'NOT IN',
37            default => throw new ParserException('Invalid expression operator: ' . $type->name),
38        };
39    }
40
41    protected function getOperand(
42        #[\SensitiveParameter]
43        Token $token,
44        Database $db,
45        array $builtins,
46        ?Context $context = null,
47    ): string {
48        return match ($token->type) {
49            TokenType::Boolean => strtolower($token->lexeme),
50            TokenType::Field => $this->compileField(
51                $token->lexeme,
52                'n.content',
53                localeIds: $this->localeIds($context),
54            ),
55            TokenType::Builtin => $builtins[$token->lexeme],
56            TokenType::Keyword => $this->translateKeyword($token->lexeme),
57            TokenType::Null => 'NULL',
58            TokenType::Number => $token->lexeme,
59            TokenType::String => $db->quote($token->lexeme),
60            TokenType::List => $token->lexeme,
61        };
62    }
63
64    private function localeIds(?Context $context): array
65    {
66        if (!$context) {
67            return ['zxx'];
68        }
69
70        $ids = [];
71        $locale = $context->locale();
72
73        while ($locale) {
74            $ids[] = $locale->id;
75            $locale = $locale->fallback();
76        }
77
78        return $ids;
79    }
80
81    protected function translateKeyword(string $keyword): string
82    {
83        return match ($keyword) { 'now' => 'NOW()' };
84    }
85}