Passed
Push — master ( 8e1e0b...949968 )
by Teye
16:13
created

HasAggregations::floatAny()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 3
crap 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Level23\Druid\Concerns;
5
6
use Closure;
7
use InvalidArgumentException;
8
use Level23\Druid\Types\DataType;
9
use Level23\Druid\Dimensions\Dimension;
10
use Level23\Druid\Filters\FilterBuilder;
11
use Level23\Druid\Filters\FilterInterface;
12
use Level23\Druid\Aggregations\MaxAggregator;
13
use Level23\Druid\Aggregations\MinAggregator;
14
use Level23\Druid\Aggregations\SumAggregator;
15
use Level23\Druid\Aggregations\AnyAggregator;
16
use Level23\Druid\Aggregations\LastAggregator;
17
use Level23\Druid\Dimensions\DimensionBuilder;
18
use Level23\Druid\Aggregations\CountAggregator;
19
use Level23\Druid\Aggregations\FirstAggregator;
20
use Level23\Druid\Aggregations\FilteredAggregator;
21
use Level23\Druid\Collections\DimensionCollection;
22
use Level23\Druid\Aggregations\AggregatorInterface;
23
use Level23\Druid\Aggregations\JavascriptAggregator;
24
use Level23\Druid\Aggregations\HyperUniqueAggregator;
25
use Level23\Druid\Aggregations\CardinalityAggregator;
26
use Level23\Druid\Aggregations\DistinctCountAggregator;
27
28
trait HasAggregations
29
{
30
    /**
31
     * @var \Level23\Druid\DruidClient
32
     */
33
    protected $client;
34
35
    /**
36
     * @var null|\Level23\Druid\Queries\QueryBuilder
37
     */
38
    protected $query;
39
40
    /**
41
     * @var array|\Level23\Druid\Aggregations\AggregatorInterface[]
42
     */
43
    protected $aggregations = [];
44
45
    /**
46
     * @return array|\Level23\Druid\Aggregations\AggregatorInterface[]
47
     */
48 1
    public function getAggregations(): array
49
    {
50 1
        return $this->aggregations;
51
    }
52
53
    /**
54
     * Sum the given metric
55
     *
56
     * @param string        $metric
57
     * @param string        $as
58
     * @param string        $type
59
     * @param \Closure|null $filterBuilder   A closure which receives a FilterBuilder. When given, we will only apply
60
     *                                       the "sum" function to the records which match with the given filter.
61
     *
62
     * @return $this
63
     */
64 15
    public function sum(string $metric, string $as = '', string $type = DataType::LONG, Closure $filterBuilder = null)
65
    {
66 15
        $this->aggregations[] = $this->buildFilteredAggregation(
67 15
            new SumAggregator($metric, $as, $type),
68
            $filterBuilder
69
        );
70
71 14
        return $this;
72
    }
73
74
    /**
75
     * Shorthand for summing long's
76
     *
77
     * @param string        $metric
78
     * @param string        $as
79
     * @param \Closure|null $filterBuilder   A closure which receives a FilterBuilder. When given, we will only apply
80
     *                                       the "sum" function to the records which match with the given filter.
81
     *
82
     * @return $this
83
     */
84 7
    public function longSum(string $metric, string $as = '', Closure $filterBuilder = null)
85
    {
86 7
        return $this->sum($metric, $as, DataType::LONG, $filterBuilder);
87
    }
88
89
    /**
90
     * Shorthand for summing doubles
91
     *
92
     * @param string        $metric
93
     * @param string        $as
94
     * @param \Closure|null $filterBuilder   A closure which receives a FilterBuilder. When given, we will only apply
95
     *                                       the "sum" function to the records which match with the given filter.
96
     *
97
     * @return $this
98
     */
99 1
    public function doubleSum(string $metric, string $as = '', Closure $filterBuilder = null)
100
    {
101 1
        return $this->sum($metric, $as, DataType::DOUBLE, $filterBuilder);
102
    }
103
104
    /**
105
     * Shorthand for summing floats
106
     *
107
     * @param string        $metric
108
     * @param string        $as
109
     * @param \Closure|null $filterBuilder   A closure which receives a FilterBuilder. When given, we will only apply
110
     *                                       the "sum" function to the records which match with the given filter.
111
     *
112
     * @return $this
113
     */
114 1
    public function floatSum(string $metric, string $as = '', Closure $filterBuilder = null)
115
    {
116 1
        return $this->sum($metric, $as, DataType::FLOAT, $filterBuilder);
117
    }
118
119
    /**
120
     * Uses HyperLogLog to compute the estimated cardinality of a dimension that has been aggregated as a "hyperUnique"
121
     * metric at indexing time.
122
     *
123
     * @see http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf
124
     *
125
     * @param string $metric
126
     * @param string $as
127
     * @param bool   $round              Only affects query-time behavior, and is ignored at ingestion-time. The
128
     *                                   HyperLogLog algorithm generates decimal estimates with some error. "round" can
129
     *                                   be set to true to round off estimated values to whole numbers. Note that even
130
     *                                   with rounding, the cardinality is still an estimate.
131
     * @param bool   $isInputHyperUnique Only affects ingestion-time behavior, and is ignored at query-time. Set to
132
     *                                   true to index pre-computed HLL (Base64 encoded output from druid-hll is
133
     *                                   expected).
134
     *
135
     * @return $this
136
     */
137 5
    public function hyperUnique(string $metric, string $as, bool $round = false, bool $isInputHyperUnique = false)
138
    {
139 5
        $this->aggregations[] = new HyperUniqueAggregator(
140
            $as, $metric, $isInputHyperUnique, $round
141
        );
142
143 5
        return $this;
144
    }
145
146
    /**
147
     * Computes the cardinality of a set of Apache Druid (incubating) dimensions, using HyperLogLog to estimate the
148
     * cardinality. Please note that this aggregator will be much slower than indexing a column with the hyperUnique
149
     * aggregator. This aggregator also runs over a dimension column, which means the string dimension cannot be
150
     * removed from the dataset to improve rollup. In general, we strongly recommend using the hyperUnique aggregator
151
     * instead of the cardinality aggregator if you do not care about the individual values of a dimension.
152
     *
153
     * The HyperLogLog algorithm generates decimal estimates with some error. "round" can be set to true to round off
154
     * estimated values to whole numbers. Note that even with rounding, the cardinality is still an estimate. The
155
     * "round" field only affects query-time behavior, and is ignored at ingestion-time.
156
     *
157
     * When setting byRow to false (the default) it computes the cardinality of the set composed of the union of all
158
     * dimension values for all the given dimensions. For a single dimension, this is equivalent to:
159
     * ```
160
     * SELECT COUNT(DISTINCT(dimension)) FROM <datasource>
161
     * ```
162
     *
163
     * For multiple dimensions, this is equivalent to something akin to
164
     * ```
165
     * SELECT COUNT(DISTINCT(value)) FROM (
166
     * SELECT dim_1 as value FROM <datasource>
167
     * UNION
168
     * SELECT dim_2 as value FROM <datasource>
169
     * UNION
170
     * SELECT dim_3 as value FROM <datasource>
171
     * )
172
     * ```
173
     *
174
     * When setting byRow to true it computes the cardinality by row, i.e. the cardinality of distinct dimension
175
     * combinations. This is equivalent to something akin to
176
     *
177
     * ```
178
     * SELECT COUNT(*) FROM ( SELECT DIM1, DIM2, DIM3 FROM <datasource> GROUP BY DIM1, DIM2, DIM3 )
179
     * ```
180
     *
181
     * @see https://druid.apache.org/docs/latest/querying/hll-old.html
182
     *
183
     * @param string         $as                           The output name which is used for the result.
184
     * @param \Closure|array $dimensionsOrDimensionBuilder An array with the dimensions which you want to calculate the
185
     *                                                     cardinality over, or a closure which will receive a
186
     *                                                     DimensionBuilder. You should build the dimensions which are
187
     *                                                     used to calculate the cardinality over.
188
     * @param bool           $byRow                        For more details see method description.
189
     * @param bool           $round                        Only affects query-time behavior, and is ignored at
190
     *                                                     ingestion-time. The HyperLogLog algorithm generates decimal
191
     *                                                     estimates with some error. "round" can be set to true to
192
     *                                                     round off estimated values to whole numbers. Note that even
193
     *                                                     with rounding, the cardinality is still an estimate.
194
     *
195
     * @return $this
196
     */
197 7
    public function cardinality(string $as, $dimensionsOrDimensionBuilder, bool $byRow = false, bool $round = false)
198
    {
199 7
        if ($dimensionsOrDimensionBuilder instanceof Closure) {
200 5
            $builder = new DimensionBuilder();
201 5
            call_user_func($dimensionsOrDimensionBuilder, $builder);
202 5
            $dimensions = $builder->getDimensions();
203 2
        } elseif (is_array($dimensionsOrDimensionBuilder)) {
204 1
            $dimensions = [];
205
206 1
            foreach ($dimensionsOrDimensionBuilder as $dimension) {
207 1
                $dimensions[] = new Dimension($dimension);
208
            }
209
        } else {
210 1
            throw new InvalidArgumentException('You should supply a Closure function or an array.');
211
        }
212
213 6
        $this->aggregations[] = new CardinalityAggregator(
214
            $as,
215 6
            new DimensionCollection(...$dimensions),
216
            $byRow,
217
            $round
218
        );
219
220 6
        return $this;
221
    }
222
223
    /**
224
     * When a closure is given, we will call the given function which is responsible for building a filter.
225
     * We will then only apply the given aggregator for the records where the filter matches.
226
     *
227
     * @param \Level23\Druid\Aggregations\AggregatorInterface $aggregator
228
     * @param \Closure|null                                   $filterBuilder
229
     *
230
     * @return \Level23\Druid\Aggregations\AggregatorInterface
231
     */
232 16
    protected function buildFilteredAggregation(
233
        AggregatorInterface $aggregator,
234
        Closure $filterBuilder = null
235
    ): AggregatorInterface {
236 16
        if (!$filterBuilder) {
237 13
            return $aggregator;
238
        }
239
240 3
        $builder = new FilterBuilder($this->client, $this->query);
241 3
        call_user_func($filterBuilder, $builder);
242 2
        $filter = $builder->getFilter();
243
244 2
        if ($filter instanceof FilterInterface) {
245 1
            return new FilteredAggregator($filter, $aggregator);
246
        }
247
248 1
        return $aggregator;
249
    }
250
251
    /**
252
     * Count the number of results and put it in a dimension with the given name.
253
     *
254
     * @param string        $as
255
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only count the
256
     *                                     records which match with the given filter.
257
     *
258
     * @return $this
259
     */
260 1
    public function count(string $as, Closure $filterBuilder = null)
261
    {
262 1
        $this->aggregations[] = $this->buildFilteredAggregation(
263 1
            new CountAggregator($as),
264
            $filterBuilder
265
        );
266
267 1
        return $this;
268
    }
269
270
    /**
271
     * Count the number of distinct values of a specific dimension.
272
     * NOTE: The DataSketches Theta Sketch extension is required to run this aggregation.
273
     *
274
     * @param string        $dimension
275
     * @param string        $as
276
     * @param int           $size          Must be a power of 2. Internally, size refers to the maximum number of
277
     *                                     entries sketch object will retain. Higher size means higher accuracy but
278
     *                                     more space to store sketches. Note that after you index with a particular
279
     *                                     size, druid will persist sketch in segments and you will use size greater or
280
     *                                     equal to that at query time. See the DataSketches site for details. In
281
     *                                     general, We recommend just sticking to default size.
282
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only count the
283
     *                                     records which match with the given filter.
284
     *
285
     * @return $this
286
     */
287 2
    public function distinctCount(string $dimension, string $as = '', $size = 16384, Closure $filterBuilder = null)
288
    {
289 2
        $this->aggregations[] = $this->buildFilteredAggregation(
290 2
            new DistinctCountAggregator($dimension, ($as ?: $dimension), $size),
291
            $filterBuilder
292
        );
293
294 2
        return $this;
295
    }
296
297
    /**
298
     * Get the minimum value for the given metric
299
     *
300
     * @param string        $metric
301
     * @param string        $as
302
     * @param string        $type
303
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
304
     *                                     min function to the records which match with the given filter.
305
     *
306
     * @return $this
307
     */
308 2
    public function min(string $metric, string $as = '', $type = DataType::LONG, Closure $filterBuilder = null)
309
    {
310 2
        $this->aggregations[] = $this->buildFilteredAggregation(
311 2
            new MinAggregator($metric, $as, $type),
312
            $filterBuilder
313
        );
314
315 2
        return $this;
316
    }
317
318
    /**
319
     * Get the minimum value for the given metric using long as type
320
     *
321
     * @param string        $metric
322
     * @param string        $as
323
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
324
     *                                     min function to the records which match with the given filter.
325
     *
326
     * @return $this
327
     */
328 1
    public function longMin(string $metric, string $as = '', Closure $filterBuilder = null)
329
    {
330 1
        return $this->min($metric, $as, DataType::LONG, $filterBuilder);
331
    }
332
333
    /**
334
     * Get the minimum value for the given metric using double as type
335
     *
336
     * @param string        $metric
337
     * @param string        $as
338
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
339
     *                                     min function to the records which match with the given filter.
340
     *
341
     * @return $this
342
     */
343 1
    public function doubleMin(string $metric, string $as = '', Closure $filterBuilder = null)
344
    {
345 1
        return $this->min($metric, $as, DataType::DOUBLE, $filterBuilder);
346
    }
347
348
    /**
349
     * Get the minimum value for the given metric using float as type
350
     *
351
     * @param string        $metric
352
     * @param string        $as
353
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
354
     *                                     min function to the records which match with the given filter.
355
     *
356
     * @return $this
357
     */
358 1
    public function floatMin(string $metric, string $as = '', Closure $filterBuilder = null)
359
    {
360 1
        return $this->min($metric, $as, DataType::FLOAT, $filterBuilder);
361
    }
362
363
    /**
364
     * Get the maximum value for the given metric
365
     *
366
     * @param string        $metric
367
     * @param string        $as
368
     * @param string        $type
369
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
370
     *                                     max function to the records which match with the given filter.
371
     *
372
     * @return $this
373
     */
374 2
    public function max(string $metric, string $as = '', $type = DataType::LONG, Closure $filterBuilder = null)
375
    {
376 2
        $this->aggregations[] = $this->buildFilteredAggregation(
377 2
            new MaxAggregator($metric, $as, $type),
378
            $filterBuilder
379
        );
380
381 2
        return $this;
382
    }
383
384
    /**
385
     * Get the maximum value for the given metric using long as type
386
     *
387
     * @param string        $metric
388
     * @param string        $as
389
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
390
     *                                     max function to the records which match with the given filter.
391
     *
392
     * @return $this
393
     */
394 1
    public function longMax(string $metric, string $as = '', Closure $filterBuilder = null)
395
    {
396 1
        return $this->max($metric, $as, DataType::LONG, $filterBuilder);
397
    }
398
399
    /**
400
     * Get the maximum value for the given metric using float as type
401
     *
402
     * @param string        $metric
403
     * @param string        $as
404
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
405
     *                                     max function to the records which match with the given filter.
406
     *
407
     * @return $this
408
     */
409 1
    public function floatMax(string $metric, string $as = '', Closure $filterBuilder = null)
410
    {
411 1
        return $this->max($metric, $as, DataType::FLOAT, $filterBuilder);
412
    }
413
414
    /**
415
     * Get the maximum value for the given metric using double as type
416
     *
417
     * @param string        $metric
418
     * @param string        $as
419
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
420
     *                                     max function to the records which match with the given filter.
421
     *
422
     * @return $this
423
     */
424 1
    public function doubleMax(string $metric, string $as = '', Closure $filterBuilder = null)
425
    {
426 1
        return $this->max($metric, $as, DataType::DOUBLE, $filterBuilder);
427
    }
428
429
    /**
430
     * Get the any metric found based on the applied group-by filters.
431
     * Returns any value including null. This aggregator can simplify and
432
     * optimize the performance by returning the first encountered value (including null)
433
     *
434
     * ANY aggregator cannot be used in ingestion spec, and should only be specified as part of queries.
435
     *
436
     * @param string        $metric
437
     * @param string        $as
438
     * @param string        $type
439
     * @param int|null      $maxStringBytes For string types only. Optional, defaults to 1024.
440
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
441
     *                                     "any" function to the records which match with the given filter.
442
     *
443
     * @return $this
444
     */
445 2
    public function any(string $metric, string $as = '', $type = DataType::LONG, int $maxStringBytes = null, Closure $filterBuilder = null)
446
    {
447 2
        $this->aggregations[] = $this->buildFilteredAggregation(
448 2
            new AnyAggregator($metric, $as, $type, $maxStringBytes),
449
            $filterBuilder
450
        );
451
452 2
        return $this;
453
    }
454
455
    /**
456
     * Get the any metric found based on the applied group-by filters.
457
     * Returns any value including null. This aggregator can simplify and
458
     * optimize the performance by returning the first encountered value (including null)
459
     *
460
     * ANY aggregator cannot be used in ingestion spec, and should only be specified as part of queries.
461
     *
462
     * @param string        $metric
463
     * @param string        $as
464
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
465
     *                                     "any" function to the records which match with the given filter.
466
     *
467
     * @return $this
468
     */
469 1
    public function doubleAny(string $metric, string $as = '', Closure $filterBuilder = null)
470
    {
471 1
        return $this->any($metric, $as, DataType::DOUBLE, null, $filterBuilder);
472
    }
473
474
    /**
475
     * Get the any metric found based on the applied group-by filters.
476
     * Returns any value including null. This aggregator can simplify and
477
     * optimize the performance by returning the first encountered value (including null)
478
     *
479
     * ANY aggregator cannot be used in ingestion spec, and should only be specified as part of queries.
480
     *
481
     * @param string        $metric
482
     * @param string        $as
483
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
484
     *                                     "any" function to the records which match with the given filter.
485
     *
486
     * @return $this
487
     */
488 1
    public function floatAny(string $metric, string $as = '', Closure $filterBuilder = null)
489
    {
490 1
        return $this->any($metric, $as, DataType::FLOAT, null, $filterBuilder);
491
    }
492
493
    /**
494
     * Get the any metric found based on the applied group-by filters.
495
     * Returns any value including null. This aggregator can simplify and
496
     * optimize the performance by returning the first encountered value (including null)
497
     *
498
     * ANY aggregator cannot be used in ingestion spec, and should only be specified as part of queries.
499
     *
500
     * @param string        $metric
501
     * @param string        $as
502
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
503
     *                                     "any" function to the records which match with the given filter.
504
     *
505
     * @return $this
506
     */
507 1
    public function longAny(string $metric, string $as = '', Closure $filterBuilder = null)
508
    {
509 1
        return $this->any($metric, $as, DataType::LONG, null, $filterBuilder);
510
    }
511
512
    /**
513
     * Get the any metric found based on the applied group-by filters.
514
     * Returns any value including null. This aggregator can simplify and
515
     * optimize the performance by returning the first encountered value (including null)
516
     *
517
     * ANY aggregator cannot be used in ingestion spec, and should only be specified as part of queries.
518
     *
519
     * @param string        $metric
520
     * @param string        $as
521
     * @param int|null      $maxStringBytes Optional, defaults to 1024
522
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
523
     *                                     "any" function to the records which match with the given filter.
524
     *
525
     * @return $this
526
     */
527 1
    public function stringAny(string $metric, string $as = '', int $maxStringBytes = null, Closure $filterBuilder = null)
528
    {
529 1
        return $this->any($metric, $as, DataType::STRING, $maxStringBytes, $filterBuilder);
530
    }
531
532
    /**
533
     * Get the first metric found based on the applied group-by filters.
534
     * So if you group by the dimension "countries", you can get the first "metric" per country.
535
     *
536
     * NOTE: This is different from the Laravel ELOQUENT first() method!
537
     *
538
     * @param string        $metric
539
     * @param string        $as
540
     * @param string        $type
541
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
542
     *                                     "first" function to the records which match with the given filter.
543
     *
544
     * @return $this
545
     */
546 3
    public function first(string $metric, string $as = '', $type = DataType::LONG, Closure $filterBuilder = null)
547
    {
548 3
        $this->aggregations[] = $this->buildFilteredAggregation(
549 3
            new FirstAggregator($metric, $as, $type),
550
            $filterBuilder
551
        );
552
553 3
        return $this;
554
    }
555
556
    /**
557
     * Get the first metric found based on the applied group-by filters.
558
     * So if you group by the dimension "countries", you can get the first "metric" per country.
559
     *
560
     * NOTE: This is different from the Laravel ELOQUENT first() method!
561
     *
562
     * @param string        $metric
563
     * @param string        $as
564
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
565
     *                                     "first" function to the records which match with the given filter.
566
     *
567
     * @return $this
568
     */
569 1
    public function longFirst(string $metric, string $as = '', Closure $filterBuilder = null)
570
    {
571 1
        return $this->first($metric, $as, DataType::LONG, $filterBuilder);
572
    }
573
574
    /**
575
     * Get the first metric found based on the applied group-by filters.
576
     * So if you group by the dimension "countries", you can get the first "metric" per country.
577
     *
578
     * NOTE: This is different from the Laravel ELOQUENT first() method!
579
     *
580
     * @param string        $metric
581
     * @param string        $as
582
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
583
     *                                     "first" function to the records which match with the given filter.
584
     *
585
     * @return $this
586
     */
587 1
    public function floatFirst(string $metric, string $as = '', Closure $filterBuilder = null)
588
    {
589 1
        return $this->first($metric, $as, DataType::FLOAT, $filterBuilder);
590
    }
591
592
    /**
593
     * Get the first metric found based on the applied group-by filters.
594
     * So if you group by the dimension "countries", you can get the first "metric" per country.
595
     *
596
     * NOTE: This is different from the Laravel ELOQUENT first() method!
597
     *
598
     * @param string        $metric
599
     * @param string        $as
600
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
601
     *                                     "first" function to the records which match with the given filter.
602
     *
603
     * @return $this
604
     */
605 1
    public function doubleFirst(string $metric, string $as = '', Closure $filterBuilder = null)
606
    {
607 1
        return $this->first($metric, $as, DataType::DOUBLE, $filterBuilder);
608
    }
609
610
    /**
611
     * Get the first metric found based on the applied group-by filters.
612
     * So if you group by the dimension "countries", you can get the first "metric" per country.
613
     *
614
     * NOTE: This is different from the Laravel ELOQUENT first() method!
615
     *
616
     * @param string        $metric
617
     * @param string        $as
618
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
619
     *                                     "first" function to the records which match with the given filter.
620
     *
621
     * @return $this
622
     */
623 1
    public function stringFirst(string $metric, string $as = '', Closure $filterBuilder = null)
624
    {
625 1
        return $this->first($metric, $as, DataType::STRING, $filterBuilder);
626
    }
627
628
    /**
629
     * Get the last metric found
630
     *
631
     * @param string        $metric
632
     * @param string        $as
633
     * @param string        $type
634
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
635
     *                                     "last" function to the records which match with the given filter.
636
     *
637
     * @return $this
638
     */
639 2
    public function last(string $metric, string $as = '', $type = DataType::LONG, Closure $filterBuilder = null)
640
    {
641 2
        $this->aggregations[] = $this->buildFilteredAggregation(
642 2
            new LastAggregator($metric, $as, $type),
643
            $filterBuilder
644
        );
645
646 2
        return $this;
647
    }
648
649
    /**
650
     * Get the last metric found based on the applied group-by filters.
651
     * So if you group by the dimension "countries", you can get the last "metric" per country.
652
     *
653
     * NOTE: This is different then the ELOQUENT last() method!
654
     *
655
     * @param string        $metric
656
     * @param string        $as
657
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
658
     *                                     "last" function to the records which match with the given filter.
659
     *
660
     * @return $this
661
     */
662 1
    public function longLast(string $metric, string $as = '', Closure $filterBuilder = null)
663
    {
664 1
        return $this->last($metric, $as, DataType::LONG, $filterBuilder);
665
    }
666
667
    /**
668
     * Get the last metric found based on the applied group-by filters.
669
     * So if you group by the dimension "countries", you can get the last "metric" per country.
670
     *
671
     * NOTE: This is different then the ELOQUENT last() method!
672
     *
673
     * @param string        $metric
674
     * @param string        $as
675
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
676
     *                                     "last" function to the records which match with the given filter.
677
     *
678
     * @return $this
679
     */
680 1
    public function floatLast(string $metric, string $as = '', Closure $filterBuilder = null)
681
    {
682 1
        return $this->last($metric, $as, DataType::FLOAT, $filterBuilder);
683
    }
684
685
    /**
686
     * Get the last metric found based on the applied group-by filters.
687
     * So if you group by the dimension "countries", you can get the last "metric" per country.
688
     *
689
     * NOTE: This is different then the ELOQUENT last() method!
690
     *
691
     * @param string        $metric
692
     * @param string        $as
693
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
694
     *                                     "last" function to the records which match with the given filter.
695
     *
696
     * @return $this
697
     */
698 1
    public function doubleLast(string $metric, string $as = '', Closure $filterBuilder = null)
699
    {
700 1
        return $this->last($metric, $as, DataType::DOUBLE, $filterBuilder);
701
    }
702
703
    /**
704
     * Get the last metric found based on the applied group-by filters.
705
     * So if you group by the dimension "countries", you can get the last "metric" per country.
706
     *
707
     * NOTE: This is different then the ELOQUENT last() method!
708
     *
709
     * @param string        $metric
710
     * @param string        $as
711
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
712
     *                                     "last" function to the records which match with the given filter.
713
     *
714
     * @return $this
715
     */
716 1
    public function stringLast(string $metric, string $as = '', Closure $filterBuilder = null)
717
    {
718 1
        return $this->last($metric, $as, DataType::STRING, $filterBuilder);
719
    }
720
721
    /**
722
     * Computes an arbitrary JavaScript function over a set of columns (both metrics and dimensions are allowed). Your
723
     * JavaScript functions are expected to return floating-point values.
724
     *
725
     * Note: JavaScript-based functionality is disabled by default. Please refer to the Druid JavaScript programming
726
     * guide for guidelines about using Druid's JavaScript functionality, including instructions on how to enable it.
727
     *
728
     * @param string        $as            The output name as the result will be available
729
     * @param array         $fieldNames    The columns which will be given to the fnAggregate function. Both metrics
730
     *                                     and dimensions are allowed.
731
     * @param string        $fnAggregate   A javascript function which does the aggregation. This function will receive
732
     *                                     the "current" value as first parameter. The other parameters will be the
733
     *                                     values of the columns as given in the $fieldNames parameter.
734
     * @param string        $fnCombine     A function which can combine two aggregation results.
735
     * @param string        $fnReset       A function which will reset a value.
736
     * @param \Closure|null $filterBuilder A closure which receives a FilterBuilder. When given, we will only apply the
737
     *                                     javascript function to the records which match with the given filter.
738
     *
739
     * @return $this
740
     */
741 1
    public function javascript(
742
        string $as,
743
        array $fieldNames,
744
        string $fnAggregate,
745
        string $fnCombine,
746
        string $fnReset,
747
        Closure $filterBuilder = null
748
    ) {
749 1
        $this->aggregations[] = $this->buildFilteredAggregation(
750 1
            new JavascriptAggregator($fieldNames, $as, $fnAggregate, $fnCombine, $fnReset),
751
            $filterBuilder
752
        );
753
754 1
        return $this;
755
    }
756
}