Skip to content

Commit 315cabd

Browse files
committed
Support custom aliases for aggregations
1 parent e869d22 commit 315cabd

File tree

4 files changed

+49
-15
lines changed

4 files changed

+49
-15
lines changed

src/SQLProviders/SQLFunctions.php

+11-2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,19 @@ class SQLFunctions
2121

2222
final public static function validateArgument(string $argument): void
2323
{
24+
$columnRegex = "/^(((_*)?([A-Za-z0-9]+))+|\*)$/";
25+
if(strpos($argument, " as ")) {
26+
[$argument, $alias] = explode(" as ", $argument);
27+
if(!preg_match($columnRegex, $alias)) {
28+
throw new JsonQueryBuilderException(
29+
"Invalid alias name: {$alias}."
30+
);
31+
}
32+
}
33+
2434
$split = explode(':', $argument);
2535
$column = array_pop($split);
26-
27-
if (!preg_match("/^[a-zA-Z_][a-zA-Z0-9_]*|\*$/", $column) || in_array($column, self::DB_FUNCTIONS)) {
36+
if (!preg_match($columnRegex, $column) || in_array($column, self::DB_FUNCTIONS)) {
2837
throw new JsonQueryBuilderException(
2938
"Invalid column name: {$column}."
3039
);

src/Traits/DatabaseFunctions.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
trait DatabaseFunctions
1111
{
1212
public Builder $builder;
13+
public $alias;
1314

1415
protected array $providers = [
1516
'pgsql' => PgSQLFunctions::class,
@@ -28,13 +29,15 @@ private function applyAggregation(array $params): string
2829
$column = array_pop($params);
2930
$provider = $this->builder->getModel()->connection ?? config('database.default');
3031
$functions = $this->providers[$provider] ?? SQLFunctions::class;
32+
if (strpos($column, " as ")) {
33+
[$column, $this->alias] = explode(" as ", $column);
34+
}
3135

3236
return array_reduce(array_reverse($params), function ($query, $param) use (
3337
$column,
3438
$functions
3539
) {
3640
$stat = $query ?? ('*' !== $column ? "\"$column\"" : $column);
37-
3841
return $functions::$param($stat);
3942
});
4043
}
@@ -47,8 +50,9 @@ protected function prepareArguments(): void
4750
}
4851
$split = explode(':', $argument);
4952
$apply = $this->applyAggregation($split);
50-
$alias = join('_', array_filter($split, fn ($s) => '*' !== $s));
5153

54+
if(last($split) === '*') array_pop($split);
55+
$alias = $this->alias ?? join('_', $split);
5256
return DB::raw("{$apply} as {$alias}");
5357
}, $this->arguments);
5458
}

tests/Unit/SQLProviders/SQLFunctionsTest.php

+25-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
declare(strict_types=1);
3+
declare (strict_types = 1);
44

55
namespace Asseco\JsonQueryBuilder\Tests\Unit\SQLProviders;
66

@@ -26,27 +26,41 @@ public function test_it_returns_the_right_functions_query()
2626
}
2727
}
2828

29-
public function test_it_throws_an_exception_if_an_invalid_function_is_given()
30-
{
31-
$this->expectException(\Asseco\JsonQueryBuilder\Exceptions\JsonQueryBuilderException::class);
32-
$this->functions::invalidFunction('id');
33-
}
34-
3529
public function test_it_validate_sql_functions()
3630
{
31+
$this->expectNotToPerformAssertions();
3732
foreach (SQLFunctions::DB_FUNCTIONS as $fn) {
38-
$this->assertNull($this->functions::validateArgument($fn . ':column'));
33+
$this->functions::validateArgument($fn . ':column');
3934
}
4035
}
4136

4237
public function test_it_validate_nested_functions_validation()
4338
{
44-
$this->assertNull($this->functions::validateArgument('avg:year:column'));
39+
$this->expectNotToPerformAssertions();
40+
$this->functions::validateArgument('avg:year:column');
4541
}
4642

4743
public function test_it_bypass_when_no_function_is_given()
4844
{
49-
$this->assertNull($this->functions::validateArgument('column'));
45+
$this->expectNotToPerformAssertions();
46+
$this->functions::validateArgument('column');
47+
}
48+
49+
public function test_it_validate_custom_aliases()
50+
{
51+
$this->expectNotToPerformAssertions();
52+
$this->functions::validateArgument("avg:_column as my_avg");
53+
}
54+
55+
public function test_it_throws_if_alias_is_not_valid() {
56+
$this->expectException(\Asseco\JsonQueryBuilder\Exceptions\JsonQueryBuilderException::class);
57+
$this->functions::validateArgument("avg:column as my_avg`ds");
58+
}
59+
60+
public function test_it_throws_an_exception_if_an_invalid_function_is_given()
61+
{
62+
$this->expectException(\Asseco\JsonQueryBuilder\Exceptions\JsonQueryBuilderException::class);
63+
$this->functions::invalidFunction('id');
5064
}
5165

5266
public function test_it_throws_an_exception_if_an_invalid_argument_is_given()
@@ -58,7 +72,7 @@ public function test_it_throws_an_exception_if_an_invalid_argument_is_given()
5872
public function test_it_throws_an_exception_if_an_invalid_column_is_given()
5973
{
6074
$this->expectException(\Asseco\JsonQueryBuilder\Exceptions\JsonQueryBuilderException::class);
61-
$this->functions::validateArgument("avg:'this--sql-scripting-is-invalid'");
75+
$this->functions::validateArgument("avg:'this--sql-scripting-is-`invalid'");
6276
}
6377

6478
public function test_it_throws_an_exception_if_no_column_is_given()

tests/Unit/Traits/DatabaseFunctionsTest.php

+7
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,11 @@ public function test_it_parses_right_count_all_query()
8181
$this->assertNull($parameter->run());
8282
$this->assertEquals('select count(*) as count', $this->builder->toSql());
8383
}
84+
85+
function test_it_should_use_the_right_alias_parameter() {
86+
app('config')->set('database.default', 'pgsql');
87+
$parameter = new TestParameterClass(['avg:day:column as the_avg'], $this->builder, $this->modelConfig);
88+
$this->assertNull($parameter->run());
89+
$this->assertEquals('select avg(EXTRACT(DAY FROM "column")) as the_avg', $this->builder->toSql());
90+
}
8491
}

0 commit comments

Comments
 (0)