@@ -1,182 +1,40 @@
1−module Search exposing
2− ( Query
3− , Search(..)
4− , SearchResult
5− , combine
6− , contramap
7− , search
8− , searchList
9− )
1+module Search exposing (searchList)
102
11−import Set exposing (Set)
12−
13−
14−ignoredCharacters : Set Char
15−ignoredCharacters =
16− Set.fromList [ '_', '-', '.' ]
17−
18−
19−prepareString : String -> String
20−prepareString =
21− String.filter (\c -> Set.member c ignoredCharacters |> not)
22− >> String.toLower
23−
24−
25−type SearchResult
26− = Match Int
27− | NoMatch {- | A search result for an empty query. It is for the most part just ignored, hance the name. -}
28− | Ignore
29−
30−
31−{-| Used to combine different search results within one search entry.
32−-}
33−combine : List SearchResult -> SearchResult
34−combine ress =
35− case ress of
36− [] ->
37− NoMatch
38−
39− _ ->
40− if List.all ((==) Ignore) ress then
41− Ignore
42−
43− else
44− let
45− go : List SearchResult -> SearchResult
46− go rr =
47− case rr of
48− [] ->
49− NoMatch
50−
51− NoMatch :: xs ->
52− go xs
53−
54− (Match score) :: xs ->
55− case go xs of
56− NoMatch ->
57− Match score
58−
59− Match score_ ->
60− Match (score + score_)
61−
62− Ignore ->
63− Match score
64−
65− Ignore :: xs ->
66− go xs
67− in
68− go ress
69−
70−
71−type alias Haystack =
72− String
3+import Html exposing (..)
4+import Html.Lazy as Lazy
735
746
757type alias Needle =
768 String
779
7810
79−type Query
80− = Query Needle
81−
82−
83−{-| Constructs queries from an input string. (Splits on spaces and requires all words to match)
84−-}
85−constructQueries : String -> List Query
86−constructQueries =
87− prepareString >> String.words >> List.filter (String.isEmpty >> not) >> List.filter (String.length >> (<) 1) >> List.map Query
88−
89−
90−{-| Search a search term within a search entry.
91−-}
92−search : Query -> Haystack -> SearchResult
93−search (Query needle) haystack =
94− if String.contains needle (prepareString haystack) then
95− Match 1
96−
97− else
98− NoMatch
11+type alias Haystack =
12+ String
9913
10014
101−{-| Requires all search results to be matched
102−-}
103−searchAll : List SearchResult -> SearchResult
104−searchAll =
15+search : List Needle -> Haystack -> Bool
16+search needles haystack =
10517 let
106− combineQueries : SearchResult -> SearchResult -> SearchResult
107− combineQueries x y =
108− case ( x, y ) of
109− ( NoMatch, _ ) ->
110− NoMatch
111−
112− ( _, NoMatch ) ->
113− NoMatch
114−
115− ( Ignore, a ) ->
116− a
117−
118− ( a, Ignore ) ->
119− a
120−
121− ( Match a, Match b ) ->
122− Match (a + b)
18+ haystack_ =
19+ haystack |> String.toLower
12320 in
124− List.foldl combineQueries Ignore
125−
126−
127−{-| A list of search inputs with the definition of what it means to search for that query.
128−-}
129−type Search a
130− = Search (List ( String, Query -> a -> SearchResult ))
131−
132−
133−contramap : (b -> a) -> Search a -> Search b
134−contramap f (Search s) =
135− List.map (\( q, g ) -> ( q, \query b -> g query (f b) )) s
136− |> Search
21+ List.all (\needle -> String.contains needle haystack_) needles
13722
13823
139−{-| The main function of the module. Search a list with the given `Search`.
140−-}
141−searchList : Search a -> List a -> List a
142−searchList (Search searches) aa =
143− let
144− searchByTerm =
145− searches
146− |> List.concatMap
147− (\( s, f ) ->
148− let
149− qq =
150− constructQueries s
151− in
152− List.map (\q a -> f q a) qq
153− )
154−
155− searchEntry a =
156− List.map (\f -> f a) searchByTerm |> searchAll
157− in
158− aa
159− |> List.map (\a -> ( searchEntry a, a ))
160− |> sortResult Tuple.first
161− |> List.map Tuple.second
24+prepareNeedles : String -> List Needle
25+prepareNeedles =
26+ String.toLower
27+ >> String.words
28+ >> List.map String.trim
29+ >> List.filter (String.isEmpty >> not)
30+ >> List.filter (String.length >> (<) 1)
16231
16332
164−sortResult : (a -> SearchResult) -> List a -> List a
165−sortResult f =
166− List.filterMap
167− (\a ->
168− case f a of
169− Match score ->
170− Just ( score, a )
171−
172− NoMatch ->
173− Nothing
33+searchList : Needle -> (a -> Haystack) -> (List a -> Html msg) -> List a -> Html msg
34+searchList needle getHaystack show aa =
35+ case prepareNeedles needle of
36+ [] ->
37+ Lazy.lazy show aa
17438
175− Ignore ->
176− Just ( 0, a )
177− )
178− -- Here we assume that the sort is stable which is not true for old
179− -- versions of ECMAScript which would result in undeterministic
180− -- ordering for empty queries.
181− >> List.sortBy Tuple.first
182− >> List.map Tuple.second
39+ needles ->
40+ aa |> List.filter (\a -> search needles (getHaystack a)) |> show