Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add whereLike clause to query builder #52147

Merged
Prev Previous commit
Next Next commit
Add whereLike clause to SQLite grammar
  • Loading branch information
einar-hansen committed Jul 16, 2024
commit eb91c38c9f67ea18bbd6333fc9c39cf2e29468e6
4 changes: 4 additions & 0 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
@@ -2186,6 +2186,10 @@ public function whereLike($column, $value, $caseSensitive = false, $boolean = 'a

$this->wheres[] = compact('type', 'column', 'value', 'caseSensitive', 'boolean', 'not');

if (method_exists($this->grammar, 'prepareWhereLikeBinding')) {
$value = $this->grammar->prepareWhereLikeBinding($value, $caseSensitive);
}

$this->addBinding($value);

return $this;
37 changes: 37 additions & 0 deletions src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php
Original file line number Diff line number Diff line change
@@ -117,6 +117,43 @@ protected function dateBasedWhere($type, Builder $query, $where)
return "strftime('{$type}', {$this->wrap($where['column'])}) {$where['operator']} cast({$value} as text)";
}

/**
* Compile a "where like" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereLike(Builder $query, $where)
{
if($where['caseSensitive'] == false){
return parent::whereLike($query, $where);
}
$where['operator'] = $where['not'] ? 'not glob' : 'glob';

return $this->whereBasic($query, $where);
}

/**
* Convert LIKE pattern to GLOB pattern using simple string replacement.
*
* @param string $value The LIKE pattern
* @param bool $caseSensitive Whether the pattern should be case-sensitive
* @return string The equivalent GLOB pattern
*/
public function prepareWhereLikeBinding($value, $caseSensitive)
{
if($caseSensitive == false){
return $value;
}

return str_replace(
['*', '?', '%', '_'],
['[*]', '[?]', '*', '?'],
$value
);
}

/**
* Compile the index hints for the query.
*
38 changes: 38 additions & 0 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
@@ -722,6 +722,44 @@ public function testWhereLikeClauseMysql()
$this->assertEquals([0 => '1'], $builder->getBindings());
}

public function testWhereLikeClauseSqlite()
{
$builder = $this->getSQLiteBuilder();
$builder->select('*')->from('users')->whereLike('id', '1');
$this->assertSame('select * from "users" where "id" like ?', $builder->toSql());
$this->assertEquals([0 => '1'], $builder->getBindings());

$builder = $this->getSQLiteBuilder();
$builder->select('*')->from('users')->whereLike('id', '1', true);
$this->assertSame('select * from "users" where "id" glob ?', $builder->toSql());
$this->assertEquals([0 => '1'], $builder->getBindings());

$builder = $this->getSQLiteBuilder();
$builder->select('*')->from('users')->whereLike('description', 'Hell* _orld?%', true);
$this->assertSame('select * from "users" where "description" glob ?', $builder->toSql());
$this->assertEquals([0 => 'Hell[*] ?orld[?]*'], $builder->getBindings());

$builder = $this->getSQLiteBuilder();
$builder->select('*')->from('users')->whereNotLike('id', '1');
$this->assertSame('select * from "users" where "id" not like ?', $builder->toSql());
$this->assertEquals([0 => '1'], $builder->getBindings());

$builder = $this->getSQLiteBuilder();
$builder->select('*')->from('users')->whereNotLike('description', 'Hell* _orld?%', true);
$this->assertSame('select * from "users" where "description" not glob ?', $builder->toSql());
$this->assertEquals([0 => 'Hell[*] ?orld[?]*'], $builder->getBindings());

$builder = $this->getSQLiteBuilder();
$builder->select('*')->from('users')->whereLike('name', 'John%', true)->whereNotLike('name', '%Doe%', true);
$this->assertSame('select * from "users" where "name" glob ? and "name" not glob ?', $builder->toSql());
$this->assertEquals([0 => 'John*', 1 => '*Doe*'], $builder->getBindings());

$builder = $this->getSQLiteBuilder();
$builder->select('*')->from('users')->whereLike('name', 'John%')->orWhereLike('name', 'Jane%', true);
$this->assertSame('select * from "users" where "name" like ? or "name" glob ?', $builder->toSql());
$this->assertEquals([0 => 'John%', 1 => 'Jane*'], $builder->getBindings());
}

public function testWhereDateSqlite()
{
$builder = $this->getSQLiteBuilder();
96 changes: 96 additions & 0 deletions tests/Integration/Database/Sqlite/WhereLikeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

namespace Illuminate\Tests\Integration\Database\Sqlite;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Tests\Integration\Database\DatabaseTestCase;
use PHPUnit\Framework\Attributes\RequiresOperatingSystem;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;

class WhereLikeTest extends DatabaseTestCase
{
protected function afterRefreshingDatabase()
{
Schema::create('users', function (Blueprint $table) {
$table->id('id');
$table->string('name', 200);
$table->text('email');
});
}

protected function destroyDatabaseMigrations()
{
Schema::drop('users');
}

protected function setUp(): void
{
parent::setUp();

DB::table('users')->insert([
['name' => 'John Doe', 'email' => '[email protected]'],
['name' => 'Jane Doe', 'email' => '[email protected]'],
['name' => 'Dale doe', 'email' => '[email protected]'],
['name' => 'Earl Smith', 'email' => '[email protected]'],
['name' => 'tim smith', 'email' => '[email protected]'],
]);
}


public function testWhereLike()
{
$users = DB::table('users')->whereLike('email', '[email protected]')->get();
$this->assertCount(1, $users);
$this->assertSame('[email protected]', $users[0]->email);

$users = DB::table('users')->whereLike('email', '[email protected]', true)->get();
$this->assertCount(0, $users);

$users = DB::table('users')->whereLike('email', '[email protected]', true)->get();
$this->assertCount(1, $users);
$this->assertSame('[email protected]', $users[0]->email);
}

public function testWhereNotLike()
{
$this->assertSame(4, DB::table('users')->whereNotLike('email', '[email protected]')->count());
$this->assertSame(5, DB::table('users')->whereNotLike('email', '[email protected]', true)->count());
}

public function testWhereLikeWithPercentWildcard()
{
$this->assertSame(5, DB::table('users')->whereLike('email', '%@example.com')->count());
$this->assertSame(2, DB::table('users')->whereLike('email', '%[email protected]', true)->count());
$this->assertSame(2, DB::table('users')->whereNotLike('email', '%Doe%')->count());
$this->assertSame(4, DB::table('users')->whereNotLike('email', '%smith%', true)->count());

$users = DB::table('users')->whereLike('email', 'john%')->get();
$this->assertCount(1, $users);
$this->assertSame('[email protected]', $users[0]->email);

$users = DB::table('users')->whereLike('email', '%[email protected]', true)->get();
$this->assertCount(2, $users);
$this->assertSame('[email protected]', $users[0]->email);
$this->assertSame('[email protected]', $users[1]->email);

}

public function testWhereLikeWithUnderscoreWildcard()
{
$users = DB::table('users')->whereLike('email', '_a_e_%@example.com')->get();
$this->assertCount(2, $users);
$this->assertSame('[email protected]', $users[0]->email);
$this->assertSame('[email protected]', $users[1]->email);

$users = DB::table('users')->whereLike('email', '[email protected]', true)->get();
$this->assertCount(1, $users);
$this->assertSame('[email protected]', $users[0]->email);

$users = DB::table('users')->whereNotLike('email', '%[email protected]', true)->get();
$this->assertCount(2, $users);
$this->assertSame('[email protected]', $users[0]->email);
$this->assertSame('[email protected]', $users[1]->email);
}
}
Loading