Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
22.73% covered (danger)
22.73%
5 / 22
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ExpressionGroup
22.73% covered (danger)
22.73%
5 / 22
40.00% covered (danger)
40.00%
2 / 5
78.44
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
 add
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getType
n/a
0 / 0
n/a
0 / 0
0
 newFromArray
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
 toSql
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 toGeneralizedSql
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace Wikimedia\Rdbms;
4
5use InvalidArgumentException;
6use Wikimedia\Rdbms\Database\DbQuoter;
7
8// Very long type annotations :(
9// phpcs:disable Generic.Files.LineLength
10
11/**
12 * A composite node representing a group of expressions.
13 *
14 * @since 1.42
15 */
16abstract class ExpressionGroup implements IExpression {
17    /**
18     * @var IExpression[]
19     */
20    protected array $children = [];
21
22    /**
23     * @param IExpression ...$children
24     * @internal Outside of rdbms, Use IReadableDatabase::andExpr() or ::orExpr to create an expression group object
25     */
26    public function __construct( IExpression ...$children ) {
27        $this->children = $children;
28    }
29
30    final protected function add( IExpression $expression ) {
31        $this->children[] = $expression;
32    }
33
34    abstract protected function getType(): string;
35
36    /**
37     * @internal to rdbms
38     * @param non-empty-array<string,?scalar|RawSQLValue|Blob|LikeValue|non-empty-list<scalar|Blob>>|non-empty-array<int,IExpression> $conds
39     * @param-taint $conds exec_sql_numkey
40     * @return static
41     */
42    public static function newFromArray( array $conds ) {
43        if ( !$conds ) {
44            throw new InvalidArgumentException( "The array of conditions can't be empty." );
45        }
46        $exprs = [];
47        foreach ( $conds as $field => $cond ) {
48            if ( is_numeric( $field ) ) {
49                if ( !$cond instanceof IExpression ) {
50                    throw new InvalidArgumentException( __METHOD__ . ": Only IExpression are allowed with numeric key." );
51                }
52                $exprs[] = $cond;
53            } else {
54                if ( $cond instanceof IExpression ) {
55                    throw new InvalidArgumentException( __METHOD__ . ": unexpected key $field for IExpression value" );
56                }
57                $exprs[] = new Expression( $field, '=', $cond );
58            }
59        }
60        // @phan-suppress-next-line PhanTypeInstantiateAbstractStatic
61        return new static( ...$exprs );
62    }
63
64    /**
65     * @param DbQuoter $dbQuoter
66     * @return string
67     * @return-taint none
68     */
69    final public function toSql( DbQuoter $dbQuoter ): string {
70        if ( !$this->children ) {
71            throw new InvalidArgumentException( "The array of values can't be empty." );
72        }
73        $sqls = array_map( static fn ( $value ) => $value->toSql( $dbQuoter ), $this->children );
74        return '(' . implode( ' ' . $this->getType() . ' ', $sqls ) . ')';
75    }
76
77    final public function toGeneralizedSql(): string {
78        if ( !$this->children ) {
79            throw new InvalidArgumentException( "The array of values can't be empty." );
80        }
81        $sqls = array_map( static fn ( $value ) => $value->toGeneralizedSql(), $this->children );
82        return '(' . implode( ' ' . $this->getType() . ' ', $sqls ) . ')';
83    }
84}