@@ -226,6 +226,13 @@ public function scopeEncryptedExact(Builder $query, string $field, string $term)
226226
227227 $ token = Tokens::exact ($ normalized , $ pepper );
228228
229+ // Check if Elasticsearch is enabled
230+ if (config ('encrypted-search.elasticsearch.enabled ' , false )) {
231+ $ modelIds = $ this ->searchElasticsearch ($ field , $ token , 'exact ' );
232+ return $ query ->whereIn ($ this ->getQualifiedKeyName (), $ modelIds );
233+ }
234+
235+ // Fallback to database
229236 return $ query ->whereIn ($ this ->getQualifiedKeyName (), function ($ sub ) use ($ field , $ token ) {
230237 $ sub ->select ('model_id ' )
231238 ->from ('encrypted_search_index ' )
@@ -259,6 +266,13 @@ public function scopeEncryptedPrefix(Builder $query, string $field, string $term
259266 $ pepper
260267 );
261268
269+ // Check if Elasticsearch is enabled
270+ if (config ('encrypted-search.elasticsearch.enabled ' , false )) {
271+ $ modelIds = $ this ->searchElasticsearch ($ field , $ tokens , 'prefix ' );
272+ return $ query ->whereIn ($ this ->getQualifiedKeyName (), $ modelIds );
273+ }
274+
275+ // Fallback to database
262276 return $ query ->whereIn ($ this ->getQualifiedKeyName (), function ($ sub ) use ($ field , $ tokens ) {
263277 $ sub ->select ('model_id ' )
264278 ->from ('encrypted_search_index ' )
@@ -284,6 +298,51 @@ protected function hasEncryptedCast(string $field): bool
284298 }
285299
286300 return str_contains (strtolower ($ casts [$ field ]), 'encrypted ' );
301+ }
302+ * Search for model IDs in Elasticsearch based on token(s).
303+ *
304+ * @param string $ field
305+ * @param string|array<int, string> $ tokens Single token or array of tokens
306+ * @param string $ type Either 'exact ' or 'prefix '
307+ * @return array<int, mixed> Array of model IDs
308+ */
309+ protected function searchElasticsearch (string $ field , $ tokens , string $ type ): array
310+ {
311+ $ index = config ('encrypted-search.elasticsearch.index ' , 'encrypted_search ' );
312+ $ service = app (ElasticsearchService::class);
313+
314+ // Normalize tokens to array
315+ $ tokenArray = is_array ($ tokens ) ? $ tokens : [$ tokens ];
316+
317+ // Build Elasticsearch query
318+ $ query = [
319+ 'query ' => [
320+ 'bool ' => [
321+ 'must ' => [
322+ ['term ' => ['model_type.keyword ' => static ::class]],
323+ ['term ' => ['field.keyword ' => $ field ]],
324+ ['term ' => ['type.keyword ' => $ type ]],
325+ ['terms ' => ['token.keyword ' => $ tokenArray ]],
326+ ],
327+ ],
328+ ],
329+ '_source ' => ['model_id ' ],
330+ 'size ' => 10000 ,
331+ ];
332+
333+ try {
334+ $ results = $ service ->search ($ index , $ query );
335+
336+ // Extract unique model IDs from results
337+ return collect ($ results )
338+ ->pluck ('_source.model_id ' )
339+ ->unique ()
340+ ->values ()
341+ ->toArray ();
342+ } catch (\Throwable $ e ) {
343+ logger ()->warning ('[EncryptedSearch] Elasticsearch search failed: ' . $ e ->getMessage ());
344+ return [];
345+ }
287346 }
288347
289348 /**
0 commit comments