Skip to content

Commit

Permalink
collection: extract numeric aggregation logic to aggregator
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Jul 12, 2022
1 parent 0642852 commit 1131b3f
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 101 deletions.
2 changes: 1 addition & 1 deletion src/Collection/Aggregations/IArrayAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface IArrayAggregator extends IAggregator
{
/**
* @param array<T> $values
* @return T
* @return T|null
*/
function aggregateValues(array $values);
}
54 changes: 54 additions & 0 deletions src/Collection/Aggregations/NumericAggregator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php declare(strict_types = 1);

namespace Nextras\Orm\Collection\Aggregations;


use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;


/**
* @internal
* @implements IArrayAggregator<number>
*/
class NumericAggregator implements IDbalAggregator, IArrayAggregator
{
/**
* @param callable(array<number>): (number|null) $arrayAggregation
* @param literal-string $dbalAggregationFunction
*/
public function __construct(
private readonly mixed $arrayAggregation,
private readonly string $dbalAggregationFunction,
)
{
}


public function getAggregateKey(): string
{
return '_' . $this->dbalAggregationFunction;
}


public function aggregateValues(array $values): mixed
{
$cb = $this->arrayAggregation;
return $cb($values);
}


public function aggregateExpression(
QueryBuilder $queryBuilder,
DbalExpressionResult $expression
): DbalExpressionResult
{
return new DbalExpressionResult(
expression: "{$this->dbalAggregationFunction}($expression->expression)",
args: $expression->args,
joins: $expression->joins,
groupBy: $expression->groupBy,
isHavingClause: true,
);
}
}
25 changes: 12 additions & 13 deletions src/Collection/Functions/AvgAggregateFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,24 @@
namespace Nextras\Orm\Collection\Functions;


use Nextras\Orm\Collection\Aggregations\NumericAggregator;
use function array_sum;
use function count;


class AvgAggregateFunction extends BaseAggregateFunction
class AvgAggregateFunction extends BaseNumericAggregateFunction
{
public function __construct()
{
parent::__construct('AVG');
}


protected function calculateAggregation(array $values)
{
$count = count($values);
if ($count === 0) {
return null;
}

return array_sum($values) / $count;
parent::__construct(
new NumericAggregator(
arrayAggregation: static function (array $values) {
$count = count($values);
if ($count === 0) return null;
return array_sum($values) / $count;
},
dbalAggregationFunction: 'AVG',
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Nextras\Orm\Collection\Aggregations\IArrayAggregator;
use Nextras\Orm\Collection\Aggregations\IDbalAggregator;
use Nextras\Orm\Collection\Aggregations\NumericAggregator;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Helpers\ArrayCollectionHelper;
Expand All @@ -19,28 +20,15 @@
use function is_string;


abstract class BaseAggregateFunction implements IArrayFunction, IQueryBuilderFunction
abstract class BaseNumericAggregateFunction implements IArrayFunction, IQueryBuilderFunction
{
/** @var literal-string */
private $sqlFunction;


/**
* @param literal-string $sqlFunction
*/
protected function __construct(string $sqlFunction)
protected function __construct(
private readonly NumericAggregator $aggregator,
)
{
$this->sqlFunction = $sqlFunction;
}


/**
* @param array<number> $values
* @return number|null
*/
abstract protected function calculateAggregation(array $values);


public function processArrayExpression(
ArrayCollectionHelper $helper,
IEntity $entity,
Expand All @@ -57,7 +45,7 @@ public function processArrayExpression(
assert(is_array($valueReference->value));

return new ArrayExpressionResult(
value: $this->calculateAggregation($valueReference->value),
value: $this->aggregator->aggregateValues($valueReference->value),
);
}

Expand All @@ -75,33 +63,6 @@ public function processQueryBuilderExpression(
throw new InvalidStateException("Cannot apply two aggregations simultaneously.");
}

$aggregator = new class implements IDbalAggregator {
/** @var literal-string */
public $sqlFunction;


public function getAggregateKey(): string
{
return '_' . $this->sqlFunction;
}


public function aggregateExpression(
QueryBuilder $queryBuilder,
DbalExpressionResult $expression
): DbalExpressionResult
{
return new DbalExpressionResult(
expression: "{$this->sqlFunction}($expression->expression)",
args: $expression->args,
joins: $expression->joins,
groupBy: $expression->groupBy,
isHavingClause: true,
);
}
};
$aggregator->sqlFunction = $this->sqlFunction;

return $helper->processPropertyExpr($builder, $args[0], $aggregator)->applyAggregator($builder);
return $helper->processPropertyExpr($builder, $args[0], $this->aggregator)->applyAggregator($builder);
}
}
16 changes: 8 additions & 8 deletions src/Collection/Functions/CountAggregateFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
namespace Nextras\Orm\Collection\Functions;


use Nextras\Orm\Collection\Aggregations\NumericAggregator;
use function count;


class CountAggregateFunction extends BaseAggregateFunction
class CountAggregateFunction extends BaseNumericAggregateFunction
{
public function __construct()
{
parent::__construct('COUNT');
}


protected function calculateAggregation(array $values)
{
return count($values);
parent::__construct(
new NumericAggregator(
arrayAggregation: static fn (array $values): int => count($values),
dbalAggregationFunction: 'COUNT',
)
);
}
}
23 changes: 11 additions & 12 deletions src/Collection/Functions/MaxAggregateFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@
namespace Nextras\Orm\Collection\Functions;


use Nextras\Orm\Collection\Aggregations\NumericAggregator;
use function count;
use function max;


class MaxAggregateFunction extends BaseAggregateFunction
class MaxAggregateFunction extends BaseNumericAggregateFunction
{
public function __construct()
{
parent::__construct('MAX');
}


protected function calculateAggregation(array $values)
{
if (count($values) === 0) {
return null;
}

return max($values);
parent::__construct(
new NumericAggregator(
arrayAggregation: static function (array $values) {
if (count($values) === 0) return null;
return max($values);
},
dbalAggregationFunction: 'MAX',
)
);
}
}
23 changes: 11 additions & 12 deletions src/Collection/Functions/MinAggregateFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@
namespace Nextras\Orm\Collection\Functions;


use Nextras\Orm\Collection\Aggregations\NumericAggregator;
use function count;
use function min;


class MinAggregateFunction extends BaseAggregateFunction
class MinAggregateFunction extends BaseNumericAggregateFunction
{
public function __construct()
{
parent::__construct('MIN');
}


protected function calculateAggregation(array $values)
{
if (count($values) === 0) {
return null;
}

return min($values);
parent::__construct(
new NumericAggregator(
arrayAggregation: static function (array $values) {
if (count($values) === 0) return null;
return min($values);
},
dbalAggregationFunction: 'MIN',
)
);
}
}
17 changes: 8 additions & 9 deletions src/Collection/Functions/SumAggregateFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@
namespace Nextras\Orm\Collection\Functions;


use function array_sum;
use Nextras\Orm\Collection\Aggregations\NumericAggregator;


class SumAggregateFunction extends BaseAggregateFunction
class SumAggregateFunction extends BaseNumericAggregateFunction
{
public function __construct()
{
parent::__construct('SUM');
}


protected function calculateAggregation(array $values)
{
return array_sum($values);
parent::__construct(
new NumericAggregator(
arrayAggregation: static fn (array $values) => array_sum($values),
dbalAggregationFunction: 'SUM',
)
);
}
}

0 comments on commit 1131b3f

Please sign in to comment.