2018-07-31 12:03:01 +02:00
class DossierSearchService
2019-08-06 11:02:54 +02:00
def self . matching_dossiers_for_instructeur ( search_terms , instructeur )
dossier_by_exact_id_for_instructeur ( search_terms , instructeur )
. presence || dossier_by_full_text_for_instructeur ( search_terms , instructeur )
2018-07-31 12:03:01 +02:00
end
2020-04-03 16:07:18 +02:00
def self . matching_dossiers_for_user ( search_terms , user )
dossier_by_exact_id_for_user ( search_terms , user )
. presence || dossier_by_full_text_for_user ( search_terms , user . dossiers ) || dossier_by_full_text_for_user ( search_terms , user . dossiers_invites )
end
2018-07-31 12:03:01 +02:00
private
2019-08-06 11:02:54 +02:00
def self . dossier_by_exact_id_for_instructeur ( search_terms , instructeur )
2018-07-31 14:29:37 +02:00
id = search_terms . to_i
2019-08-06 11:02:54 +02:00
if id != 0 && id_compatible? ( id ) # Sometimes instructeur is searching dossiers with a big number (ex: SIRET), ActiveRecord can't deal with them and throws ActiveModel::RangeError. id_compatible? prevents this.
dossiers_by_id ( id , instructeur )
2018-07-31 14:54:55 +02:00
else
Dossier . none
2018-07-31 14:29:37 +02:00
end
end
2019-08-06 11:02:54 +02:00
def self . dossiers_by_id ( id , instructeur )
2021-03-22 10:05:04 +01:00
instructeur . dossiers . where ( id : id ) . uniq
2018-07-31 12:03:01 +02:00
end
def self . id_compatible? ( number )
2018-07-31 14:45:50 +02:00
ActiveRecord :: Type :: Integer . new . serialize ( number )
true
rescue ActiveModel :: RangeError
false
2018-07-31 12:03:01 +02:00
end
2018-07-31 14:32:17 +02:00
2020-04-03 16:07:18 +02:00
def self . dossier_by_full_text_for_user ( search_terms , dossiers )
ts_vector = " to_tsvector('french', search_terms) "
ts_query = " to_tsquery('french', #{ Dossier . connection . quote ( to_tsquery ( search_terms ) ) } ) "
dossiers
. where ( " #{ ts_vector } @@ #{ ts_query } " )
2021-02-17 18:25:41 +01:00
. order ( Arel . sql ( " COALESCE(ts_rank( #{ ts_vector } , #{ ts_query } ), 0) DESC " ) )
2020-04-03 16:07:18 +02:00
end
def self . dossier_by_exact_id_for_user ( search_terms , user )
id = search_terms . to_i
if id != 0 && id_compatible? ( id ) # Sometimes user is searching dossiers with a big number (ex: SIRET), ActiveRecord can't deal with them and throws ActiveModel::RangeError. id_compatible? prevents this.
Dossier . where ( id : user . dossiers . where ( id : id ) + user . dossiers_invites . where ( id : id ) ) . distinct
else
Dossier . none
end
end
2019-08-06 11:02:54 +02:00
def self . dossier_by_full_text_for_instructeur ( search_terms , instructeur )
2018-07-31 15:08:10 +02:00
ts_vector = " to_tsvector('french', search_terms || private_search_terms) "
ts_query = " to_tsquery('french', #{ Dossier . connection . quote ( to_tsquery ( search_terms ) ) } ) "
2019-08-06 11:02:54 +02:00
instructeur
2018-07-31 15:08:10 +02:00
. dossiers
. state_not_brouillon
. where ( " #{ ts_vector } @@ #{ ts_query } " )
2021-02-17 18:25:41 +01:00
. order ( Arel . sql ( " COALESCE(ts_rank( #{ ts_vector } , #{ ts_query } ), 0) DESC " ) )
2018-07-31 15:08:10 +02:00
end
def self . to_tsquery ( search_terms )
2019-05-22 14:34:46 +02:00
( search_terms || " " )
2021-02-16 15:05:04 +01:00
. gsub ( / ['? \\ :&|!<>()] / , " " ) # drop disallowed characters
2020-04-20 14:27:43 +02:00
. strip
2018-08-22 18:36:24 +02:00
. split ( / \ s+ / ) # split words
. map { | x | " #{ x } :* " } # enable prefix matching
2018-07-31 15:08:10 +02:00
. join ( " & " )
2018-07-31 14:32:17 +02:00
end
2018-07-31 12:03:01 +02:00
end