|
1 | 1 | module SearchHelper |
| 2 | + include SearchQualifierHelper |
| 3 | + |
2 | 4 | ## |
3 | 5 | # Search & sort a default posts list based on parameters in the current request. |
4 | 6 | # |
@@ -129,86 +131,46 @@ def parse_search(raw_search) |
129 | 131 | { qualifiers: qualifiers, search: search } |
130 | 132 | end |
131 | 133 |
|
132 | | - # rubocop:disable Metrics/CyclomaticComplexity |
133 | | - |
134 | 134 | ## |
135 | 135 | # Parses a full qualifier string into an array of qualifier objects. |
136 | 136 | # @param qualifiers [String] A qualifier string as returned by {#parse_search}. |
137 | 137 | # @return [Array<Hash{Symbol => Object}>] |
138 | 138 | def parse_qualifier_strings(qualifiers) |
139 | | - valid_value = { |
140 | | - date: /^[<>=]{0,2}[\d.]+(?:s|m|h|d|w|mo|y)?$/, |
141 | | - status: /any|open|closed/, |
142 | | - numeric: /^[<>=]{0,2}[\d.]+$/ |
143 | | - } |
144 | | - |
145 | | - qualifiers.map do |qualifier| # rubocop:disable Metrics/BlockLength |
| 139 | + qualifiers.map do |qualifier| |
146 | 140 | splat = qualifier.split ':' |
147 | 141 | parameter = splat[0] |
148 | 142 | value = splat[1] |
149 | 143 |
|
150 | | - case parameter |
151 | | - when 'score' |
152 | | - next unless value.match?(valid_value[:numeric]) |
153 | | - |
154 | | - operator, val = numeric_value_sql value |
155 | | - { param: :score, operator: operator.presence || '=', value: val.to_f } |
156 | | - when 'created' |
157 | | - next unless value.match?(valid_value[:date]) |
158 | | - |
159 | | - operator, val, timeframe = date_value_sql value |
160 | | - { param: :created, operator: operator.presence || '=', timeframe: timeframe, value: val.to_i } |
161 | | - when 'user' |
162 | | - operator, val = if value.match?(valid_value[:numeric]) |
163 | | - numeric_value_sql value |
164 | | - elsif value == 'me' |
165 | | - ['=', current_user&.id&.to_i] |
166 | | - else |
167 | | - next |
168 | | - end |
169 | | - |
170 | | - { param: :user, operator: operator.presence || '=', user_id: val } |
171 | | - when 'upvotes' |
172 | | - next unless value.match?(valid_value[:numeric]) |
173 | | - |
174 | | - operator, val = numeric_value_sql value |
175 | | - { param: :upvotes, operator: operator.presence || '=', value: val.to_i } |
176 | | - when 'downvotes' |
177 | | - next unless value.match?(valid_value[:numeric]) |
178 | | - |
179 | | - operator, val = numeric_value_sql value |
180 | | - { param: :downvotes, operator: operator.presence || '=', value: val.to_i } |
181 | | - when 'votes' |
182 | | - next unless value.match?(valid_value[:numeric]) |
183 | | - |
184 | | - operator, val = numeric_value_sql value |
185 | | - { param: :net_votes, operator: operator.presence || '=', value: val.to_i } |
186 | | - when 'tag' |
187 | | - { param: :include_tag, tag_id: Tag.where(name: value).select(:id) } |
188 | | - when '-tag' |
189 | | - { param: :exclude_tag, tag_id: Tag.where(name: value).select(:id) } |
190 | | - when 'category' |
191 | | - next unless value.match?(valid_value[:numeric]) |
192 | | - |
193 | | - operator, val = numeric_value_sql value |
194 | | - { param: :category, operator: operator.presence || '=', category_id: val.to_i } |
195 | | - when 'post_type' |
196 | | - next unless value.match?(valid_value[:numeric]) |
197 | | - |
198 | | - operator, val = numeric_value_sql value |
199 | | - { param: :post_type, operator: operator.presence || '=', post_type_id: val.to_i } |
200 | | - when 'answers' |
201 | | - next unless value.match?(valid_value[:numeric]) |
202 | | - |
203 | | - operator, val = numeric_value_sql value |
204 | | - { param: :answers, operator: operator.presence || '=', value: val.to_i } |
205 | | - when 'status' |
206 | | - next unless value.match?(valid_value[:status]) |
207 | | - |
208 | | - { param: :status, value: value } |
209 | | - end |
| 144 | + parsed = case parameter |
| 145 | + when 'score' |
| 146 | + parse_score_qualifier(value) |
| 147 | + when 'created' |
| 148 | + parse_created_qualifier(value) |
| 149 | + when 'user' |
| 150 | + parse_user_qualifier(value) |
| 151 | + when 'upvotes' |
| 152 | + parse_upvotes_qualifier(value) |
| 153 | + when 'downvotes' |
| 154 | + parse_downvotes_qualifier(value) |
| 155 | + when 'votes' |
| 156 | + parse_votes_qualifier(value) |
| 157 | + when 'tag' |
| 158 | + parse_include_tag_qualifier(value) |
| 159 | + when '-tag' |
| 160 | + parse_exclude_tag_qualifier(value) |
| 161 | + when 'category' |
| 162 | + parse_category_qualifier(value) |
| 163 | + when 'post_type' |
| 164 | + parse_post_type_qualifier(value) |
| 165 | + when 'answers' |
| 166 | + parse_answers_qualifier(value) |
| 167 | + when 'status' |
| 168 | + parse_status_qualifier(value) |
| 169 | + end |
| 170 | + |
| 171 | + parsed |
210 | 172 | end.compact |
211 | | - # Consider partitioning and telling the user which filters were invalid |
| 173 | + # Consider telling the user which filters were invalid |
212 | 174 | end |
213 | 175 |
|
214 | 176 | ## |
@@ -266,49 +228,4 @@ def qualifiers_to_sql(qualifiers, query, user) |
266 | 228 |
|
267 | 229 | query |
268 | 230 | end |
269 | | - # rubocop:enable Metrics/CyclomaticComplexity |
270 | | - |
271 | | - ## |
272 | | - # Parses a qualifier value string, including operator, as a numeric value. |
273 | | - # @param value [String] The value part of the qualifier, i.e. +">=10"+ |
274 | | - # @return [Array(String, String)] A 2-tuple containing operator and value. |
275 | | - # @api private |
276 | | - def numeric_value_sql(value) |
277 | | - operator = '' |
278 | | - while ['<', '>', '='].include? value[0] |
279 | | - operator += value[0] |
280 | | - value = value[1..-1] |
281 | | - end |
282 | | - |
283 | | - # whatever's left after stripping operator is the number |
284 | | - # validated by regex in qualifiers_to_sql |
285 | | - [operator, value] |
286 | | - end |
287 | | - |
288 | | - ## |
289 | | - # Parses a qualifier value string, including operator, as a date value. |
290 | | - # @param value [String] The value part of the qualifier, i.e. +">=10d"+ |
291 | | - # @return [Array(String, String, String)] A 3-tuple containing operator, value, and timeframe. |
292 | | - # @api private |
293 | | - def date_value_sql(value) |
294 | | - operator = '' |
295 | | - |
296 | | - while ['<', '>', '='].include? value[0] |
297 | | - operator += value[0] |
298 | | - value = value[1..-1] |
299 | | - end |
300 | | - |
301 | | - # working with dates: <1y ('less than one year ago') is SQL: > 1y ago |
302 | | - operator = { '<' => '>', '>' => '<', '<=' => '>=', '>=' => '<=' }[operator] || '' |
303 | | - |
304 | | - val = '' |
305 | | - while value[0] =~ /[[:digit:]]/ |
306 | | - val += value[0] |
307 | | - value = value[1..-1] |
308 | | - end |
309 | | - |
310 | | - timeframe = { s: 'SECOND', m: 'MINUTE', h: 'HOUR', d: 'DAY', w: 'WEEK', mo: 'MONTH', y: 'YEAR' }[value.to_sym] |
311 | | - |
312 | | - [operator, val, timeframe || 'MONTH'] |
313 | | - end |
314 | 231 | end |
0 commit comments