Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
68.00% covered (warning)
68.00%
17 / 25
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Exists
68.00% covered (warning)
68.00%
17 / 25
33.33% covered (danger)
33.33%
1 / 3
20.42
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
2.02
 fieldPath
61.11% covered (warning)
61.11%
11 / 18
0.00% covered (danger)
0.00%
0 / 1
18.12
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Finder\Output;
6
7use Cosray\Context;
8use Cosray\Exception\ParserOutputException;
9use Cosray\Finder\Input\Token;
10use Override;
11
12final readonly class Exists extends Expression implements Output
13{
14    public function __construct(
15        #[\SensitiveParameter]
16        private Token $token,
17        private Context $context,
18    ) {}
19
20    #[Override]
21    public function get(): string
22    {
23        if ($this->token->lexeme === '') {
24            throw new ParserOutputException($this->token, 'Invalid field name in exists condition.');
25        }
26
27        // PDO reads a bare `?` as a positional parameter; `??` is its escape.
28        return 'n.content @?? '
29            . $this->context->db->quote(
30                '$.' . $this->fieldPath($this->token->lexeme),
31            );
32    }
33
34    private function fieldPath(string $field): string
35    {
36        $parts = explode('.', $field);
37
38        foreach ($parts as $part) {
39            if ($part === '') {
40                throw new ParserOutputException($this->token, 'Invalid field name in exists condition.');
41            }
42        }
43
44        if (count($parts) === 1) {
45            return $parts[0] . '.value.*';
46        }
47
48        if (count($parts) === 2 && $parts[1] === '?') {
49            return $parts[0] . '.value.' . $this->context->localeId();
50        }
51
52        if (count($parts) > 2 && in_array('?', $parts, true)) {
53            throw new ParserOutputException(
54                $this->token,
55                'The questionmark is allowed after the first dot only.',
56            );
57        }
58
59        if (count($parts) === 2 && $parts[1] === '*') {
60            return $parts[0] . '.value.*';
61        }
62
63        if (count($parts) === 2) {
64            return $parts[0] . '.value.' . $parts[1];
65        }
66
67        return implode('.', $parts);
68    }
69}