Skip to content

Commit

Permalink
Merge branch 'main' into phpstan
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexVanderbist authored May 10, 2024
2 parents fef22d9 + 47d9561 commit d250c1b
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 13 deletions.
1 change: 1 addition & 0 deletions .phpunit.cache/test-results

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

All notable changes to `laravel-query-builder` will be documented in this file

## 5.8.1 - 2024-05-10

### What's Changed

* Fix typo by @justinkekeocha in https://github.com/spatie/laravel-query-builder/pull/926
* List query-builder-ts front-end implementation package by @rogervila in https://github.com/spatie/laravel-query-builder/pull/925
* Fix incorrect escape character in SQL for LIKE query in partial filter by @Talpx1 in https://github.com/spatie/laravel-query-builder/pull/927

### New Contributors

* @justinkekeocha made their first contribution in https://github.com/spatie/laravel-query-builder/pull/926
* @rogervila made their first contribution in https://github.com/spatie/laravel-query-builder/pull/925
* @Talpx1 made their first contribution in https://github.com/spatie/laravel-query-builder/pull/927

**Full Changelog**: https://github.com/spatie/laravel-query-builder/compare/5.8.0...5.8.1

## 5.8.0 - 2024-02-06

### What's Changed
Expand Down
1 change: 1 addition & 0 deletions docs/advanced-usage/front-end-implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ If you're interested in building query urls on the front-end to match this packa
- Vue + Inertia.js: [inertiajs-tables-laravel-query-builder](https://github.com/protonemedia/inertiajs-tables-laravel-query-builder) by [
Pascal Baljet](https://github.com/pascalbaljet).
- React: [cogent-js package](https://www.npmjs.com/package/cogent-js) by [Joel Male](https://github.com/joelwmale).
- Typescript: [query-builder-ts package](https://www.npmjs.com/package/@vortechron/query-builder-ts) by [Amirul Adli](https://www.npmjs.com/~vortechron)
6 changes: 3 additions & 3 deletions src/Filters/FiltersBeginsWithStrict.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
*/
class FiltersBeginsWithStrict extends FiltersPartial implements Filter
{
protected function getWhereRawParameters($value, string $property): array
protected function getWhereRawParameters($value, string $property, string $driver): array
{
return [
"{$property} LIKE ?",
["{$value}%"],
"{$property} LIKE ?".static::maybeSpecifyEscapeChar($driver),
[static::escapeLike($value).'%'],
];
}
}
7 changes: 4 additions & 3 deletions src/Filters/FiltersEndsWithStrict.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
*/
class FiltersEndsWithStrict extends FiltersPartial implements Filter
{
protected function getWhereRawParameters($value, string $property): array
protected function getWhereRawParameters($value, string $property, string $driver): array
{

return [
"{$property} LIKE ?",
["%{$value}"],
"{$property} LIKE ?".static::maybeSpecifyEscapeChar($driver),
['%'.static::escapeLike($value)],
];
}
}
32 changes: 26 additions & 6 deletions src/Filters/FiltersPartial.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,62 @@ public function __invoke(Builder $query, $value, string $property)
}

$wrappedProperty = $query->getQuery()->getGrammar()->wrap($query->qualifyColumn($property));
$databaseDriver = $this->getDatabaseDriver($query);

if (is_array($value)) {
if (count(array_filter($value, 'strlen')) === 0) {
return $query;
}

$query->where(function (Builder $query) use ($value, $wrappedProperty) {
$query->where(function (Builder $query) use ($databaseDriver, $value, $wrappedProperty) {
foreach (array_filter($value, 'strlen') as $partialValue) {
[$sql, $bindings] = $this->getWhereRawParameters($partialValue, $wrappedProperty);
[$sql, $bindings] = $this->getWhereRawParameters($partialValue, $wrappedProperty, $databaseDriver);
$query->orWhereRaw($sql, $bindings);
}
});

return;
}

[$sql, $bindings] = $this->getWhereRawParameters($value, $wrappedProperty);
[$sql, $bindings] = $this->getWhereRawParameters($value, $wrappedProperty, $databaseDriver);
$query->whereRaw($sql, $bindings);
}

protected function getWhereRawParameters(mixed $value, string $property): array
protected function getDatabaseDriver(Builder $query): string
{
return $query->getConnection()->getDriverName();
}


protected function getWhereRawParameters(mixed $value, string $property, string $driver): array
{
$value = mb_strtolower((string) $value, 'UTF8');

return [
"LOWER({$property}) LIKE ?",
"LOWER({$property}) LIKE ?".self::maybeSpecifyEscapeChar($driver),
['%'.self::escapeLike($value).'%'],
];
}

private static function escapeLike(string $value): string
protected static function escapeLike(string $value): string
{
return str_replace(
['\\', '_', '%'],
['\\\\', '\\_', '\\%'],
$value,
);
}

/**
* @param 'sqlite'|'pgsql'|'sqlsrc'|'mysql' $driver
* @return string
*/
protected static function maybeSpecifyEscapeChar(string $driver): string
{
if(! in_array($driver, ['sqlite','pgsql','sqlsrv'])) {
return '';
}

return " ESCAPE '\'";
}
}
26 changes: 25 additions & 1 deletion tests/FilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

use Pest\Expectation;

use function PHPUnit\Framework\assertObjectHasProperty;

use Spatie\QueryBuilder\AllowedFilter;
Expand Down Expand Up @@ -86,9 +88,31 @@
->where(DB::raw('LOWER(`test_models`.`name`)'), 'LIKE', 'john')
->toSql();

expect($queryBuilderSql)->toEqual($expectedSql);
expect($queryBuilderSql)->toContain($expectedSql);
});

it('specifies escape character in supported databases', function (string $dbDriver) {
$fakeConnection = "test_{$dbDriver}";

DB::connectUsing($fakeConnection, [
'driver' => $dbDriver,
'database' => null,
]);

DB::usingConnection($fakeConnection, function () use ($dbDriver) {
$request = new Request([
'filter' => ['name' => 'to_find'],
]);

$queryBuilderSql = QueryBuilder::for(TestModel::select('id', 'name'), $request)
->allowedFilters('name', 'id')
->toSql();

expect($queryBuilderSql)->when(in_array($dbDriver, ["sqlite","pgsql","sqlsrv"]), fn (Expectation $query) => $query->toContain("ESCAPE '\'"));
expect($queryBuilderSql)->when($dbDriver === 'mysql', fn (Expectation $query) => $query->not->toContain("ESCAPE '\'"));
});
})->with(['sqlite', 'mysql', 'pgsql', 'sqlsrv']);

it('can filter results based on the existence of a property in an array', function () {
$results = createQueryFromFilterRequest([
'id' => '1,2',
Expand Down

0 comments on commit d250c1b

Please sign in to comment.