Lines
100.00%
18 / 18
Functions and Methods
100.00%
6 / 6
Classes and Traits
100.00%
1 / 1
| Name | Lines | Functions and Methods | CRAP | Classes and Traits | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Aggregate | 100.00% | 18 / 18 | 100.00% | 6 / 6 | 11 | 100.00% | 1 / 1 | |||
| count | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| max | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| min | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| sum | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| avg | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| __construct | 100.00% | 13 / 13 | 100.00% | 1 / 1 | 6 | |||||
| 1 | <?php | |
| 2 | ||
| 3 | declare(strict_types=1); | |
| 4 | ||
| 5 | namespace BlueprintAU\Radiant\Database\Query; | |
| 6 | ||
| 7 | /** | |
| 8 | * A typed SQL aggregate: function over a column, with an optional alias. | |
| 9 | * | |
| 10 | * Static factories cover the five universal aggregates; `new Aggregate(...)` | |
| 11 | * covers everything server-specific. | |
| 12 | * | |
| 13 | * @package BlueprintAU\Radiant\Database\Query | |
| 14 | */ | |
| 15 | final class Aggregate | |
| 16 | { | |
| 17 | /** | |
| 18 | * Count rows (or non-null values of a column). | |
| 19 | * | |
| 20 | * @param string $column | |
| 21 | * @param string|null $alias | |
| 22 | * @return self | |
| 23 | */ | |
| 24 | public static function count(string $column = '*', ?string $alias = null): self | |
| 25 | { | |
| 26 | return new self('count', $column, $alias); | |
| 27 | } | |
| 28 | ||
| 29 | /** | |
| 30 | * Maximum of a column's values. | |
| 31 | * | |
| 32 | * @param string $column | |
| 33 | * @param string|null $alias | |
| 34 | * @return self | |
| 35 | */ | |
| 36 | public static function max(string $column, ?string $alias = null): self | |
| 37 | { | |
| 38 | return new self('max', $column, $alias); | |
| 39 | } | |
| 40 | ||
| 41 | /** | |
| 42 | * Minimum of a column's values. | |
| 43 | * | |
| 44 | * @param string $column | |
| 45 | * @param string|null $alias | |
| 46 | * @return self | |
| 47 | */ | |
| 48 | public static function min(string $column, ?string $alias = null): self | |
| 49 | { | |
| 50 | return new self('min', $column, $alias); | |
| 51 | } | |
| 52 | ||
| 53 | /** | |
| 54 | * Sum of a column's values. | |
| 55 | * | |
| 56 | * @param string $column | |
| 57 | * @param string|null $alias | |
| 58 | * @return self | |
| 59 | */ | |
| 60 | public static function sum(string $column, ?string $alias = null): self | |
| 61 | { | |
| 62 | return new self('sum', $column, $alias); | |
| 63 | } | |
| 64 | ||
| 65 | /** | |
| 66 | * Average of a column's values. | |
| 67 | * | |
| 68 | * @param string $column | |
| 69 | * @param string|null $alias | |
| 70 | * @return self | |
| 71 | */ | |
| 72 | public static function avg(string $column, ?string $alias = null): self | |
| 73 | { | |
| 74 | return new self('avg', $column, $alias); | |
| 75 | } | |
| 76 | ||
| 77 | /** | |
| 78 | * Create an aggregate. | |
| 79 | * | |
| 80 | * @param string $function The aggregate function name — any bare SQL identifier. | |
| 81 | * @param string|Expression $column The column to aggregate, or an Expression for complex arguments. | |
| 82 | * @param string|null $alias The result column name; derived from the call text when null. | |
| 83 | * @throws \InvalidArgumentException | |
| 84 | */ | |
| 85 | public function __construct( | |
| 86 | public readonly string $function, | |
| 87 | public readonly string|Expression $column, | |
| 88 | public readonly ?string $alias = null, | |
| 89 | ) { | |
| 90 | if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $function) !== 1) { | |
| 91 | throw new \InvalidArgumentException( | |
| 92 | "Aggregate function must be a bare SQL identifier; got [{$function}]." | |
| 93 | ); | |
| 94 | } | |
| 95 | ||
| 96 | // Column: `*`, an identifier path (`age`, `users.age`, `users.*`), | |
| 97 | // or `distinct <path>` — validated at DECLARATION. An Expression is | |
| 98 | // raw SQL by contract and passes through unvalidated (the same | |
| 99 | // trust model as a raw select). | |
| 100 | if (!$column instanceof Expression | |
| 101 | && preg_match('/^(distinct\s+)?(\*|[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*|\.\*)?)$/i', $column) !== 1 | |
| 102 | ) { | |
| 103 | throw new \InvalidArgumentException( | |
| 104 | "Aggregate column must be *, an identifier path, `distinct <path>`, or an Expression; got [{$column}]." | |
| 105 | ); | |
| 106 | } | |
| 107 | ||
| 108 | if ($alias !== null && preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $alias) !== 1) { | |
| 109 | throw new \InvalidArgumentException( | |
| 110 | "Aggregate alias must be a bare identifier; got [{$alias}]." | |
| 111 | ); | |
| 112 | } | |
| 113 | } | |
| 114 | } |