Throw Exception if the required functions are defined in incorrect order

Signed-off-by: davidarendsen <davidarendsen@hey.com>
This commit is contained in:
davidarendsen 2022-09-01 15:17:25 +00:00
commit 3a112f4e79
4 changed files with 103 additions and 68 deletions

View file

@ -19,8 +19,8 @@ use Arendsen\FluxQueryBuilder\Expression\KeyValue;
$queryBuilder = new QueryBuilder();
$queryBuilder->fromBucket('test_bucket')
->fromMeasurement('test_measurement')
->addRangeStart(new DateTime('3 hours ago'))
->fromMeasurement('test_measurement')
->addFilter(
KeyValue::setEqualTo('_field', 'username')
->orEqualTo('_field', 'email')
@ -39,7 +39,7 @@ composer test
## Coding style
Run the following commands to check the coding style. We're using the PSR12 standard.
Run the following commands to check and fix the coding style. We're using the PSR12 standard.
```
composer check

View file

@ -0,0 +1,21 @@
<?php
namespace Arendsen\FluxQueryBuilder\Functions;
class RawFunction extends Base
{
/**
* @var string $input
*/
private $input;
public function __construct(string $input)
{
$this->input = $input;
}
public function __toString()
{
return $this->input . ' ';
}
}

View file

@ -16,6 +16,7 @@ use Arendsen\FluxQueryBuilder\Functions\Map;
use Arendsen\FluxQueryBuilder\Functions\Group;
use Arendsen\FluxQueryBuilder\Functions\Limit;
use Arendsen\FluxQueryBuilder\Functions\Mean;
use Arendsen\FluxQueryBuilder\Functions\RawFunction;
use Arendsen\FluxQueryBuilder\Functions\Window;
class QueryBuilder
@ -33,33 +34,23 @@ class QueryBuilder
public const FLUX_PART_DUPLICATE = 'duplicate';
public const FLUX_PART_UNWINDOW = 'unwindow';
public const FLUX_PART_AGGREGATEWINDOW = 'aggregateWindow';
public const PARTS = [
self::FLUX_PART_FROM,
self::FLUX_PART_RANGE,
self::FLUX_PART_REDUCE,
self::FLUX_PART_WINDOW,
self::FLUX_PART_MEAN,
self::FLUX_PART_DUPLICATE,
self::FLUX_PART_FILTERS,
self::FLUX_PART_MAP,
self::FLUX_PART_SORT,
self::FLUX_PART_GROUP,
self::FLUX_PART_LIMIT,
self::FLUX_PART_UNWINDOW,
self::FLUX_PART_AGGREGATEWINDOW,
];
public const FLUX_PART_RAWFUNCTION = 'raw';
public const REQUIRED_INPUT_FROM = 'from';
public const REQUIRED_INPUT_MEASUREMENT = 'measurement';
public const REQUIRED_INPUT_RANGE = 'range';
public const REQUIRED_INPUT_MEASUREMENT = 'measurement';
public const REQUIRED_INPUT = [
self::REQUIRED_INPUT_FROM,
self::REQUIRED_INPUT_MEASUREMENT,
self::REQUIRED_INPUT_RANGE,
self::REQUIRED_INPUT_MEASUREMENT,
];
/**
* @var int $currentFluxQueryPart
*/
private $currentFluxQueryPart = 0;
/**
* @var array $fluxQuery
*/
@ -89,16 +80,13 @@ class QueryBuilder
public function fromMeasurement(string $measurement): QueryBuilder
{
$this->addRequiredData(self::REQUIRED_INPUT_MEASUREMENT, $measurement);
$this->addToQueryArray(
self::FLUX_PART_FILTERS,
new Filter(KeyValue::setEqualTo('_measurement', $measurement))
);
$this->addFilter(KeyValue::setEqualTo('_measurement', $measurement));
return $this;
}
public function addFilter(KeyValue $keyValue): QueryBuilder
{
$this->addToQueryArray(
$this->addToQuery(
self::FLUX_PART_FILTERS,
new Filter($keyValue)
);
@ -107,7 +95,7 @@ class QueryBuilder
public function addFieldFilter(array $fields): QueryBuilder
{
$this->addToQueryArray(
$this->addToQuery(
self::FLUX_PART_FILTERS,
new Filter($fields)
);
@ -138,7 +126,7 @@ class QueryBuilder
public function addReduce(array $settings, array $identity): QueryBuilder
{
$this->addToQueryArray(
$this->addToQuery(
self::FLUX_PART_REDUCE,
new Reduce($settings, $identity)
);
@ -147,7 +135,7 @@ class QueryBuilder
public function addSort(array $columns, $desc): QueryBuilder
{
$this->addToQueryArray(
$this->addToQuery(
self::FLUX_PART_SORT,
new Sort($columns, $desc)
);
@ -156,7 +144,7 @@ class QueryBuilder
public function addMap(string $query): QueryBuilder
{
$this->addToQueryArray(
$this->addToQuery(
self::FLUX_PART_MAP,
new Map($query)
);
@ -165,7 +153,7 @@ class QueryBuilder
public function addGroup(array $columns, $mode = 'by'): QueryBuilder
{
$this->addToQueryArray(
$this->addToQuery(
self::FLUX_PART_GROUP,
new Group($columns, $mode)
);
@ -174,7 +162,7 @@ class QueryBuilder
public function addLimit(int $limit): QueryBuilder
{
$this->addToQueryArray(
$this->addToQuery(
self::FLUX_PART_LIMIT,
new Limit($limit)
);
@ -226,14 +214,19 @@ class QueryBuilder
return $this;
}
protected function addToQuery($key, $query)
public function addRawFunction(string $input): QueryBuilder
{
$this->fluxQueryParts[$key] = $query;
$this->addToQuery(
self::FLUX_PART_RAWFUNCTION,
new RawFunction($input)
);
return $this;
}
protected function addToQueryArray($key, $query)
protected function addToQuery($key, $query)
{
$this->fluxQueryParts[$key][] = $query;
$this->fluxQueryParts[$this->currentFluxQueryPart] = $query;
$this->currentFluxQueryPart++;
}
public function build(): string
@ -242,16 +235,8 @@ class QueryBuilder
$query = '';
foreach (self::PARTS as $part) {
if (isset($this->fluxQueryParts[$part])) {
if (is_array($this->fluxQueryParts[$part])) {
foreach ($this->fluxQueryParts[$part] as $filter) {
$query .= $filter;
}
} else {
$query .= $this->fluxQueryParts[$part];
}
}
foreach ($this->fluxQueryParts as $part) {
$query .= $part;
}
return $query;
@ -259,13 +244,13 @@ class QueryBuilder
protected function addRequiredData(string $key, $value)
{
$this->requiredData[$key] = $value;
$this->requiredData[][$key] = $value;
}
protected function checkRequired()
{
foreach (self::REQUIRED_INPUT as $input) {
if (!isset($this->requiredData[$input])) {
foreach (self::REQUIRED_INPUT as $key => $input) {
if (!isset($this->requiredData[$key][$input])) {
throw new Exception('You need to define the "' . $input . '" part of the query!');
}
}

View file

@ -20,8 +20,8 @@ final class QueryBuilderTest extends TestCase
{
$queryBuilder = new QueryBuilder();
$queryBuilder->from($bucket)
->fromMeasurement($measurement)
->addRangeStart($range);
->addRangeStart($range)
->fromMeasurement($measurement);
if ($keyValue) {
$queryBuilder->addFilter($keyValue);
@ -69,12 +69,12 @@ final class QueryBuilderTest extends TestCase
if ($from) {
$queryBuilder->from($from);
}
if ($measurement) {
$queryBuilder->fromMeasurement($measurement);
}
if ($range) {
$queryBuilder->addRangeStart($range['start']);
}
if ($measurement) {
$queryBuilder->fromMeasurement($measurement);
}
$queryBuilder->build();
}
@ -94,17 +94,29 @@ final class QueryBuilderTest extends TestCase
];
}
public function testThrowsExceptionWhenIncorrectOrder()
{
$this->expectException(Exception::class);
$queryBuilder = new QueryBuilder();
$queryBuilder->from(['bucket' => 'test_bucket'])
->fromMeasurement('test_measurement')
->addRangeStart(new DateTime('2022-08-12 20:05:00'));
$queryBuilder->build();
}
public function testComplexQuery()
{
$queryBuilder = new QueryBuilder();
$queryBuilder->fromBucket('test_bucket')
->fromMeasurement('test_measurement')
->addRangeStart(new DateTime('2022-08-12 17:31:00'))
->addFieldFilter(['username', 'ip'])
->addMap('r with name: r.user')
->addGroup(['_field', 'ip'])
->addReduce(['count' => new MathType('accumulator.count + 1')], ['count' => 0])
->addFilter(KeyValue::setGreaterOrEqualTo('count', 1)->andGreaterOrEqualTo('count2', 2));
->fromMeasurement('test_measurement')
->addFieldFilter(['username', 'ip'])
->addFilter(KeyValue::setGreaterOrEqualTo('count', 1)->andGreaterOrEqualTo('count2', 2))
->addMap('r with name: r.user')
->addGroup(['_field', 'ip']);
$expectedQuery = 'from(bucket: "test_bucket") |> range(start: time(v: 2022-08-12T17:31:00Z)) ' .
'|> reduce(fn: (r, accumulator) => ({count: accumulator.count + 1}), identity: {count: 0}) ' .
@ -119,12 +131,12 @@ final class QueryBuilderTest extends TestCase
{
$queryBuilder = new QueryBuilder();
$queryBuilder->fromBucket('test_bucket')
->fromMeasurement('test_measurement')
->addRangeStart(new DateTime('2022-08-12 17:31:00'))
->addWindow('20s')
->addReduce(['count' => new MathType('accumulator.count + 1')], ['count' => 0])
->addWindow('20s')
->addMean()
->addDuplicate('tag', 'tag_dup')
->fromMeasurement('test_measurement')
->addFilter(KeyValue::setGreaterOrEqualTo('count', 1)->andGreaterOrEqualTo('count2', 2))
->addUnWindow();
@ -141,10 +153,27 @@ final class QueryBuilderTest extends TestCase
{
$queryBuilder = new QueryBuilder();
$queryBuilder->fromBucket('test_bucket')
->fromMeasurement('test_measurement')
->addRangeStart(new DateTime('2022-08-12 17:31:00'))
->addAggregateWindow('20s', 'mean', ['timeDst' => '_time'])
->addReduce(['count' => new MathType('accumulator.count + 1')], ['count' => 0]);
->addReduce(['count' => new MathType('accumulator.count + 1')], ['count' => 0])
->fromMeasurement('test_measurement')
->addAggregateWindow('20s', 'mean', ['timeDst' => '_time']);
$expectedQuery = 'from(bucket: "test_bucket") |> range(start: time(v: 2022-08-12T17:31:00Z)) ' .
'|> reduce(fn: (r, accumulator) => ({count: accumulator.count + 1}), identity: {count: 0}) ' .
'|> filter(fn: (r) => r._measurement == "test_measurement") ' .
'|> aggregateWindow(every: 20s, fn: mean, timeDst: "_time") ';
$this->assertEquals($expectedQuery, $queryBuilder->build());
}
public function testRawQuery()
{
$queryBuilder = new QueryBuilder();
$queryBuilder->fromBucket('test_bucket')
->addRangeStart(new DateTime('2022-08-12 17:31:00'))
->addReduce(['count' => new MathType('accumulator.count + 1')], ['count' => 0])
->fromMeasurement('test_measurement')
->addRawFunction('|> aggregateWindow(every: 20s, fn: mean, timeDst: "_time")');
$expectedQuery = 'from(bucket: "test_bucket") |> range(start: time(v: 2022-08-12T17:31:00Z)) ' .
'|> reduce(fn: (r, accumulator) => ({count: accumulator.count + 1}), identity: {count: 0}) ' .