From 0a457216490287489eb1ac4c2aa6295cd21a1828 Mon Sep 17 00:00:00 2001 From: Ricardo Gobbo de Souza Date: Wed, 28 Sep 2022 14:50:06 -0300 Subject: [PATCH] Improvements `whereLike` --- README.md | 12 ++++++ src/Macros/Filter.php | 5 +-- src/Macros/WhereLike.php | 67 +++++++++++++++++++--------------- tests/Macros/FilterTest.php | 6 +-- tests/Macros/WhereLikeTest.php | 20 ++++++++-- 5 files changed, 69 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 21dd901..93ed407 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,18 @@ $query->whereLike('title', 'john')->get(); // Returns all results where title includes `john` ``` +```php +$query->whereLike('title', 'john', false)->get(); + +// Returns all results where title ends with `john` +``` + +```php +$query->whereLike('title', 'john', true, false)->get(); + +// Returns all results where title starts with `john` +``` + You can also supply an array of columns to search in: ```php $query->whereLike(['title', 'contact.name'], 'john')->get(); diff --git a/src/Macros/Filter.php b/src/Macros/Filter.php index ceff032..24293b1 100644 --- a/src/Macros/Filter.php +++ b/src/Macros/Filter.php @@ -2,7 +2,6 @@ namespace Datalogix\BuilderMacros\Macros; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Arr; /** @@ -17,9 +16,7 @@ public function __invoke() { return function ($filters) { foreach (Arr::wrap($filters) as $column => $filter) { - $this->when($filter, function (Builder $query, $filter) use ($column) { - return $query->whereLike($column, $filter); - }); + $this->whereLike($column, $filter); } return $this; diff --git a/src/Macros/WhereLike.php b/src/Macros/WhereLike.php index beffcdd..3cb3ce2 100644 --- a/src/Macros/WhereLike.php +++ b/src/Macros/WhereLike.php @@ -17,40 +17,47 @@ class WhereLike { public function __invoke() { - return function ($columns, $value) { - $this->where(function (Builder $query) use ($columns, $value) { - foreach (Arr::wrap($columns) as $column) { - $query->when( - Str::contains($column, '.'), - - // Relational searches - function (Builder $query) use ($column, $value) { - $parts = explode('.', $column); - $relationColumn = array_pop($parts); - $relationName = join('.', $parts); - - return $query->orWhereHas( - $relationName, - function (Builder $query) use ($relationColumn, $value) { - if (Str::endsWith($relationColumn, '_id')) { - $query->where($relationColumn, $value); - } else { - $query->where($relationColumn, 'LIKE', "%{$value}%"); + return function ($columns, $value, $start = true, $end = true) { + $start = $start === true ? '%' : $start; + $end = $end === true ? '%' : $end; + + $this->when(filled($value), function (Builder $query) use ($columns, $value, $start, $end) { + return $query->where(function (Builder $query) use ($columns, $value, $start, $end) { + $from = $query->getQuery()->from; + + foreach (Arr::wrap($columns) as $column) { + $query->when( + Str::contains($column, '.'), + + // Relational searches + function (Builder $query) use ($column, $value, $start, $end) { + $parts = explode('.', $column); + $relationColumn = array_pop($parts); + $relationName = join('.', $parts); + + return $query->orWhereHas( + $relationName, + function (Builder $query) use ($relationColumn, $value, $start, $end) { + if (Str::endsWith($relationColumn, '_id')) { + $query->where($relationColumn, $value); + } else { + $query->where($relationColumn, 'LIKE', $start.$value.$end); + } } + ); + }, + + // Default searches + function (Builder $query) use ($from, $column, $value, $start, $end) { + if (Str::endsWith($column, '_id')) { + return $query->orWhere(($from ? $from.'.' : '').$column, $value); } - ); - }, - // Default searches - function (Builder $query) use ($column, $value) { - if (Str::endsWith($column, '_id')) { - return $query->orWhere($column, $value); + return $query->orWhere(($from ? $from.'.' : '').$column, 'LIKE', $start.$value.$end); } - - return $query->orWhere($column, 'LIKE', "%{$value}%"); - } - ); - } + ); + } + }); }); return $this; diff --git a/tests/Macros/FilterTest.php b/tests/Macros/FilterTest.php index 6c711e4..0044800 100644 --- a/tests/Macros/FilterTest.php +++ b/tests/Macros/FilterTest.php @@ -9,7 +9,7 @@ class FilterTest extends TestCase { public function testQueryWithOneColumn() { - $expected = 'select * from "users" where ("name" LIKE ?)'; + $expected = 'select * from "users" where ("users"."name" LIKE ?)'; $actual = User::filter(['name' => 'foo'])->toSql(); $this->assertEquals($expected, $actual); @@ -17,7 +17,7 @@ public function testQueryWithOneColumn() public function testQueryWithMoreColumns() { - $expected = 'select * from "users" where ("name" LIKE ?) and ("email" LIKE ?)'; + $expected = 'select * from "users" where ("users"."name" LIKE ?) and ("users"."email" LIKE ?)'; $actual = User::filter(['name' => 'foo', 'email' => 'foo'])->toSql(); $this->assertEquals($expected, $actual); @@ -25,7 +25,7 @@ public function testQueryWithMoreColumns() public function testQueryWithColumnNullable() { - $expected = 'select * from "users" where ("name" LIKE ?)'; + $expected = 'select * from "users" where ("users"."name" LIKE ?)'; $actual = User::filter(['name' => 'foo', 'email' => null])->toSql(); $this->assertEquals($expected, $actual); diff --git a/tests/Macros/WhereLikeTest.php b/tests/Macros/WhereLikeTest.php index 639a33e..88f7ed3 100644 --- a/tests/Macros/WhereLikeTest.php +++ b/tests/Macros/WhereLikeTest.php @@ -7,9 +7,21 @@ class WhereLikeTest extends TestCase { + public function testQueryWithBlankValue() + { + $this->assertEquals('select * from "users"', User::whereLike('name', null)->toSql()); + $this->assertEquals('select * from "users"', User::whereLike('name', '')->toSql()); + } + + public function testQueryWithFilledValue() + { + $this->assertEquals('select * from "users" where ("users"."name" LIKE ?)', User::whereLike('name', false)->toSql()); + $this->assertEquals('select * from "users" where ("users"."name" LIKE ?)', User::whereLike('name', 0)->toSql()); + } + public function testQueryWithOneColumn() { - $expected = 'select * from "users" where ("name" LIKE ?)'; + $expected = 'select * from "users" where ("users"."name" LIKE ?)'; $actual = User::whereLike('name', 'foo')->toSql(); $this->assertEquals($expected, $actual); @@ -17,7 +29,7 @@ public function testQueryWithOneColumn() public function testQueryWithMoreColumns() { - $expected = 'select * from "users" where ("name" LIKE ? or "email" LIKE ?)'; + $expected = 'select * from "users" where ("users"."name" LIKE ? or "users"."email" LIKE ?)'; $actual = User::whereLike(['name', 'email'], 'foo')->toSql(); $this->assertEquals($expected, $actual); @@ -25,7 +37,7 @@ public function testQueryWithMoreColumns() public function testQueryWithRelation() { - $expected = 'select * from "users" where ("name" LIKE ? or "email" LIKE ? or exists (select * from "posts" where "users"."id" = "posts"."user_id" and "title" LIKE ?))'; + $expected = 'select * from "users" where ("users"."name" LIKE ? or "users"."email" LIKE ? or exists (select * from "posts" where "users"."id" = "posts"."user_id" and "title" LIKE ?))'; $actual = User::whereLike(['name', 'email', 'posts.title'], 'foo')->toSql(); $this->assertEquals($expected, $actual); @@ -33,7 +45,7 @@ public function testQueryWithRelation() public function testQueryWithColumnKey() { - $expected = 'select * from "users" where ("name_id" = ?)'; + $expected = 'select * from "users" where ("users"."name_id" = ?)'; $actual = User::whereLike(['name_id'], 'foo')->toSql(); $this->assertEquals($expected, $actual);