Skip to content

Commit

Permalink
IBX-7355: Allowed LIKE query conditions in Criteria for joins (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
Steveb-p authored Jan 11, 2024
1 parent d3710a6 commit aa6aedf
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 65 deletions.
132 changes: 71 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,71 @@ 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 aa6aedf

Please sign in to comment.