Lines 80.00% 16 / 20
Functions and Methods 80.00% 16 / 20
Classes and Traits 0.00% 0 / 1
Name Lines Functions and Methods CRAP Classes and Traits
FiltersStaticQuery 80.00% 16 / 20 80.00% 16 / 20 23.20 0.00% 0 / 1
 where n/a 0 / 0 n/a 0 / 0 0
 whereEq 100.00% 1 / 1 100.00% 1 / 1 1
 orWhereEq 100.00% 1 / 1 100.00% 1 / 1 1
 whereNested n/a 0 / 0 n/a 0 / 0 0
 whereNestedGroup 100.00% 1 / 1 100.00% 1 / 1 1
 orWhereNested 100.00% 1 / 1 100.00% 1 / 1 1
 whereExists n/a 0 / 0 n/a 0 / 0 0
 whereNotExists 100.00% 1 / 1 100.00% 1 / 1 1
 orWhereExists 0.00% 0 / 1 0.00% 0 / 1 2
 orWhereNotExists 0.00% 0 / 1 0.00% 0 / 1 2
 whereInQuery n/a 0 / 0 n/a 0 / 0 0
 whereNotInQuery 100.00% 1 / 1 100.00% 1 / 1 1
 orWhereInQuery 0.00% 0 / 1 0.00% 0 / 1 2
 orWhereNotInQuery 0.00% 0 / 1 0.00% 0 / 1 2
 orWhere 100.00% 1 / 1 100.00% 1 / 1 1
 whereIn 100.00% 1 / 1 100.00% 1 / 1 1
 whereNotIn 100.00% 1 / 1 100.00% 1 / 1 1
 whereNull 100.00% 1 / 1 100.00% 1 / 1 1
 whereNotNull 100.00% 1 / 1 100.00% 1 / 1 1
 whereBetween 100.00% 1 / 1 100.00% 1 / 1 1
 whereNotBetween 100.00% 1 / 1 100.00% 1 / 1 1
 whereLike 100.00% 1 / 1 100.00% 1 / 1 1
 orWhereLike 100.00% 1 / 1 100.00% 1 / 1 1
 whereNotLike 100.00% 1 / 1 100.00% 1 / 1 1
 orderBy n/a 0 / 0 n/a 0 / 0 0
 limit n/a 0 / 0 n/a 0 / 0 0
 offset n/a 0 / 0 n/a 0 / 0 0
 select n/a 0 / 0 n/a 0 / 0 0
 groupBy n/a 0 / 0 n/a 0 / 0 0
 having n/a 0 / 0 n/a 0 / 0 0
1<?php
2
3declare(strict_types=1);
4
5namespace BlueprintAU\Radiant\Concerns;
6
7use BlueprintAU\Radiant\Database\Query\Enums\SortDirection;
8use BlueprintAU\Radiant\Database\Query\Enums\WhereBoolean;
9use BlueprintAU\Radiant\Database\Query\Enums\WhereOperator;
10use BlueprintAU\Radiant\Database\Query\QueryBuilder;
11use BlueprintAU\Radiant\Model;
12use BlueprintAU\Radiant\ModelQueryBuilder;
13use BlueprintAU\Radiant\Database\Query\WhereBuilder;
14
15/**
16 * The shared filter vocabulary, static-forwarder shaped.
17 *
18 * The static twin of {@see FiltersQuery}: `Model`'s filter entry points
19 * are static (they start a query), so a PHP trait method cannot be static
20 * AND instance at once — this trait mirrors the same vocabulary by hand,
21 * forwarding every helper into the {@see FiltersStaticQuery::where()}
22 * static sink. Static filters return the builder.
23 *
24 * @mixin Model
25 * @phpstan-require-extends Model
26 *
27 * @template TModel of Model
28 */
29trait FiltersStaticQuery
30{
31    /**
32     * Start a model query with a where clause — the single sink every
33     * other static filter funnels into.
34     *
35     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
36     * @param  WhereOperator|string  $operator
37     * @param  mixed  $value
38     * @param  WhereBoolean  $boolean
39     * @return ModelQueryBuilder<static>
40     */
41    abstract public static function where(
42        string|\BlueprintAU\Radiant\Database\Query\Expression $column,
43        WhereOperator|string $operator,
44        mixed $value,
45        WhereBoolean $boolean = WhereBoolean::And,
46    ): ModelQueryBuilder;
47
48    /**
49     * Start a model query with an equality where clause — sugar for
50     * `where($column, '=', $value)`.
51     *
52     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
53     * @param  mixed  $value
54     * @param  WhereBoolean  $boolean
55     * @return ModelQueryBuilder<static>
56     */
57    public static function whereEq(
58        string|\BlueprintAU\Radiant\Database\Query\Expression $column,
59        mixed $value,
60        WhereBoolean $boolean = WhereBoolean::And,
61    ): ModelQueryBuilder {
62        return static::where($column, WhereOperator::Eq, $value, $boolean);
63    }
64
65    /**
66     * Start a model query with an OR-connected equality where clause.
67     *
68     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
69     * @param  mixed  $value
70     * @return ModelQueryBuilder<static>
71     */
72    public static function orWhereEq(
73        string|\BlueprintAU\Radiant\Database\Query\Expression $column,
74        mixed $value,
75    ): ModelQueryBuilder {
76        return static::where($column, WhereOperator::Eq, $value, WhereBoolean::Or);
77    }
78
79    /**
80     * Start a model query with a nested where group — the second static
81     * sink; the `orWhereNested` default delegates here.
82     *
83     * @param  callable(WhereBuilder): WhereBuilder  $callback
84     * @param  WhereBoolean  $boolean
85     * @return ModelQueryBuilder<static>
86     */
87    abstract public static function whereNested(
88        callable $callback,
89        WhereBoolean $boolean = WhereBoolean::And,
90    ): ModelQueryBuilder;
91
92    /**
93     * Start a model query with a nested where group on the wrapped builder.
94     *
95     * @param  callable(WhereBuilder): WhereBuilder  $callback
96     * @return ModelQueryBuilder<static>
97     */
98    public static function whereNestedGroup(callable $callback): ModelQueryBuilder
99    {
100        return static::whereNested($callback, WhereBoolean::And);
101    }
102
103    /**
104     * Start a model query with an OR-connected nested where group.
105     *
106     * @param  callable(WhereBuilder): WhereBuilder  $callback
107     * @return ModelQueryBuilder<static>
108     */
109    public static function orWhereNested(callable $callback): ModelQueryBuilder
110    {
111        return static::whereNested($callback, WhereBoolean::Or);
112    }
113
114    /**
115     * Start a model query with an `EXISTS (subquery)` clause.
116     *
117     * The subquery is a caller-built builder, typically another model's
118     * `newQuery()` correlated to the outer query via `whereColumn()`.
119     *
120     * @param  QueryBuilder  $query  The existential subquery.
121     * @param  WhereBoolean  $boolean
122     * @param  bool  $negated  True renders `NOT EXISTS`.
123     * @return ModelQueryBuilder<static>
124     */
125    abstract public static function whereExists(
126        QueryBuilder $query,
127        WhereBoolean $boolean = WhereBoolean::And,
128        bool $negated = false,
129    ): ModelQueryBuilder;
130
131    /**
132     * Start a model query with a `NOT EXISTS (subquery)` clause.
133     *
134     * @param  QueryBuilder  $query  The existential subquery.
135     * @param  WhereBoolean  $boolean
136     * @return ModelQueryBuilder<static>
137     */
138    public static function whereNotExists(QueryBuilder $query, WhereBoolean $boolean = WhereBoolean::And): ModelQueryBuilder
139    {
140        return static::whereExists($query, $boolean, true);
141    }
142
143    /**
144     * Start a model query with an OR-connected `EXISTS (subquery)` clause.
145     *
146     * @param  QueryBuilder  $query  The existential subquery.
147     * @return ModelQueryBuilder<static>
148     */
149    public static function orWhereExists(QueryBuilder $query): ModelQueryBuilder
150    {
151        return static::whereExists($query, WhereBoolean::Or);
152    }
153
154    /**
155     * Start a model query with an OR-connected `NOT EXISTS (subquery)` clause.
156     *
157     * @param  QueryBuilder  $query  The existential subquery.
158     * @return ModelQueryBuilder<static>
159     */
160    public static function orWhereNotExists(QueryBuilder $query): ModelQueryBuilder
161    {
162        return static::whereExists($query, WhereBoolean::Or, true);
163    }
164
165    /**
166     * Start a model query with a `column IN (subquery)` clause.
167     *
168     * The subquery must select exactly one column.
169     *
170     * @param  string  $column  The outer column the IN constrains.
171     * @param  QueryBuilder  $query  The single-column value subquery.
172     * @param  WhereBoolean  $boolean
173     * @param  bool  $negated  True renders `NOT IN`.
174     * @return ModelQueryBuilder<static>
175     */
176    abstract public static function whereInQuery(
177        string $column,
178        QueryBuilder $query,
179        WhereBoolean $boolean = WhereBoolean::And,
180        bool $negated = false,
181    ): ModelQueryBuilder;
182
183    /**
184     * Start a model query with a `column NOT IN (subquery)` clause.
185     *
186     * @param  string  $column  The outer column the NOT IN constrains.
187     * @param  QueryBuilder  $query  The single-column value subquery.
188     * @param  WhereBoolean  $boolean
189     * @return ModelQueryBuilder<static>
190     */
191    public static function whereNotInQuery(string $column, QueryBuilder $query, WhereBoolean $boolean = WhereBoolean::And): ModelQueryBuilder
192    {
193        return static::whereInQuery($column, $query, $boolean, true);
194    }
195
196    /**
197     * Start a model query with an OR-connected `column IN (subquery)` clause.
198     *
199     * @param  string  $column  The outer column the IN constrains.
200     * @param  QueryBuilder  $query  The single-column value subquery.
201     * @return ModelQueryBuilder<static>
202     */
203    public static function orWhereInQuery(string $column, QueryBuilder $query): ModelQueryBuilder
204    {
205        return static::whereInQuery($column, $query, WhereBoolean::Or);
206    }
207
208    /**
209     * Start a model query with an OR-connected `column NOT IN (subquery)` clause.
210     *
211     * @param  string  $column  The outer column the NOT IN constrains.
212     * @param  QueryBuilder  $query  The single-column value subquery.
213     * @return ModelQueryBuilder<static>
214     */
215    public static function orWhereNotInQuery(string $column, QueryBuilder $query): ModelQueryBuilder
216    {
217        return static::whereInQuery($column, $query, WhereBoolean::Or, true);
218    }
219
220    /**
221     * Start a model query with an `or where` clause.
222     *
223     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
224     * @param  WhereOperator|string  $operator
225     * @param  mixed  $value
226     * @return ModelQueryBuilder<static>
227     */
228    public static function orWhere(
229        string|\BlueprintAU\Radiant\Database\Query\Expression $column,
230        WhereOperator|string $operator,
231        mixed $value,
232    ): ModelQueryBuilder {
233        return static::where($column, $operator, $value, WhereBoolean::Or);
234    }
235
236    /**
237     * Start a model query with a `where in` clause.
238     *
239     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
240     * @param  array<int, mixed>  $values
241     * @param  WhereBoolean  $boolean
242     * @return ModelQueryBuilder<static>
243     */
244    public static function whereIn(
245        string|\BlueprintAU\Radiant\Database\Query\Expression $column,
246        array $values,
247        WhereBoolean $boolean = WhereBoolean::And,
248    ): ModelQueryBuilder {
249        return static::where($column, WhereOperator::In, $values, $boolean);
250    }
251
252    /**
253     * Start a model query with a `where not in` clause.
254     *
255     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
256     * @param  array<int, mixed>  $values
257     * @param  WhereBoolean  $boolean
258     * @return ModelQueryBuilder<static>
259     */
260    public static function whereNotIn(
261        string|\BlueprintAU\Radiant\Database\Query\Expression $column,
262        array $values,
263        WhereBoolean $boolean = WhereBoolean::And,
264    ): ModelQueryBuilder {
265        return static::where($column, WhereOperator::NotIn, $values, $boolean);
266    }
267
268    /**
269     * Start a model query with a `where null` clause.
270     *
271     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
272     * @param  WhereBoolean  $boolean
273     * @return ModelQueryBuilder<static>
274     */
275    public static function whereNull(string|\BlueprintAU\Radiant\Database\Query\Expression $column, WhereBoolean $boolean = WhereBoolean::And): ModelQueryBuilder
276    {
277        return static::where($column, WhereOperator::Null, null, $boolean);
278    }
279
280    /**
281     * Start a model query with a `where not null` clause.
282     *
283     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
284     * @param  WhereBoolean  $boolean
285     * @return ModelQueryBuilder<static>
286     */
287    public static function whereNotNull(string|\BlueprintAU\Radiant\Database\Query\Expression $column, WhereBoolean $boolean = WhereBoolean::And): ModelQueryBuilder
288    {
289        return static::where($column, WhereOperator::NotNull, null, $boolean);
290    }
291
292    /**
293     * Start a model query with a `where between` clause.
294     *
295     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
296     * @param  array{0: mixed, 1: mixed}  $range
297     * @param  WhereBoolean  $boolean
298     * @return ModelQueryBuilder<static>
299     */
300    public static function whereBetween(string|\BlueprintAU\Radiant\Database\Query\Expression $column, array $range, WhereBoolean $boolean = WhereBoolean::And): ModelQueryBuilder
301    {
302        return static::where($column, WhereOperator::Between, $range, $boolean);
303    }
304
305    /**
306     * Start a model query with a `where not between` clause.
307     *
308     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
309     * @param  array{0: mixed, 1: mixed}  $range
310     * @param  WhereBoolean  $boolean
311     * @return ModelQueryBuilder<static>
312     */
313    public static function whereNotBetween(string|\BlueprintAU\Radiant\Database\Query\Expression $column, array $range, WhereBoolean $boolean = WhereBoolean::And): ModelQueryBuilder
314    {
315        return static::where($column, WhereOperator::NotBetween, $range, $boolean);
316    }
317
318    /**
319     * Start a model query with a `where like` clause — the pattern is a
320     * bound value.
321     *
322     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
323     * @param  string  $pattern
324     * @param  WhereBoolean  $boolean
325     * @return ModelQueryBuilder<static>
326     */
327    public static function whereLike(string|\BlueprintAU\Radiant\Database\Query\Expression $column, string $pattern, WhereBoolean $boolean = WhereBoolean::And): ModelQueryBuilder
328    {
329        return static::where($column, WhereOperator::Like, $pattern, $boolean);
330    }
331
332    /**
333     * Start a model query with an OR-connected `where like` clause.
334     *
335     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
336     * @param  string  $pattern
337     * @return ModelQueryBuilder<static>
338     */
339    public static function orWhereLike(string|\BlueprintAU\Radiant\Database\Query\Expression $column, string $pattern): ModelQueryBuilder
340    {
341        return static::where($column, WhereOperator::Like, $pattern, WhereBoolean::Or);
342    }
343
344    /**
345     * Start a model query with a `where not like` clause.
346     *
347     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
348     * @param  string  $pattern
349     * @param  WhereBoolean  $boolean
350     * @return ModelQueryBuilder<static>
351     */
352    public static function whereNotLike(string|\BlueprintAU\Radiant\Database\Query\Expression $column, string $pattern, WhereBoolean $boolean = WhereBoolean::And): ModelQueryBuilder
353    {
354        return static::where($column, WhereOperator::NotLike, $pattern, $boolean);
355    }
356
357    /**
358     * Start a model query with an order-by clause.
359     *
360     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression  $column
361     * @param  SortDirection|string  $direction
362     * @return ModelQueryBuilder<static>
363     */
364    abstract public static function orderBy(
365        string|\BlueprintAU\Radiant\Database\Query\Expression $column,
366        SortDirection|string $direction = SortDirection::Asc,
367    ): ModelQueryBuilder;
368
369    /**
370     * Start a model query with a row limit.
371     *
372     * @param  int  $limit
373     * @return ModelQueryBuilder<static>
374     */
375    abstract public static function limit(int $limit): ModelQueryBuilder;
376
377    /**
378     * Start a model query with a row offset.
379     *
380     * @param  int  $offset
381     * @return ModelQueryBuilder<static>
382     */
383    abstract public static function offset(int $offset): ModelQueryBuilder;
384
385    /**
386     * Start a model query with an explicit column selection.
387     *
388     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression|\BlueprintAU\Radiant\Database\Query\Aggregate  ...$columns
389     * @return ModelQueryBuilder<static>
390     */
391    abstract public static function select(string|\BlueprintAU\Radiant\Database\Query\Expression|\BlueprintAU\Radiant\Database\Query\Aggregate ...$columns): ModelQueryBuilder;
392
393    /**
394     * Start a model query grouped by one or more columns.
395     *
396     * @param  string|array<int, string>  $columns
397     * @return ModelQueryBuilder<static>
398     */
399    abstract public static function groupBy(string|array $columns): ModelQueryBuilder;
400
401    /**
402     * Start a model query with a having clause.
403     *
404     * @param  string|\BlueprintAU\Radiant\Database\Query\Expression|\BlueprintAU\Radiant\Database\Query\Aggregate  $column
405     * @param  WhereOperator|string  $operator
406     * @param  mixed  $value
407     * @return ModelQueryBuilder<static>
408     */
409    abstract public static function having(
410        string|\BlueprintAU\Radiant\Database\Query\Expression|\BlueprintAU\Radiant\Database\Query\Aggregate $column,
411        WhereOperator|string $operator,
412        mixed $value,
413    ): ModelQueryBuilder;
414}