Skip to content

Commit

Permalink
add where in support
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Jun 29, 2021
1 parent 7c622f1 commit 2b1dd75
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 6 deletions.
21 changes: 21 additions & 0 deletions src/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ class Builder
*/
public $wheres = [];

/**
* The "where in" constraints added to the query.
*
* @var array
*/
public $whereIns = [];

/**
* The "limit" that should be applied to the search.
*
Expand Down Expand Up @@ -114,6 +121,20 @@ public function where($field, $value)
return $this;
}

/**
* Add a "where in" constraint to the search query.
*
* @param string $field
* @param array $values
* @return $this
*/
public function whereIn($field, array $values)
{
$this->whereIns[$field] = $values;

return $this;
}

/**
* Include soft deleted records in the results.
*
Expand Down
10 changes: 8 additions & 2 deletions src/Engines/AlgoliaEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,15 @@ protected function performSearch(Builder $builder, array $options = [])
*/
protected function filters(Builder $builder)
{
return collect($builder->wheres)->map(function ($value, $key) {
$wheres = collect($builder->wheres)->map(function ($value, $key) {
return $key.'='.$value;
})->values()->all();
})->values();

return $wheres->merge(collect($builder->whereIns)->map(function ($values, $key) {
return collect($values)->map(function ($value) use ($key) {
return $key.'='.$value;
})->all();
})->values())->values()->all();
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/Engines/CollectionEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ protected function searchModels(Builder $builder)
}
}
})
->when(count($builder->whereIns) > 0, function ($query) use ($builder) {
foreach ($builder->whereIns as $key => $values) {
$query->whereIn($key, $values);
}
})
->orderBy($builder->model->getKeyName(), 'desc');

$models = $this->ensureSoftDeletesAreHandled($builder, $query)
Expand Down
20 changes: 18 additions & 2 deletions src/Engines/MeiliSearchEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,25 @@ protected function performSearch(Builder $builder, array $searchParams = [])
*/
protected function filters(Builder $builder)
{
return collect($builder->wheres)->map(function ($value, $key) {
return sprintf('%s="%s"', $key, $value);
$filters = collect($builder->wheres)->map(function ($value, $key) {
return filter_var($value, FILTER_VALIDATE_INT) !== false
? sprintf('%s=%s', $key, $value)
: sprintf('%s="%s"', $key, $value);
})->values()->implode(' AND ');

if (empty($builder->whereIns)) {
return $filters;
}

foreach ($builder->whereIns as $key => $values) {
$filters = $filters.' AND ('.collect($values)->map(function ($value) use ($key) {
return filter_var($value, FILTER_VALIDATE_INT) !== false
? sprintf('%s=%s', $key, $value)
: sprintf('%s="%s"', $key, $value);
})->values()->implode(' OR ').')';
}

return $filters;
}

/**
Expand Down
14 changes: 14 additions & 0 deletions tests/Unit/AlgoliaEngineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ public function test_search_sends_correct_parameters_to_algolia()
$engine->search($builder);
}

public function test_search_sends_correct_parameters_to_algolia_for_where_in_search()
{
$client = m::mock(SearchClient::class);
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock(stdClass::class));
$index->shouldReceive('search')->with('zonda', [
'numericFilters' => ['foo=1', ['bar=1', 'bar=2']],
]);

$engine = new AlgoliaEngine($client);
$builder = new Builder(new SearchableModel, 'zonda');
$builder->where('foo', 1)->whereIn('bar', [1, 2]);
$engine->search($builder);
}

public function test_map_correctly_maps_results_to_models()
{
$client = m::mock(SearchClient::class);
Expand Down
22 changes: 20 additions & 2 deletions tests/Unit/MeiliSearchEngineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ public function test_search_sends_correct_parameters_to_meilisearch()
$client = m::mock(Client::class);
$client->shouldReceive('index')->with('table')->andReturn($index = m::mock(Indexes::class));
$index->shouldReceive('search')->with('mustang', [
'filters' => 'foo=1',
'filters' => 'foo=1 AND bar=2',
]);

$engine = new MeiliSearchEngine($client);
$builder = new Builder(new SearchableModel(), 'mustang', function ($meilisearch, $query, $options) {
$options['filters'] = 'foo=1';
$options['filters'] = 'foo=1 AND bar=2';

return $meilisearch->search($query, $options);
});
Expand Down Expand Up @@ -343,6 +343,24 @@ public function test_where_conditions_are_applied()
$engine->search($builder);
}

public function test_where_in_conditions_are_applied()
{
$builder = new Builder(new SearchableModel(), '');
$builder->where('foo', 'bar');
$builder->where('bar', 'baz');
$builder->whereIn('qux', [1, 2]);
$builder->whereIn('quux', [1, 2]);
$client = m::mock(Client::class);
$client->shouldReceive('index')->once()->andReturn($index = m::mock(Indexes::class));
$index->shouldReceive('rawSearch')->once()->with($builder->query, array_filter([
'filters' => 'foo="bar" AND bar="baz" AND (qux=1 OR qux=2) AND (quux=1 OR quux=2)',
'limit' => $builder->limit,
]))->andReturn([]);

$engine = new MeiliSearchEngine($client);
$engine->search($builder);
}

public function test_engine_returns_hits_entry_from_search_response()
{
$this->assertTrue(3 === (new MeiliSearchEngine(m::mock(Client::class)))->getTotalCount([
Expand Down

1 comment on commit 2b1dd75

@francoism90
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks for adding this (again), it's really useful and doesn't require writing additional filter parameters. :)

Please sign in to comment.