Skip to content

Commit

Permalink
Allowed LIKE query conditions in Criteria for joins
Browse files Browse the repository at this point in the history
  • Loading branch information
Steveb-p committed Dec 12, 2023
1 parent d3710a6 commit ff42e0b
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 65 deletions.
128 changes: 67 additions & 61 deletions src/lib/Gateway/ExpressionVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,65 +118,7 @@ public function walkComparison(Comparison $comparison)
}
$parameter = new Parameter($parameterName, $value, $type);

switch ($comparison->getOperator()) {
case Comparison::IN:
$this->parameters[] = $parameter;

return $this->expr()->in($fullColumnName, $placeholder);

case Comparison::NIN:
$this->parameters[] = $parameter;

return $this->expr()->notIn($fullColumnName, $placeholder);

case Comparison::EQ:
case Comparison::IS:
if ($this->walkValue($comparison->getValue()) === null) {
return $this->expr()->isNull($fullColumnName);
}

$this->parameters[] = $parameter;

return $this->expr()->eq($fullColumnName, $placeholder);

case Comparison::NEQ:
if ($this->walkValue($comparison->getValue()) === null) {
return $this->expr()->isNotNull($fullColumnName);
}

$this->parameters[] = $parameter;

return $this->expr()->neq($fullColumnName, $placeholder);

case Comparison::CONTAINS:
$parameter->setValue('%' . $this->escapeSpecialSQLValues($parameter) . '%');
$this->parameters[] = $parameter;

return $this->expr()->like($fullColumnName, $placeholder);

case Comparison::STARTS_WITH:
$parameter->setValue($this->escapeSpecialSQLValues($parameter) . '%');
$this->parameters[] = $parameter;

return $this->expr()->like($fullColumnName, $placeholder);

case Comparison::ENDS_WITH:
$parameter->setValue('%' . $this->escapeSpecialSQLValues($parameter));
$this->parameters[] = $parameter;

return $this->expr()->like($fullColumnName, $placeholder);

case Comparison::GT:
case Comparison::GTE:
case Comparison::LT:
case Comparison::LTE:
$this->parameters[] = $parameter;

return $this->expr()->comparison($fullColumnName, $comparison->getOperator(), $placeholder);

default:
throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
}
return $this->handleComparison($comparison, $parameter, $fullColumnName, $placeholder);
}

/**
Expand Down Expand Up @@ -300,13 +242,14 @@ private function handleJoinQuery(
}

$parameter = new Parameter($parameterName, $value, $type);
$this->parameters[] = $parameter;

if (is_array($value)) {
$this->parameters[] = $parameter;

return $this->expr()->in($tableName . '.' . $field, $placeholder);
}

return $this->expr()->comparison($tableName . '.' . $field, $comparison->getOperator(), $placeholder);
return $this->handleComparison($comparison, $parameter, $tableName . '.' . $field, $placeholder);
}

private function handleSubSelectQuery(
Expand Down Expand Up @@ -379,4 +322,67 @@ private function isInheritedColumn(string $column): bool
return $this->schemaMetadata->getIdentifierColumn() !== $column
&& $this->schemaMetadata->isInheritedColumn($column);
}

private function handleComparison(Comparison $comparison, Parameter $parameter, string $fullColumnName, string $placeholder): string
{
switch ($comparison->getOperator()) {
case Comparison::IN:
$this->parameters[] = $parameter;

return $this->expr()->in($fullColumnName, $placeholder);

case Comparison::NIN:
$this->parameters[] = $parameter;

return $this->expr()->notIn($fullColumnName, $placeholder);

case Comparison::EQ:
case Comparison::IS:
if ($this->walkValue($comparison->getValue()) === null) {
return $this->expr()->isNull($fullColumnName);
}

$this->parameters[] = $parameter;

return $this->expr()->eq($fullColumnName, $placeholder);

case Comparison::NEQ:
if ($this->walkValue($comparison->getValue()) === null) {
return $this->expr()->isNotNull($fullColumnName);
}

$this->parameters[] = $parameter;

return $this->expr()->neq($fullColumnName, $placeholder);

case Comparison::CONTAINS:
$parameter->setValue('%' . $this->escapeSpecialSQLValues($parameter) . '%');
$this->parameters[] = $parameter;

return $this->expr()->like($fullColumnName, $placeholder);

case Comparison::STARTS_WITH:
$parameter->setValue($this->escapeSpecialSQLValues($parameter) . '%');
$this->parameters[] = $parameter;

return $this->expr()->like($fullColumnName, $placeholder);

case Comparison::ENDS_WITH:
$parameter->setValue('%' . $this->escapeSpecialSQLValues($parameter));
$this->parameters[] = $parameter;

return $this->expr()->like($fullColumnName, $placeholder);

case Comparison::GT:
case Comparison::GTE:
case Comparison::LT:
case Comparison::LTE:
$this->parameters[] = $parameter;

return $this->expr()->comparison($fullColumnName, $comparison->getOperator(), $placeholder);

default:
throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
}
}
}
38 changes: 35 additions & 3 deletions tests/bundle/Gateway/ExpressionVisitorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,14 @@ public function testFieldFromSubSelectRelationship(): void

/**
* @dataProvider provideForFieldFromInheritedRelationship
*
* @phpstan-param array<\Ibexa\CorePersistence\Gateway\Parameter> $parameters
*/
public function testFieldFromInheritedRelationship(Comparison $comparison, string $expectedResult): void
{
public function testFieldFromInheritedRelationship(
Comparison $comparison,
string $expectedResult,
array $parameters
): void {
/** @var class-string $relationshipClass pretend it's a class-string */
$relationshipClass = 'relationship_class';
$doctrineRelationship = new DoctrineOneToManyRelationship(
Expand Down Expand Up @@ -254,26 +259,53 @@ public function testFieldFromInheritedRelationship(Comparison $comparison, strin
$expectedResult,
$result,
);

self::assertEquals($parameters, $this->expressionVisitor->getParameters());
}

/**
* @return iterable<array{\Doctrine\Common\Collections\Expr\Comparison, non-empty-string}>
* @return iterable<array{
* \Doctrine\Common\Collections\Expr\Comparison,
* non-empty-string,
* array<\Ibexa\CorePersistence\Gateway\Parameter>,
* }>
*/
public static function provideForFieldFromInheritedRelationship(): iterable
{
yield [
new Comparison('relationship_1.field', '=', 'value'),
'relationship_table_name.field = :field_0',
[new Parameter('field_0', 'value', 0)],
];

yield [
new Comparison('relationship_1.field', 'IN', ['value', 'value_2']),
'relationship_table_name.field IN (:field_0)',
[new Parameter('field_0', ['value', 'value_2'], 100)],
];

yield [
new Comparison('relationship_1.field', '=', ['value', 'value_2']),
'relationship_table_name.field IN (:field_0)',
[new Parameter('field_0', ['value', 'value_2'], 100)],
];

yield [
new Comparison('relationship_1.field', 'STARTS_WITH', 'value'),
'relationship_table_name.field LIKE :field_0',
[new Parameter('field_0', 'value%', 0)],
];

yield [
new Comparison('relationship_1.field', 'ENDS_WITH', 'value'),
'relationship_table_name.field LIKE :field_0',
[new Parameter('field_0', '%value', 0)],
];

yield [
new Comparison('relationship_1.field', 'CONTAINS', 'value'),
'relationship_table_name.field LIKE :field_0',
[new Parameter('field_0', '%value%', 0)],
];
}

Expand Down
2 changes: 1 addition & 1 deletion tests/integration/Gateway/ExpressionVisitorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public static function provideForTraversingRelationships(): iterable
'IN',
'bar',
),
'relationship_2_table_name.relationship_2_foo IN :relationship_2_foo_0',
'relationship_2_table_name.relationship_2_foo IN (:relationship_2_foo_0)',
];

yield [
Expand Down

0 comments on commit ff42e0b

Please sign in to comment.