Author: Kevin Schoon [kevinschoon@gmail.com]
Hash: eae31e654b44dcfd6d57e31f9d1a4c66147ec4e9
Timestamp: Sun, 25 Apr 2021 19:35:55 +0000 (3 years ago)

+50 -28 +/-3 browse
continued filtering refactor
1diff --git a/lib/cmd.ml b/lib/cmd.ml
2index c402032..15cdf75 100644
3--- a/lib/cmd.ml
4+++ b/lib/cmd.ml
5 @@ -64,16 +64,16 @@ let list_style_arg =
6 let filter_args =
7 let open Command.Let_syntax in
8 [%map_open
9- let title =
10+ let titles =
11 flag "title"
12- (optional (search_arg `Title))
13+ (listed (search_arg `Title))
14 ~doc:"regular expression matching the note title"
15 and tags =
16 flag "tag"
17 (listed (search_arg `Tags))
18 ~doc:"sequence of regular expressions matching note tags"
19 and operator = flag "and" no_arg ~doc:"logical AND instead of default OR" in
20- (title, tags, operator)]
21+ (titles, tags, operator)]
22
23 (*
24 * commands
25 @@ -89,7 +89,7 @@ note to stdout as plain text however the encoding can be adjusted to yaml or
26 json for consumption by other tools.
27 |})
28 [%map_open
29- let title, tags, operator = filter_args
30+ let titles, tags, operator = filter_args
31 and encoding =
32 flag "encoding"
33 (optional_with_default cfg.encoding encoding_arg)
34 @@ -98,7 +98,7 @@ json for consumption by other tools.
35 fun () ->
36 let notes =
37 Note.find_many
38- ~term:{ title; tags; operator = flag_to_op operator }
39+ ~term:{ titles; tags; operator = flag_to_op operator }
40 get_notes
41 in
42 List.iter
43 @@ -163,12 +163,12 @@ let delete_note =
44 Delete the first note that matches the filter criteria.
45 |})
46 [%map_open
47- let title, tags, operator = filter_args in
48+ let titles, tags, operator = filter_args in
49 fun () ->
50 let notes = get_notes in
51 let note =
52 Note.find_one
53- ~term:{ title; tags; operator = flag_to_op operator }
54+ ~term:{ titles; tags; operator = flag_to_op operator }
55 notes
56 in
57 match note with
58 @@ -185,11 +185,11 @@ let edit_note =
59 Select a note that matches the filter criteria and open it in your text editor.
60 |})
61 [%map_open
62- let title, tags, operator = filter_args in
63+ let titles, tags, operator = filter_args in
64 fun () ->
65 let note =
66 Note.find_one
67- ~term:{ title; tags; operator = flag_to_op operator }
68+ ~term:{ titles; tags; operator = flag_to_op operator }
69 get_notes
70 in
71 match note with
72 @@ -207,7 +207,7 @@ List one or more notes that match the filter criteria, if no filter criteria
73 is provided then all notes will be listed.
74 |})
75 [%map_open
76- let title, tags, operator = filter_args
77+ let titles, tags, operator = filter_args
78 and style =
79 flag "style"
80 (optional_with_default cfg.list_style list_style_arg)
81 @@ -220,7 +220,7 @@ is provided then all notes will be listed.
82 fun () ->
83 let notes =
84 Note.find_many
85- ~term:{ title; tags; operator = flag_to_op operator }
86+ ~term:{ titles; tags; operator = flag_to_op operator }
87 get_notes
88 in
89 let styles = cfg.styles in
90 diff --git a/lib/note.ml b/lib/note.ml
91index e73442b..607e3dc 100644
92--- a/lib/note.ml
93+++ b/lib/note.ml
94 @@ -3,7 +3,7 @@ open Core
95 type operator = And | Or
96
97 and term = {
98- title : Re.Str.regexp option;
99+ titles : Re.Str.regexp list;
100 tags : Re.Str.regexp list;
101 operator : operator;
102 }
103 @@ -143,19 +143,21 @@ end
104
105 let find_many ~term notes =
106 let open Re.Str in
107- if Option.is_none term.title && List.length term.tags = 0 then notes
108+ let n_titles, n_tags = (List.length term.titles, List.length term.tags) in
109+ if n_titles + n_tags = 0 then notes
110 else
111 List.filter
112 ~f:(fun note ->
113 let has_title =
114- match term.title with
115- | Some title -> string_match title (get_title note) 0
116- | None -> false
117- in
118- let has_title = Option.is_none term.title || has_title in
119- let has_tags =
120 let result =
121- List.find
122+ List.count
123+ ~f:(fun expr -> string_match expr (get_title note) 0)
124+ term.titles
125+ in
126+ match term.operator with Or -> result > 0 | And -> result = n_titles
127+ and has_tags =
128+ let result =
129+ List.count
130 ~f:(fun expr ->
131 Option.is_some
132 (List.find
133 @@ -163,9 +165,8 @@ let find_many ~term notes =
134 (get_tags note)))
135 term.tags
136 in
137- Option.is_some result
138+ match term.operator with Or -> result > 0 | And -> result = n_tags
139 in
140- let has_tags = List.length term.tags = 0 || has_tags in
141 match term.operator with
142 | Or -> has_title || has_tags
143 | And -> has_title && has_tags)
144 diff --git a/test/search.ml b/test/search.ml
145index e7cb68a..c98dfb4 100644
146--- a/test/search.ml
147+++ b/test/search.ml
148 @@ -22,26 +22,47 @@ let test_filter_by_keys =
149 Note.find_many
150 ~term:
151 {
152- title = None;
153+ titles = [ Re.Str.regexp "A Very Important Note" ];
154+ tags = [];
155+ operator = Note.Or;
156+ }
157+ notes
158+ in
159+ assert (List.length result = 1);
160+ let result =
161+ Note.find_many
162+ ~term:
163+ {
164+ titles = [ Re.Str.regexp "A Very Important Note" ];
165+ tags = [];
166+ operator = Note.Or;
167+ }
168+ notes
169+ in
170+ assert (List.length result = 1);
171+ let result =
172+ Note.find_many
173+ ~term:
174+ {
175+ titles = [];
176 tags =
177 [ Re.Str.regexp "fuu"; Re.Str.regexp "bar"; Re.Str.regexp "baz" ];
178- operator = Note.Or;
179+ operator = Note.And;
180 }
181 notes
182 in
183- assert (List.length result = 3)
184+ assert (List.length result = 2)
185
186 let test_filter_by_title_find_one =
187 let notes = make_notes in
188 let result =
189 Note.find_one
190- ~term:{ title = None; tags = [ Re.Str.regexp "fuu" ]; operator = Note.Or }
191+ ~term:{ titles = [Re.Str.regexp "^A.*"]; tags = []; operator = Note.Or }
192 notes
193 in
194 assert (Option.is_some result);
195 let note = Option.get result in
196- (* title should take priority *)
197- assert (Note.get_title note = "fuu")
198+ assert (Note.get_title note = "A Very Important Note")
199
200 let () =
201 test_filter_by_keys;