Skip to content

Commit 117d594

Browse files
committed
Fix: Make case-insensitive search for the view filters
Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
1 parent f998888 commit 117d594

2 files changed

Lines changed: 54 additions & 17 deletions

File tree

lib/Db/Row2Mapper.php

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,11 @@ private function getFilterExpression(IQueryBuilder $qb, Column $column, string $
442442
switch ($operator) {
443443
case 'begins-with':
444444
$includeDefault = str_starts_with((string)($defaultValue ?? ''), $value);
445-
$filterExpression = $qb->expr()->like('value', $qb->createNamedParameter($this->db->escapeLikeParameter($value) . '%', $paramType));
445+
$filterExpression = $qb->expr()->ilike('value', $qb->createNamedParameter($this->db->escapeLikeParameter($value) . '%', $paramType));
446446
break;
447447
case 'ends-with':
448448
$includeDefault = str_ends_with((string)($defaultValue ?? ''), $value);
449-
$filterExpression = $qb->expr()->like('value', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value), $paramType));
449+
$filterExpression = $qb->expr()->ilike('value', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value), $paramType));
450450
break;
451451
case 'contains':
452452
$filterExpressions = [];
@@ -477,14 +477,14 @@ private function getFilterExpression(IQueryBuilder $qb, Column $column, string $
477477
if ($column->getType() === 'selection' && $column->getSubtype() === 'multi') {
478478
$value = str_replace(['"', '\''], '', $value);
479479
$filterExpression = $qb2->expr()->orX(
480-
$qb->expr()->like('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ']')),
481-
$qb->expr()->like('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ',%')),
482-
$qb->expr()->like('value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ']%')),
483-
$qb->expr()->like('value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ',%'))
480+
$qb->expr()->ilike('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ']')),
481+
$qb->expr()->ilike('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ',%')),
482+
$qb->expr()->ilike('value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ']%')),
483+
$qb->expr()->ilike('value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ',%'))
484484
);
485485
break;
486486
}
487-
$filterExpression = $qb->expr()->like('value', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
487+
$filterExpression = $qb->expr()->ilike('value', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
488488
break;
489489
case 'does-not-contain':
490490
if (is_array($value) && $column->getType() === Column::TYPE_USERGROUP) {
@@ -522,14 +522,15 @@ private function getFilterExpression(IQueryBuilder $qb, Column $column, string $
522522
if ($column->getType() === 'selection' && $column->getSubtype() === 'multi') {
523523
$value = str_replace(['"', '\''], '', $value);
524524
$filterExpression = $qb2->expr()->andX(
525-
$qb->expr()->notLike('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ']')),
526-
$qb->expr()->notLike('value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ',%')),
527-
$qb->expr()->notLike('value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ']%')),
528-
$qb->expr()->notLike('value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ',%'))
529-
);
525+
$qb->expr()->andX(
526+
$this->notILike($qb, 'value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ']')),
527+
$this->notILike($qb, 'value', $qb->createNamedParameter('[' . $this->db->escapeLikeParameter($value) . ',%')),
528+
$this->notILike($qb, 'value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ']%')),
529+
$this->notILike($qb, 'value', $qb->createNamedParameter('%,' . $this->db->escapeLikeParameter($value) . ',%'))
530+
));
530531
break;
531532
}
532-
$filterExpression = $qb->expr()->notLike('value', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
533+
$filterExpression = $this->notILike($qb, 'value', $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
533534
break;
534535
case 'is-equal':
535536
$includeDefault = $defaultValue === $value;
@@ -618,6 +619,19 @@ private function getMetaFilterExpression(IQueryBuilder $qb, int $columnId, strin
618619
return $qb2;
619620
}
620621

622+
/**
623+
* Helper method to use notILike if available, otherwise fall back to not(iLike(...))
624+
*/
625+
private function notILike(IQueryBuilder $qb, string $column, $parameter): string {
626+
$expr = $qb->expr();
627+
// Nextcloud v35 introduced shortcut method
628+
if (method_exists($expr, 'notILike')) {
629+
return $expr->notILike($column, $parameter);
630+
}
631+
632+
return 'NOT (' . $expr->iLike($column, $parameter) . ')';
633+
}
634+
621635
/**
622636
* @param string $operator
623637
* @param IQueryBuilder $qb
@@ -630,13 +644,13 @@ private function getMetaFilterExpression(IQueryBuilder $qb, int $columnId, strin
630644
private function getSqlOperator(string $operator, IQueryBuilder $qb, string $columnName, $value, $paramType): string {
631645
switch ($operator) {
632646
case 'begins-with':
633-
return $qb->expr()->like($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value), $paramType));
647+
return $qb->expr()->ilike($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value), $paramType));
634648
case 'ends-with':
635-
return $qb->expr()->like($columnName, $qb->createNamedParameter($this->db->escapeLikeParameter($value) . '%', $paramType));
649+
return $qb->expr()->ilike($columnName, $qb->createNamedParameter($this->db->escapeLikeParameter($value) . '%', $paramType));
636650
case 'contains':
637-
return $qb->expr()->like($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
651+
return $qb->expr()->ilike($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
638652
case 'does-not-contain':
639-
return $qb->expr()->notLike($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
653+
return $this->notILike($qb, $columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
640654
case 'is-equal':
641655
return $qb->expr()->eq($columnName, $qb->createNamedParameter($value, $paramType));
642656
case 'is-not-equal':

tests/integration/features/APIv1.feature

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,29 @@ Feature: APIv1
553553
| task |
554554
| New general task |
555555

556+
@api1 @views @view-filters
557+
Scenario: Case-insensitive filter with contains operator
558+
Given table "Product List" with emoji "📦" exists for user "participant1" as "product-list"
559+
Then column "name" exists with following properties
560+
| type | text |
561+
| subtype | line |
562+
| mandatory | 1 |
563+
| description | Product name |
564+
Then row exists with following values
565+
| name | Apple |
566+
Then row exists with following values
567+
| name | Banana |
568+
Then row exists with following values
569+
| name | Orange |
570+
And user "participant1" create view "Fruit Products" with emoji "🍎" for "product-list" as "fruit-products"
571+
When user "participant1" sets columnSettings "name" to view "fruit-products"
572+
And user "participant1" sets filter to view "fruit-products"
573+
| column | operator | value |
574+
| name | contains | APP |
575+
Then view "fruit-products" has exactly the following rows
576+
| name |
577+
| Apple |
578+
556579
@api1 @views @technical-name
557580
Scenario: Create and update view with technical name
558581
Given table "View technical name test" with emoji "🔧" exists for user "participant1" as "tech-name-table"

0 commit comments

Comments
 (0)