rad_core_rails 0.7.4 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9e0668296a4c9eaf8a2ee096c59affeb7b72a95174ed1e15716f250ee08a083
4
- data.tar.gz: 91a4ceb121b1439519e451ca319357954bd62782c981752643def0cc7a9f4887
3
+ metadata.gz: '014856ac16f8d40063feb80c47e97120f02ddcf2f8a6717fad3472aefb6c0e4b'
4
+ data.tar.gz: d0ec03250fb3b8b868ce3694b3d029b86469563d9fede11fb8b34b690ea2fef5
5
5
  SHA512:
6
- metadata.gz: 9251d1a8bc39a8cefb863f0d6ba26d88e0059bc04cb2bdd14a53ee897a7f53ee85f4400d188433e0b8dba3266bf09caa7c6246c4354aa6df72c32a00d00c88db
7
- data.tar.gz: fbe6961987af27557a37113c2a03977b28fa3df008ed921a663ad32ba586920e935cc6ddb409b06d43155f9ebbbad244fdc181bf908937142f85bb94ba9cd201
6
+ metadata.gz: 410ed03d6ddd007f220ce1ceeeea8cedc1a7df95b044d8417ed7d11a00579b8eb980befc9fc2fc81dde7131502dcba08bb1d462bb50a0fe34cf577be9e606a27
7
+ data.tar.gz: 4a1fe8b16e4bda9f0631624cd769d67610a67efbd6c59e012c0c68b13f8b50496fbc8e5e08a3a6c69a5280537bf30f77a0cd55064537253224950e577c587a02
@@ -24,15 +24,16 @@ module RadCoreRails
24
24
  @filter_manifest || {}.with_indifferent_access
25
25
  end
26
26
 
27
- def create_filters(search, filters)
27
+ def create_filters(filters)
28
28
  query = []
29
29
  args = []
30
- clause, arguments = generate_search_clause(search)
31
- query << clause
32
- arguments.each do |arg|
33
- args << arg
34
- end
35
- filters.map do |filter|
30
+ # clause, arguments = generate_search_clause(search)
31
+ # query << clause
32
+ # arguments.each do |arg|
33
+ # args << arg
34
+ # end
35
+ filters.map do |raw_filter|
36
+ filter = raw_filter.with_indifferent_access
36
37
  begin
37
38
  clause, arguments = filter_manifest[filter[:key]].call(filter)
38
39
  query << clause
@@ -46,92 +47,126 @@ module RadCoreRails
46
47
  [query.reject(&:blank?).join(' AND '), args]
47
48
  end
48
49
 
49
- # def generate_search_clause(search)
50
- # and_args = []
51
- # or_args = []
52
- # if search.present? && searchable_columns.is_a?(Array)
53
- # # search_term_size = search.split(' ').length
54
- # and_terms = search.split(' ').select { |term| !term.include?('+') }
55
- # or_terms = search.split(' ').select { |term| term.include?('+') }
56
- # and_columns = []
57
- # or_columns = []
58
- # # just_ors = search_term_size == or_term_size
59
- # # operand = just_ors ? 'OR' : 'AND'
60
- # # search_terms = just_ors == true ? search.split(' ') : search.split(' ').select { |term| !term.include?('+') }
61
- # and_terms.each do |term|
62
- # columns = []
63
- # and_terms.each do |col|
64
- # and_columns.push("(LOWER(#{col}) ILIKE ?)")
65
- # and_args.push '%' + term.downcase.strip + '%'
66
- # end
67
- # or_terms.each do |col|
68
- # columns.push("(LOWER(#{col}) ILIKE ?)")
69
- # or_args.push '%' + term[1, term.length].downcase.strip + '%'
70
- # end
71
- # clause = if or_columns.empty?
72
- # '(' + and_columns.join(' OR ') + ')'
73
- # else
74
- # '(' + '(' + and_columns.join(' OR ') + ')' + 'AND' + '(' + or_columns.join(' OR ') + ')' + ')'
75
- # end
76
- # end
77
- # [clause, and_args + or_args]
78
- # else
79
- # ['', []]
80
- # end
81
- # end
82
-
83
- # @searchable_columns, is an array of column names that you can compare to your terms.
84
- #
85
- def generate_search_clause(search)
50
+ def generate_search_clause(filter)
51
+ search = filter[:values][0]
52
+ search_clause = ['', []]
53
+
86
54
  if search.present? && searchable_columns.is_a?(Array)
87
- # holds all of the sql from sanitized_and_terms
88
- and_args = []
89
- # holds all the table columns sql for all the AND terms
90
- and_clause = []
91
- # holds all of the sql from sanitized_or_terms
92
- or_args = []
93
- # holds all the table columns sql for all the OR terms
94
- or_clause = []
95
- # extract and terms, remove casing, and add ILIKE '%' comparisions
55
+ and_args = [] # SQL from sanitized_and_terms
56
+ excluded_args = [] # SQL from sanitized_excluded_terms
57
+ and_clause = [] # table columns SQL for all the AND terms
58
+ excluded_clause = [] # table columns SQL for all the AND NOT terms
59
+ or_args = [] # SQL from sanitized_or_terms
60
+ or_clause = [] # table columns SQL for all the OR terms
61
+
62
+ phrases_or = search.scan(/\+"([^"]*)"/) # e.g. +"Phrase for OR"
63
+ # remove 'or' phrases from search if any
64
+ phrases_or.each { |phrase| search.gsub!('+"' + phrase.first.to_s + '"', '') } if phrases_or.any?
65
+
66
+ phrases_to_exclude = search.scan(/-"([^"]*)"/) # e.g. -"Phrase to exclude"
67
+ # remove excluded phrases from search if any
68
+ if phrases_to_exclude.any?
69
+ phrases_to_exclude.each { |phrase| search.gsub!('-"' + phrase.first.to_s + '"', '') }
70
+ end
71
+
72
+ phrases_and = search.scan(/"([^"]*)"/) # e.g. "Phrase for AND"
73
+ # remove 'and' phrases from search if any
74
+ phrases_and.each { |phrase| search.gsub!('"' + phrase.first.to_s + '"', '') } if phrases_and.any?
75
+
76
+ # extract 'and' terms, remove casing, and add ILIKE '%' comparisons
96
77
  sanitized_and_terms = search.split(' ')
97
- .reject { |term| term.include?('+') }
78
+ .reject { |term| term.include?('+') || term.include?('-') }
98
79
  .map { |term| '%' + term.downcase.strip + '%' }
99
- # extract or terms, remove casing, and add ILIKE '%' comparisions
80
+ # add 'and' phrase terms, remove casing, and add ILIKE '%' comparisons
81
+ if phrases_and.any?
82
+ sanitized_and_terms += phrases_and.flatten.map { |phrase| '%' + phrase.downcase.strip + '%' }
83
+ end
84
+
85
+ # extract 'or' terms, remove casing, and add ILIKE '%' comparisons
100
86
  sanitized_or_terms = search.split(' ')
101
87
  .select { |term| term.include?('+') }
102
88
  .map { |term| '%' + term[1, term.length].downcase.strip + '%' }
89
+
90
+ # add 'or' phrase terms, remove casing, and add ILIKE '%' comparisons
91
+ sanitized_or_terms += phrases_or.flatten.map { |phrase| '%' + phrase.downcase.strip + '%' } if phrases_or.any?
92
+
93
+ # extract excluded terms, remove casing, and add NOT ILIKE '%' comparisons
94
+ sanitized_excluded_terms = search.split(' ')
95
+ .select { |term| term.include?('-') }
96
+ .map { |term| '%' + term[1, term.length].downcase.strip + '%' }
97
+
98
+ # add excluded phrase terms, remove casing, and add NOT ILIKE '%' comparisons
99
+ if phrases_to_exclude.any?
100
+ sanitized_excluded_terms += phrases_to_exclude.flatten
101
+ .map { |phrase| '%' + phrase.downcase.strip + '%' }
102
+ end
103
+
103
104
  # loop through sanitized_and_terms to find all possible columns.
104
105
  sanitized_and_terms.each do |sanitized_term|
105
106
  columns = []
106
107
  # all possible columns where this should be searched
107
108
  searchable_columns.each do |col|
108
- columns.push("(LOWER(#{col}) ILIKE ?)")
109
+ columns.push("(COALESCE(LOWER(#{col}), '') ILIKE ?)")
109
110
  and_args.push sanitized_term
110
111
  end
111
112
  and_clause.push '(' + columns.join(' OR ') + ')'
112
113
  end
114
+ # loop through sanitized_excluded_terms to find all possible columns.
115
+ sanitized_excluded_terms.each do |sanitized_term|
116
+ columns = []
117
+ # all possible columns where this should be searched
118
+ searchable_columns.each do |col|
119
+ columns.push("(COALESCE(LOWER(#{col}), '') NOT ILIKE ?)")
120
+ excluded_args.push sanitized_term
121
+ end
122
+ excluded_clause.push '(' + columns.join(' AND ') + ')'
123
+ end
113
124
  # loop through sanitized_or_terms to find all possible columns.
114
125
  sanitized_or_terms.each do |sanitized_term|
115
126
  columns = []
116
127
  # all possible columns where this should be searched
117
128
  searchable_columns.each do |col|
118
- columns.push("(LOWER(#{col}) ILIKE ?)")
129
+ columns.push("(COALESCE(LOWER(#{col}), '') ILIKE ?)")
119
130
  or_args.push sanitized_term
120
131
  end
121
132
  or_clause.push '(' + columns.join(' OR ') + ')'
122
133
  end
123
- if or_clause.empty? && and_clause.empty?
124
- ['', []]
125
- elsif or_clause.empty?
126
- ['(' + and_clause.join(' AND ') + ')', and_args]
127
- elsif and_clause.empty?
128
- ['(' + or_clause.join(' OR ') + ')', or_args]
129
- else
130
- ['((' + and_clause.join(' AND ') + ') AND (' + or_clause.join(' OR ') + '))', and_args + or_args]
134
+
135
+ return ['', []] if or_clause.empty? && and_clause.empty? && excluded_clause.empty?
136
+
137
+ return ['(' + and_clause.join(' AND ') + ')', and_args] if or_clause.empty? && excluded_clause.empty?
138
+
139
+ return ['(' + or_clause.join(' OR ') + ')', or_args] if and_clause.empty? && excluded_clause.empty?
140
+
141
+ return ['(' + excluded_clause.join(' AND ') + ')', excluded_args] if or_clause.empty? && and_clause.empty?
142
+
143
+ if or_clause.empty?
144
+ return ['((' + and_clause.join(' AND ') + ') AND (' + excluded_clause.join(' AND ') + '))',
145
+ and_args + excluded_args]
131
146
  end
132
- else
133
- ['', []]
147
+
148
+ if and_clause.empty?
149
+ return ['((' + or_clause.join(' OR ') + ') AND (' + excluded_clause.join(' AND ') + '))',
150
+ or_args + excluded_args]
151
+ end
152
+
153
+ if excluded_clause.empty?
154
+ return ['((' + and_clause.join(' AND ') + ') AND (' + or_clause.join(' OR ') + '))', and_args + or_args]
155
+ end
156
+
157
+ search_clause = [
158
+ '((' +
159
+ and_clause.join(' AND ') +
160
+ ') AND (' +
161
+ or_clause.join(' OR ') +
162
+ ') AND (' +
163
+ excluded_clause.join(' AND ') +
164
+ '))',
165
+ and_args + or_args + excluded_args
166
+ ]
134
167
  end
168
+
169
+ search_clause
135
170
  end
136
171
 
137
172
  # Generate Boolean clause
@@ -156,6 +191,77 @@ module RadCoreRails
156
191
  [str, args]
157
192
  end
158
193
 
194
+ def sanitize_vector_string(search)
195
+ phrases_or = search.scan(/\+"([^"]*)"/) # e.g. +"Phrase for OR"
196
+ # remove 'or' phrases from search if any
197
+ phrases_or.each { |phrase| search.gsub!('+"' + phrase.first.to_s + '"', '') } if phrases_or.any?
198
+
199
+ phrases_to_exclude = search.scan(/-"([^"]*)"/) # e.g. -"Phrase to exclude"
200
+ # remove excluded phrases from search if any
201
+ phrases_to_exclude.each { |phrase| search.gsub!('-"' + phrase.first.to_s + '"', '') } if phrases_to_exclude.any?
202
+
203
+ phrases_and = search.scan(/"([^"]*)"/) # e.g. "Phrase for AND"
204
+ # remove 'and' phrases from search if any
205
+ phrases_and.each { |phrase| search.gsub!('"' + phrase.first.to_s + '"', '') } if phrases_and.any?
206
+
207
+ sanitized_and_terms = search.split(' ')
208
+ .reject { |term| term.include?('+') || term.include?('-') }
209
+ .map { |term| term.downcase.strip + ':*' }
210
+ .reject { |t| t.blank? }
211
+
212
+ sanitized_or_terms = search.split(' ')
213
+ .select { |term| term.include?('+') }
214
+ .map { |term| term[1, term.length].downcase + ':*' }
215
+ .reject { |t| t.blank? }
216
+
217
+ sanitized_excluded_terms = search.split(' ')
218
+ .select { |term| term.include?('-') }
219
+ .map { |term| term[1, term.length].downcase.strip + ':*' }
220
+ .reject { |t| t.blank? }
221
+
222
+ and_clause = sanitized_and_terms.join(' & ')
223
+
224
+ or_clause = sanitized_or_terms.join(' | ')
225
+
226
+ excluded_clause = sanitized_excluded_terms.map { |t| "!#{t}" }.join(' & ')
227
+
228
+ # puts '------'
229
+ # puts '------'
230
+ # puts '------'
231
+ # puts and_clause.inspect
232
+ # puts or_clause.inspect
233
+ # puts excluded_clause.inspect
234
+ # puts '------'
235
+ # puts '------'
236
+
237
+ if and_clause.present? && or_clause.empty? && excluded_clause.empty?
238
+ and_clause
239
+ elsif and_clause.empty? && or_clause.present? && excluded_clause.empty?
240
+ or_clause
241
+ elsif and_clause.empty? && or_clause.empty? && excluded_clause.present?
242
+ excluded_clause
243
+ elsif and_clause.present? && or_clause.present? && excluded_clause.empty?
244
+ "(#{and_clause}) & (#{or_clause})"
245
+ elsif and_clause.present? && or_clause.empty? && excluded_clause.present?
246
+ "(#{and_clause}) & (#{excluded_clause})"
247
+ elsif and_clause.empty? && or_clause.present? && excluded_clause.present?
248
+ "(#{or_clause}) & (#{excluded_clause})"
249
+ elsif and_clause.present? && or_clause.present? && excluded_clause.present?
250
+ "(#{and_clause}) & (#{or_clause}) & (#{excluded_clause})"
251
+ else
252
+ raise StandardError, 'Combination not available.'
253
+ end
254
+ end
255
+
256
+ def generate_vector_clause(column_name, filter)
257
+ return ['', []] if filter[:values][0].blank?
258
+
259
+ vector_string = sanitize_vector_string(filter[:values][0])
260
+
261
+ query = "(#{column_name} @@ to_tsquery('simple', ?))"
262
+ [query, [vector_string]]
263
+ end
264
+
159
265
  def generate_zip_codes_clause(column_name, filter)
160
266
  str = "(#{column_name} = ANY(#{zip_code_class.distance_query}))"
161
267
  args = zip_code_class.distance_args(filter)
@@ -165,10 +271,10 @@ module RadCoreRails
165
271
 
166
272
  def generate_array_clause(column_name, filter)
167
273
  if filter[:option] == '!='
168
- str = "(SELECT NOT(#{column_name}::text[] && ARRAY[?]))"
274
+ str = "(SELECT NOT(#{column_name}::text[] && ARRAY[?]::text[]))"
169
275
  args = [filter[:values]]
170
276
  else
171
- str = "(SELECT (#{column_name}::text[] && ARRAY[?]))"
277
+ str = "(SELECT (#{column_name}::text[] && ARRAY[?]::text[]))"
172
278
  args = [filter[:values]]
173
279
  end
174
280
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RadCoreRails
4
- VERSION = '0.7.4'
4
+ VERSION = '0.8.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rad_core_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.4
4
+ version: 0.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleksandr Poltavets, James Marrs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-13 00:00:00.000000000 Z
11
+ date: 2021-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport