aboutsummaryrefslogtreecommitdiff
path: root/src/Search/LogicOp.php
blob: 19d85f379b1f61506a6a45c8d1a539f9ecb8ec24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php


namespace Micropoly\Search;


class LogicOp implements SearchExpr
{
    public const OP_AND = "and";
    public const OP_OR = "or";

    private const SQLOPS = [
        self::OP_AND => "AND",
        self::OP_OR => "OR",
    ];

    private string $op;
    private SearchExpr $a;
    private SearchExpr $b;

    public function __construct(string $op, SearchExpr $a, SearchExpr $b)
    {
        if (!self::checkOp($op))
            throw new \DomainException("{$op} is not a valid operator");

        $this->op = $op;
        $this->a = $a;
        $this->b = $b;
    }

    public static function build(string $op, SearchExpr $a, SearchExpr $b): SearchExpr
    {
        return $a instanceof AbstractFTSExpr && $b instanceof AbstractFTSExpr
            ? new FTSLogicOp($op, $a, $b)
            : new self($op, $a, $b);
    }

    /**
     * @param string $op
     * @return bool
     */
    public static function checkOp(string $op): bool
    {
        return in_array($op, [
            self::OP_AND,
            self::OP_OR,
        ]);
    }

    public function getA(): SearchExpr { return $this->a; }
    public function getB(): SearchExpr { return $this->b; }
    public function getOp(): string { return $this->op; }

    public function toString(): string
    {
        return "({$this->a->toString()}) {$this->op} ({$this->b->toString()})";
    }

    public function toSQL($bindPrefix, bool $singleFTS): SQLSearchExpr
    {
        $sqlex = new SQLSearchExpr();

        $a = $this->a->toSQL("a_$bindPrefix", $singleFTS);
        $b = $this->b->toSQL("b_$bindPrefix", $singleFTS);
        assert(isset(self::SQLOPS[$this->op]));
        $sqlop = self::SQLOPS[$this->op];

        $sqlex->sql = "(({$a->sql}) {$sqlop} ({$b->sql}))";
        $sqlex->bindings = array_merge($a->bindings, $b->bindings);

        return $sqlex;
    }

    public function countFTSQueries(): int
    {
        return $this->a->countFTSQueries() + $this->b->countFTSQueries();
    }
}