Skip to content

Commit 76fa3a5

Browse files
authored
Ends with strict (#885)
* feat: ends with strict * update: docs
1 parent c30d3a9 commit 76fa3a5

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

docs/features/filtering.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ weight: 1
55

66
The `filter` query parameters can be used to add `where` clauses to your Eloquent query. Out of the box we support filtering results by partial attribute value, exact attribute value or even if an attribute value exists in a given array of values. For anything more advanced, custom filters can be used.
77

8-
By default, all filters have to be explicitly allowed using `allowedFilters()`. This method takes an array of strings or `AllowedFilter` instances. An allowed filter can be partial, beginsWithStrict, exact, scope or custom. By default, any string values passed to `allowedFilters()` will automatically be converted to `AllowedFilter::partial()` filters.
8+
By default, all filters have to be explicitly allowed using `allowedFilters()`. This method takes an array of strings or `AllowedFilter` instances. An allowed filter can be partial, beginsWithStrict, endsWithStrict, exact, scope or custom. By default, any string values passed to `allowedFilters()` will automatically be converted to `AllowedFilter::partial()` filters.
99

1010
## Basic usage
1111

@@ -48,9 +48,9 @@ You can set in configuration file to not throw an InvalidFilterQuery exception w
4848

4949
By default the option is set false.
5050

51-
## Partial and beginsWithStrict filters
51+
## Partial, beginsWithStrict and endsWithStrict filters
5252

53-
By default, all values passed to `allowedFilters` are converted to partial filters. The underlying query will be modified to use a `LIKE LOWER(%value%)` statement. Because this can cause missed indexes, it's often worth considering a `beginsWithStrict` filter instead. This filter will use a `LIKE value%` statement instead.
53+
By default, all values passed to `allowedFilters` are converted to partial filters. The underlying query will be modified to use a `LIKE LOWER(%value%)` statement. Because this can cause missed indexes, it's often worth considering a `beginsWithStrict` filter for the beginning of the value, or an `endsWithStrict` filter for the end of the value. These filters will use a `LIKE value%` statement and a `LIKE %value` statement respectively, instead of the default partial filter. This can help optimize query performance and index utilization.
5454

5555
## Exact filters
5656

src/AllowedFilter.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Spatie\QueryBuilder\Filters\Filter;
77
use Spatie\QueryBuilder\Filters\FiltersBeginsWithStrict;
88
use Spatie\QueryBuilder\Filters\FiltersCallback;
9+
use Spatie\QueryBuilder\Filters\FiltersEndsWithStrict;
910
use Spatie\QueryBuilder\Filters\FiltersExact;
1011
use Spatie\QueryBuilder\Filters\FiltersPartial;
1112
use Spatie\QueryBuilder\Filters\FiltersScope;
@@ -78,6 +79,13 @@ public static function beginsWithStrict(string $name, $internalName = null, bool
7879
return new static($name, new FiltersBeginsWithStrict($addRelationConstraint), $internalName);
7980
}
8081

82+
public static function endsWithStrict(string $name, $internalName = null, bool $addRelationConstraint = true, string $arrayValueDelimiter = null): self
83+
{
84+
static::setFilterArrayValueDelimiter($arrayValueDelimiter);
85+
86+
return new static($name, new FiltersEndsWithStrict($addRelationConstraint), $internalName);
87+
}
88+
8189
public static function scope(string $name, $internalName = null, string $arrayValueDelimiter = null): self
8290
{
8391
static::setFilterArrayValueDelimiter($arrayValueDelimiter);

src/Filters/FiltersEndsWithStrict.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Spatie\QueryBuilder\Filters;
4+
5+
/**
6+
* @template TModelClass of \Illuminate\Database\Eloquent\Model
7+
* @template-implements \Spatie\QueryBuilder\Filters\Filter<TModelClass>
8+
*/
9+
class FiltersEndsWithStrict extends FiltersPartial implements Filter
10+
{
11+
protected function getWhereRawParameters($value, string $property): array
12+
{
13+
return [
14+
"{$property} LIKE ?",
15+
["%{$value}"],
16+
];
17+
}
18+
}

tests/FilterTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@
142142
$this->assertQueryLogContains("select * from `test_models` where (`test_models`.`id` LIKE ?)");
143143
});
144144

145+
test('falsy values are not ignored when applying a ends with strict filter', function () {
146+
DB::enableQueryLog();
147+
148+
createQueryFromFilterRequest([
149+
'id' => [0],
150+
])
151+
->allowedFilters(AllowedFilter::endsWithStrict('id'))
152+
->get();
153+
154+
$this->assertQueryLogContains("select * from `test_models` where (`test_models`.`id` LIKE ?)");
155+
});
156+
145157
it('can filter partial using begins with strict', function () {
146158
TestModel::create([
147159
'name' => 'John Doe',
@@ -161,6 +173,25 @@
161173
expect($models2->count())->toBe(0);
162174
});
163175

176+
it('can filter partial using ends with strict', function () {
177+
TestModel::create([
178+
'name' => 'John Doe',
179+
]);
180+
181+
$models = createQueryFromFilterRequest(['name' => 'doe'])
182+
->allowedFilters([
183+
AllowedFilter::endsWithStrict('name'),
184+
]);
185+
186+
$models2 = createQueryFromFilterRequest(['name' => 'john'])
187+
->allowedFilters([
188+
AllowedFilter::endsWithStrict('name'),
189+
]);
190+
191+
expect($models->count())->toBe(1);
192+
expect($models2->count())->toBe(0);
193+
});
194+
164195
it('can filter and match results by exact property', function () {
165196
$testModel = TestModel::first();
166197

0 commit comments

Comments
 (0)