@@ -6,8 +6,9 @@ module Share.Postgres.Search.DefinitionSearch.Queries
6
6
claimUnsyncedRelease ,
7
7
insertDefinitionDocuments ,
8
8
cleanIndexForRelease ,
9
- defNameInfixSearch ,
10
- definitionSearch ,
9
+ defNameCompletionSearch ,
10
+ definitionTokenSearch ,
11
+ definitionNameSearch ,
11
12
DefnNameSearchFilter (.. ),
12
13
-- Exported for logging/debugging
13
14
searchTokensToTsQuery ,
@@ -268,9 +269,9 @@ data DefnNameSearchFilter
268
269
| ReleaseFilter ReleaseId
269
270
| UserFilter UserId
270
271
271
- -- | Find definitions whose name contains the query.
272
- defNameInfixSearch :: Maybe UserId -> Maybe DefnNameSearchFilter -> Query -> Limit -> Transaction e [(ProjectId , ReleaseId , Name , TermOrTypeTag )]
273
- defNameInfixSearch mayCaller mayFilter (Query query) limit = do
272
+ -- | Find names which would be valid completions for the given query.
273
+ defNameCompletionSearch :: Maybe UserId -> Maybe DefnNameSearchFilter -> Query -> Limit -> Transaction e [(ProjectId , ReleaseId , Name , TermOrTypeTag )]
274
+ defNameCompletionSearch mayCaller mayFilter (Query query) limit = do
274
275
let filters = case mayFilter of
275
276
Just (ProjectFilter projId) -> [sql | AND doc.project_id = #{projId} |]
276
277
Just (ReleaseFilter relId) -> [sql | AND doc.release_id = #{relId} |]
@@ -309,8 +310,9 @@ defNameInfixSearch mayCaller mayFilter (Query query) limit = do
309
310
-- Names are stored in absolute form, but we usually work with them in relative form.
310
311
<&> over (traversed . _3) Name. makeRelative
311
312
312
- definitionSearch :: Maybe UserId -> Maybe DefnNameSearchFilter -> Limit -> Set (DefnSearchToken (Either Name ShortHash )) -> Maybe Arity -> Transaction e [(ProjectId , ReleaseId , Name , TermOrTypeSummary )]
313
- definitionSearch mayCaller mayFilter limit searchTokens preferredArity = do
313
+ -- | Perform a type search for the given tokens.
314
+ definitionTokenSearch :: Maybe UserId -> Maybe DefnNameSearchFilter -> Limit -> Set (DefnSearchToken (Either Name ShortHash )) -> Maybe Arity -> Transaction e [(ProjectId , ReleaseId , Name , TermOrTypeSummary )]
315
+ definitionTokenSearch mayCaller mayFilter limit searchTokens preferredArity = do
314
316
let filters = case mayFilter of
315
317
Just (ProjectFilter projId) -> [sql | AND doc.project_id = #{projId} |]
316
318
Just (ReleaseFilter relId) -> [sql | AND doc.release_id = #{relId} |]
@@ -355,3 +357,40 @@ definitionSearch mayCaller mayFilter limit searchTokens preferredArity = do
355
357
Aeson. Error err -> unrecoverableError $ FailedToDecodeMetadata v (Text. pack err)
356
358
Aeson. Success summary -> pure summary
357
359
)
360
+
361
+ -- | Perform a fuzzy trigram search on definition names
362
+ definitionNameSearch :: Maybe UserId -> Maybe DefnNameSearchFilter -> Limit -> Query -> Transaction e [(ProjectId , ReleaseId , Name , TermOrTypeSummary )]
363
+ definitionNameSearch mayCaller mayFilter limit (Query query) = do
364
+ let filters = case mayFilter of
365
+ Just (ProjectFilter projId) -> [sql | AND doc.project_id = #{projId} |]
366
+ Just (ReleaseFilter relId) -> [sql | AND doc.release_id = #{relId} |]
367
+ Just (UserFilter userId) -> [sql | AND p.owner_user_id = #{userId} |]
368
+ Nothing -> mempty
369
+ rows <-
370
+ queryListRows @ (ProjectId , ReleaseId , Name , Hasql. Jsonb )
371
+ [sql |
372
+ WITH matches_deduped_by_project(project_id, release_id, name, metadata) AS (
373
+ SELECT DISTINCT ON (doc.project_id, doc.name) doc.project_id, doc.release_id, doc.name, doc.metadata FROM global_definition_search_docs doc
374
+ JOIN projects p ON p.id = doc.project_id
375
+ JOIN project_releases r ON r.id = doc.release_id
376
+ WHERE
377
+ -- Adjust the similarity threshold as needed (between 0 and 1)
378
+ word_similarity(#{query}, doc.name) >= 0.5
379
+ AND (NOT p.private OR (#{mayCaller} IS NOT NULL AND EXISTS (SELECT FROM accessible_private_projects pp WHERE pp.user_id = #{mayCaller} AND pp.project_id = p.id)))
380
+ ^{filters}
381
+ ORDER BY doc.project_id, doc.name, r.major_version, r.minor_version, r.patch_version
382
+ ) SELECT m.project_id, m.release_id, m.name, m.metadata
383
+ FROM matches_deduped_by_project m
384
+ -- Score matches by name similarity
385
+ ORDER BY word_similarity(#{query}, m.name) DESC
386
+ LIMIT #{limit}
387
+ |]
388
+ rows
389
+ & over (traversed . _3) Name. makeRelative
390
+ & traverseOf
391
+ (traversed . _4)
392
+ ( \ (Hasql. Jsonb v) -> do
393
+ case fromJSON v of
394
+ Aeson. Error err -> unrecoverableError $ FailedToDecodeMetadata v (Text. pack err)
395
+ Aeson. Success summary -> pure summary
396
+ )
0 commit comments