Skip to content

Commit

Permalink
use simple filtering joinst for simple ANY relationship condition
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Mar 11, 2024
1 parent 884a1ef commit f5994ba
Show file tree
Hide file tree
Showing 29 changed files with 119 additions and 46 deletions.
8 changes: 8 additions & 0 deletions src/Collection/Aggregations/AnyAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalTableJoin;
use Nextras\Orm\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -50,8 +51,15 @@ public function aggregateValues(array $values): bool
public function aggregateExpression(
QueryBuilder $queryBuilder,
DbalExpressionResult $expression,
ExpressionContext $context,
): DbalExpressionResult
{
if ($context !== ExpressionContext::FilterOr) {
// When we are not in OR expression, we may simply filter the joined table by the condition.
// Otherwise, we have to employ a HAVING clause with aggregation function.
return $expression;
}

$joins = $expression->joins;
$join = array_pop($joins);
if ($join === null) {
Expand Down
2 changes: 2 additions & 0 deletions src/Collection/Aggregations/CountAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalTableJoin;
use Nextras\Orm\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -56,6 +57,7 @@ public function aggregateValues(array $values): bool
public function aggregateExpression(
QueryBuilder $queryBuilder,
DbalExpressionResult $expression,
ExpressionContext $context,
): DbalExpressionResult
{
$joins = $expression->joins;
Expand Down
2 changes: 2 additions & 0 deletions src/Collection/Aggregations/IDbalAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


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


Expand All @@ -12,5 +13,6 @@ interface IDbalAggregator extends IAggregator
public function aggregateExpression(
QueryBuilder $queryBuilder,
DbalExpressionResult $expression,
ExpressionContext $context,
): DbalExpressionResult;
}
2 changes: 2 additions & 0 deletions src/Collection/Aggregations/NoneAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalTableJoin;
use Nextras\Orm\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -50,6 +51,7 @@ public function aggregateValues(array $values): bool
public function aggregateExpression(
QueryBuilder $queryBuilder,
DbalExpressionResult $expression,
ExpressionContext $context,
): DbalExpressionResult
{
$joins = $expression->joins;
Expand Down
2 changes: 2 additions & 0 deletions src/Collection/Aggregations/NumericAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


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


Expand Down Expand Up @@ -41,6 +42,7 @@ public function aggregateValues(array $values): mixed
public function aggregateExpression(
QueryBuilder $queryBuilder,
DbalExpressionResult $expression,
ExpressionContext $context,
): DbalExpressionResult
{
return new DbalExpressionResult(
Expand Down
12 changes: 7 additions & 5 deletions src/Collection/DbalCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Iterator;
use Nextras\Dbal\IConnection;
use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Helpers\DbalQueryBuilderHelper;
use Nextras\Orm\Collection\Helpers\FetchPairsHelper;
Expand Down Expand Up @@ -122,13 +123,13 @@ public function orderBy($expression, string $direction = ICollection::ASC): ICol

foreach ($expression as $subExpression => $subDirection) {
$collection->ordering[] = [
$helper->processExpression($collection->queryBuilder, $subExpression, null),
$helper->processExpression($collection->queryBuilder, $subExpression, ExpressionContext::FilterAnd, null),
$subDirection,
];
}
} else {
$collection->ordering[] = [
$helper->processExpression($collection->queryBuilder, $expression, null),
$helper->processExpression($collection->queryBuilder, $expression, ExpressionContext::ValueExpression, null),
$direction,
];
}
Expand Down Expand Up @@ -307,9 +308,10 @@ public function getQueryBuilder(): QueryBuilder
if (count($args) > 0) {
array_unshift($args, ICollection::AND);
$expression = $helper->processExpression(
$this->queryBuilder,
$args,
null,
builder: $this->queryBuilder,
expression: $args,
context: ExpressionContext::FilterAnd,
aggregator: null,
);
$joins = $expression->joins;
if ($expression->isHavingClause) {
Expand Down
17 changes: 17 additions & 0 deletions src/Collection/Expression/ExpressionContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php declare(strict_types = 1);

namespace Nextras\Orm\Collection\Expression;


/**
* @internal
*
* Determines if the expression is processed for AND subtree, OR subtree or pure expression, e.g., a sorting expression.
* OR subtree requires more complex SQL construction, in other modes we may optimize the resulting SQL.
*/
enum ExpressionContext
{
case FilterAnd;
case FilterOr;
case ValueExpression;
}
4 changes: 3 additions & 1 deletion src/Collection/Functions/BaseCompareFunction.php
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\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Helpers\ArrayCollectionHelper;
Expand Down Expand Up @@ -59,12 +60,13 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
ExpressionContext $context,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
assert(count($args) === 2);

$expression = $helper->processExpression($builder, $args[0], $aggregator);
$expression = $helper->processExpression($builder, $args[0], $context, $aggregator);

if ($expression->valueNormalizer !== null) {
$cb = $expression->valueNormalizer;
Expand Down
5 changes: 4 additions & 1 deletion src/Collection/Functions/BaseNumericAggregateFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Nextras\Orm\Collection\Aggregations\IArrayAggregator;
use Nextras\Orm\Collection\Aggregations\IDbalAggregator;
use Nextras\Orm\Collection\Aggregations\NumericAggregator;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Helpers\ArrayCollectionHelper;
Expand Down Expand Up @@ -54,6 +55,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
ExpressionContext $context,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
Expand All @@ -63,6 +65,7 @@ public function processDbalExpression(
throw new InvalidStateException("Cannot apply two aggregations simultaneously.");
}

return $helper->processExpression($builder, $args[0], $this->aggregator)->applyAggregator($builder);
return $helper->processExpression($builder, $args[0], $context, $this->aggregator)
->applyAggregator($builder, ExpressionContext::ValueExpression);
}
}
2 changes: 2 additions & 0 deletions src/Collection/Functions/CollectionFunction.php
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\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Helpers\ArrayCollectionHelper;
Expand Down Expand Up @@ -45,6 +46,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
ExpressionContext $context,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult;
}
4 changes: 3 additions & 1 deletion src/Collection/Functions/CompareLikeFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Nextras\Orm\Collection\Aggregations\IArrayAggregator;
use Nextras\Orm\Collection\Aggregations\IDbalAggregator;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Collection\Expression\LikeExpression;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
Expand Down Expand Up @@ -64,12 +65,13 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
ExpressionContext $context,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
assert(count($args) === 2);

$expression = $helper->processExpression($builder, $args[0], $aggregator);
$expression = $helper->processExpression($builder, $args[0], $context, $aggregator);

$likeExpression = $args[1];
assert($likeExpression instanceof LikeExpression);
Expand Down
3 changes: 3 additions & 0 deletions src/Collection/Functions/ConjunctionOperatorFunction.php
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\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Helpers\ArrayCollectionHelper;
Expand Down Expand Up @@ -105,6 +106,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
ExpressionContext $context,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
Expand All @@ -113,6 +115,7 @@ public function processDbalExpression(
helper: $helper,
builder: $builder,
args: $args,
context: $context,
aggregator: $aggregator,
);
}
Expand Down
3 changes: 3 additions & 0 deletions src/Collection/Functions/DisjunctionOperatorFunction.php
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\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Helpers\ArrayCollectionHelper;
Expand Down Expand Up @@ -98,6 +99,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
ExpressionContext $context,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
Expand All @@ -106,6 +108,7 @@ public function processDbalExpression(
helper: $helper,
builder: $builder,
args: $args,
context: ExpressionContext::FilterOr,
aggregator: $aggregator,
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Collection/Functions/FetchPropertyFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Nextras\Orm\Collection\Aggregations\IAggregator;
use Nextras\Orm\Collection\Aggregations\IArrayAggregator;
use Nextras\Orm\Collection\Aggregations\IDbalAggregator;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalTableJoin;
Expand Down Expand Up @@ -154,6 +155,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
ExpressionContext $context,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
Expand Down Expand Up @@ -257,7 +259,6 @@ private function processTokens(
joins: $joins,
groupBy: $groupBy,
aggregator: $makeDistinct ? ($aggregator ?? new AnyAggregator()) : null,
isHavingClause: $makeDistinct,
propertyMetadata: $propertyMetadata,
valueNormalizer: function ($value) use ($propertyMetadata, $currentConventions) {
return $this->normalizeValue($value, $propertyMetadata, $currentConventions);
Expand Down
6 changes: 4 additions & 2 deletions src/Collection/Functions/JunctionFunctionTrait.php
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\IAggregator;
use Nextras\Orm\Collection\Aggregations\IDbalAggregator;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Helpers\DbalQueryBuilderHelper;
use Nextras\Orm\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -61,6 +62,7 @@ protected function processQueryBuilderExpressionWithModifier(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
ExpressionContext $context,
?IDbalAggregator $aggregator,
): DbalExpressionResult
{
Expand All @@ -77,8 +79,8 @@ protected function processQueryBuilderExpressionWithModifier(
}

foreach ($normalized as $collectionFunctionArgs) {
$expression = $helper->processExpression($builder, $collectionFunctionArgs, $aggregator);
$expression = $expression->applyAggregator($builder);
$expression = $helper->processExpression($builder, $collectionFunctionArgs, $context, $aggregator);
$expression = $expression->applyAggregator($builder, $context);
$processedArgs[] = $expression->getArgumentsForExpansion();
$joins = array_merge($joins, $expression->joins);
$groupBy = array_merge($groupBy, $expression->groupBy);
Expand Down
25 changes: 11 additions & 14 deletions src/Collection/Functions/Result/DbalExpressionResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@

use Nextras\Dbal\QueryBuilder\QueryBuilder;
use Nextras\Orm\Collection\Aggregations\IDbalAggregator;
use Nextras\Orm\Collection\Expression\ExpressionContext;
use Nextras\Orm\Entity\Reflection\PropertyMetadata;
use Nextras\Orm\Exception\InvalidArgumentException;
use function array_unshift;
use function array_values;


/**
* Represents an SQL expression.
* This class hold the main expression and its attributes.
* If possible, also holds a reference to a backing property of the expression.
* Represents an SQL expression. This class hold the main expression and its attributes.
*
* The class is used either in WHERE clause or in HAVING clause, it is decided from the outside of this class,
* yet this expression may force its using in HAVING clause by setting {@see $isHavingClause}.
*
* If possible, the expression holds a reference to a backing property of the expression {@see $propertyMetadata};
* this is utilized to provide a value normalization.
*/
class DbalExpressionResult
{
Expand Down Expand Up @@ -64,6 +68,7 @@ class DbalExpressionResult
*/
public readonly ?string $dbalModifier;


/**
* @param literal-string $expression
* @param list<mixed> $args
Expand Down Expand Up @@ -93,10 +98,6 @@ public function __construct(
$this->propertyMetadata = $propertyMetadata;
$this->valueNormalizer = $valueNormalizer;
$this->dbalModifier = $dbalModifier;

if ($aggregator !== null && !$isHavingClause) {
throw new InvalidArgumentException('Dbal expression with aggregator is expected to be defined as HAVING clause.');
}
}


Expand Down Expand Up @@ -155,12 +156,8 @@ public function withArgs(string $expression, array $args): DbalExpressionResult
/**
* Applies the aggregator and returns modified expression result.
*/
public function applyAggregator(QueryBuilder $queryBuilder): DbalExpressionResult
public function applyAggregator(QueryBuilder $queryBuilder, ExpressionContext $context): DbalExpressionResult
{
if ($this->aggregator === null) {
return $this;
}

return $this->aggregator->aggregateExpression($queryBuilder, $this);
return $this->aggregator?->aggregateExpression($queryBuilder, $this, $context) ?? $this;
}
}
Loading

0 comments on commit f5994ba

Please sign in to comment.