diff --git a/src/Engines/TypesenseEngine.php b/src/Engines/TypesenseEngine.php index ad78ec38..ed0c5f1a 100644 --- a/src/Engines/TypesenseEngine.php +++ b/src/Engines/TypesenseEngine.php @@ -364,9 +364,16 @@ protected function filters(Builder $builder): string ->values() ->implode(' && '); - return $whereFilter.( - ($whereFilter !== '' && $whereInFilter !== '') ? ' && ' : '' - ).$whereInFilter; + $whereNotInFilter = collect($builder->whereNotIns) + ->map(fn ($value, $key) => $this->parseWhereNotInFilter($this->parseFilterValue($value), $key)) + ->values() + ->implode(' && '); + + $filters = collect([$whereFilter, $whereInFilter, $whereNotInFilter]) + ->filter() + ->implode(' && '); + + return $filters; } /** @@ -414,6 +421,18 @@ protected function parseWhereInFilter(array $value, string $key): string return sprintf('%s:=[%s]', $key, implode(', ', $value)); } + /** + * Create a "where not in" filter string. + * + * @param array|string $value + * @param string $key + * @return string + */ + protected function parseWhereNotInFilter(array $value, string $key): string + { + return sprintf('%s:!=[%s]', $key, implode(', ', $value)); + } + /** * Parse the order by fields for the query. * diff --git a/tests/Unit/TypesenseEngineTest.php b/tests/Unit/TypesenseEngineTest.php index 69d0d504..7b821e9e 100644 --- a/tests/Unit/TypesenseEngineTest.php +++ b/tests/Unit/TypesenseEngineTest.php @@ -65,10 +65,13 @@ public function test_filters_method() $builder->whereIns = [ 'category' => ['electronics', 'books'], ]; + $builder->whereNotIns = [ + 'category' => ['furniture', 'phones'], + ]; $result = $this->invokeMethod($this->engine, 'filters', [$builder]); - $expected = 'status:=active && age:=25 && category:=[electronics, books]'; + $expected = 'status:=active && age:=25 && category:=[electronics, books] && category:!=[furniture, phones]'; $this->assertEquals($expected, $result); } @@ -100,6 +103,11 @@ public function test_parse_where_in_filter_method() $this->assertEquals('id:=[1, 2, 3]', $this->invokeMethod($this->engine, 'parseWhereInFilter', [[1, 2, 3], 'id'])); } + public function test_parse_where_not_in_filter_metheod() + { + $this->assertEquals('category:!=[electronics, books]', $this->invokeMethod($this->engine, 'parseWhereNotInFilter', [['electronics', 'books'], 'category'])); + $this->assertEquals('id:!=[1, 2, 3]', $this->invokeMethod($this->engine, 'parseWhereNotInFilter', [[1, 2, 3], 'id'])); + } public function test_update_method(): void { // Mock models and their methods