Skip to content

Commit 4e08209

Browse files
Add BeginsWithStrict filter (spatie#821)
* isolate "where" applying * use strtolower when applying "where" * add beginsWithStrict filter * remove unused variable * implements getWhereRawParameters and use it instead applyWhere * add tests
1 parent b714fb6 commit 4e08209

File tree

4 files changed

+72
-7
lines changed

4 files changed

+72
-7
lines changed

src/AllowedFilter.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Support\Collection;
66
use Spatie\QueryBuilder\Filters\Filter;
7+
use Spatie\QueryBuilder\Filters\FiltersBeginsWithStrict;
78
use Spatie\QueryBuilder\Filters\FiltersCallback;
89
use Spatie\QueryBuilder\Filters\FiltersExact;
910
use Spatie\QueryBuilder\Filters\FiltersPartial;
@@ -70,6 +71,13 @@ public static function partial(string $name, $internalName = null, bool $addRela
7071
return new static($name, new FiltersPartial($addRelationConstraint), $internalName);
7172
}
7273

74+
public static function beginsWithStrict(string $name, $internalName = null, bool $addRelationConstraint = true, string $arrayValueDelimiter = null): self
75+
{
76+
static::setFilterArrayValueDelimiter($arrayValueDelimiter);
77+
78+
return new static($name, new FiltersBeginsWithStrict($addRelationConstraint), $internalName);
79+
}
80+
7381
public static function scope(string $name, $internalName = null, string $arrayValueDelimiter = null): self
7482
{
7583
static::setFilterArrayValueDelimiter($arrayValueDelimiter);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Spatie\QueryBuilder\Filters;
4+
5+
use Illuminate\Database\Eloquent\Builder;
6+
7+
/**
8+
* @template TModelClass of \Illuminate\Database\Eloquent\Model
9+
* @template-implements \Spatie\QueryBuilder\Filters\Filter<TModelClass>
10+
*/
11+
class FiltersBeginsWithStrict extends FiltersPartial implements Filter
12+
{
13+
protected function getWhereRawParameters($value, string $property): array
14+
{
15+
return [
16+
"{$property} LIKE ?",
17+
["{$value}%"],
18+
];
19+
}
20+
}

src/Filters/FiltersPartial.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,32 @@ public function __invoke(Builder $query, $value, string $property)
2323

2424
$wrappedProperty = $query->getQuery()->getGrammar()->wrap($query->qualifyColumn($property));
2525

26-
$sql = "LOWER({$wrappedProperty}) LIKE ?";
27-
2826
if (is_array($value)) {
2927
if (count(array_filter($value, 'strlen')) === 0) {
3028
return $query;
3129
}
3230

33-
$query->where(function (Builder $query) use ($value, $sql) {
31+
$query->where(function (Builder $query) use ($value, $wrappedProperty) {
3432
foreach (array_filter($value, 'strlen') as $partialValue) {
35-
$partialValue = mb_strtolower($partialValue, 'UTF8');
36-
37-
$query->orWhereRaw($sql, ["%{$partialValue}%"]);
33+
[$sql, $bindings] = $this->getWhereRawParameters($partialValue, $wrappedProperty);
34+
$query->orWhereRaw($sql, $bindings);
3835
}
3936
});
4037

4138
return;
4239
}
4340

41+
[$sql, $bindings] = $this->getWhereRawParameters($value, $wrappedProperty);
42+
$query->whereRaw($sql, $bindings);
43+
}
44+
45+
protected function getWhereRawParameters($value, string $property): array
46+
{
4447
$value = mb_strtolower($value, 'UTF8');
4548

46-
$query->whereRaw($sql, ["%{$value}%"]);
49+
return [
50+
"LOWER({$property}) LIKE ?",
51+
["%{$value}%"],
52+
];
4753
}
4854
}

tests/FilterTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,37 @@
130130
$this->assertQueryLogContains("select * from `test_models` where (LOWER(`test_models`.`id`) LIKE ?)");
131131
});
132132

133+
test('falsy values are not ignored when applying a begins with strict filter', function () {
134+
DB::enableQueryLog();
135+
136+
createQueryFromFilterRequest([
137+
'id' => [0],
138+
])
139+
->allowedFilters(AllowedFilter::beginsWithStrict('id'))
140+
->get();
141+
142+
$this->assertQueryLogContains("select * from `test_models` where (`test_models`.`id` LIKE ?)");
143+
});
144+
145+
it('can filter partial using begins with strict', function () {
146+
TestModel::create([
147+
'name' => 'John Doe',
148+
]);
149+
150+
$models = createQueryFromFilterRequest(['name' => 'john'])
151+
->allowedFilters([
152+
AllowedFilter::beginsWithStrict('name'),
153+
]);
154+
155+
$models2 = createQueryFromFilterRequest(['name' => 'doe'])
156+
->allowedFilters([
157+
AllowedFilter::beginsWithStrict('name'),
158+
]);
159+
160+
expect($models->count())->toBe(1);
161+
expect($models2->count())->toBe(0);
162+
});
163+
133164
it('can filter and match results by exact property', function () {
134165
$testModel = TestModel::first();
135166

0 commit comments

Comments
 (0)