Skip to content

Commit 08de9bf

Browse files
authored
[10.x][Algolia] Support numeric 'whereNotIn' to prevent silent failures (#959)
* fix(algolia): support whereNotIn filters in Algolia engine search * refactor(algolia): improve whereNotIn filter handling and add related tests
1 parent 2b047f6 commit 08de9bf

File tree

3 files changed

+128
-2
lines changed

3 files changed

+128
-2
lines changed

src/Engines/AlgoliaEngine.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,27 @@ protected function filters(Builder $builder)
133133
->map(fn ($value, $key) => $key.'='.$value)
134134
->values();
135135

136-
return $wheres->merge(collect($builder->whereIns)->map(function ($values, $key) {
136+
$whereIns = collect($builder->whereIns)->map(function ($values, $key) {
137137
if (empty($values)) {
138138
return '0=1';
139139
}
140140

141141
return collect($values)
142142
->map(fn ($value) => $key.'='.$value)
143143
->all();
144-
})->values())->values()->all();
144+
})->values();
145+
146+
$whereNotIns = collect($builder->whereNotIns)->flatMap(function ($values, $key) {
147+
if (empty($values)) {
148+
return [];
149+
}
150+
151+
return collect($values)
152+
->map(fn ($value) => $key.'!='.$value)
153+
->all();
154+
});
155+
156+
return $wheres->merge($whereIns)->merge($whereNotIns)->values()->all();
145157
}
146158

147159
/**

tests/Feature/Engines/Algolia3EngineTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,57 @@ public function test_update_empty_searchable_array_from_soft_deleted_model_does_
243243

244244
unset($_ENV['chirp.toSearchableArray']);
245245
}
246+
247+
public function test_search_sends_correct_parameters_to_algolia_for_where_not_in_search()
248+
{
249+
$engine = $this->app->make(EngineManager::class)->engine();
250+
$this->client->shouldReceive('initIndex')->once()->with('users')->andReturn($index = m::mock(stdClass::class));
251+
252+
$index->shouldReceive('search')->once()->with('zonda', [
253+
'numericFilters' => [
254+
'foo!=1',
255+
'foo!=2',
256+
],
257+
]);
258+
259+
$builder = new Builder(new SearchableUser, 'zonda');
260+
$builder->whereNotIn('foo', [1, 2]);
261+
262+
$engine->search($builder);
263+
}
264+
265+
public function test_search_ignores_empty_where_not_in_search()
266+
{
267+
$engine = $this->app->make(EngineManager::class)->engine();
268+
$this->client->shouldReceive('initIndex')->once()->with('users')->andReturn($index = m::mock(stdClass::class));
269+
270+
$index->shouldReceive('search')->once()->with('zonda', []);
271+
272+
$builder = new Builder(new SearchableUser, 'zonda');
273+
$builder->whereNotIn('foo', []);
274+
275+
$engine->search($builder);
276+
}
277+
278+
public function test_search_sends_correct_parameters_to_algolia_for_mixed_search()
279+
{
280+
$engine = $this->app->make(EngineManager::class)->engine();
281+
$this->client->shouldReceive('initIndex')->once()->with('users')->andReturn($index = m::mock(stdClass::class));
282+
283+
$index->shouldReceive('search')->once()->with('zonda', [
284+
'numericFilters' => [
285+
'foo=1',
286+
['bar=1', 'bar=2'],
287+
'baz!=1',
288+
'baz!=2',
289+
],
290+
]);
291+
292+
$builder = new Builder(new SearchableUser, 'zonda');
293+
$builder->where('foo', 1)
294+
->whereIn('bar', [1, 2])
295+
->whereNotIn('baz', [1, 2]);
296+
297+
$engine->search($builder);
298+
}
246299
}

tests/Feature/Engines/Algolia4EngineTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,4 +234,65 @@ public function test_update_empty_searchable_array_from_soft_deleted_model_does_
234234

235235
unset($_ENV['searchable.chirp']);
236236
}
237+
238+
public function test_search_sends_correct_parameters_to_algolia_for_where_not_in_search()
239+
{
240+
$engine = $this->app->make(EngineManager::class)->engine();
241+
242+
$this->client->shouldReceive('searchSingleIndex')->once()->with(
243+
'users',
244+
[
245+
'query' => 'zonda',
246+
'numericFilters' => [
247+
'foo!=1',
248+
'foo!=2',
249+
],
250+
]
251+
);
252+
253+
$builder = new Builder(new SearchableUser, 'zonda');
254+
$builder->whereNotIn('foo', [1, 2]);
255+
256+
$engine->search($builder);
257+
}
258+
259+
public function test_search_ignores_empty_where_not_in_search()
260+
{
261+
$engine = $this->app->make(EngineManager::class)->engine();
262+
263+
$this->client->shouldReceive('searchSingleIndex')->once()->with(
264+
'users',
265+
['query' => 'zonda']
266+
);
267+
268+
$builder = new Builder(new SearchableUser, 'zonda');
269+
$builder->whereNotIn('foo', []);
270+
271+
$engine->search($builder);
272+
}
273+
274+
public function test_search_sends_correct_parameters_to_algolia_for_mixed_search()
275+
{
276+
$engine = $this->app->make(EngineManager::class)->engine();
277+
278+
$this->client->shouldReceive('searchSingleIndex')->once()->with(
279+
'users',
280+
[
281+
'query' => 'zonda',
282+
'numericFilters' => [
283+
'foo=1',
284+
['bar=1', 'bar=2'],
285+
'baz!=1',
286+
'baz!=2',
287+
],
288+
]
289+
);
290+
291+
$builder = new Builder(new SearchableUser, 'zonda');
292+
$builder->where('foo', 1)
293+
->whereIn('bar', [1, 2])
294+
->whereNotIn('baz', [1, 2]);
295+
296+
$engine->search($builder);
297+
}
237298
}

0 commit comments

Comments
 (0)