query_helper 0.2.7 → 0.2.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34196dda5d9ed84de34c317c6f9096a87e9b403ca37868f5f087ef565886fe8d
4
- data.tar.gz: e036203e497d95e1d37ceddd53ec72a3cb794ac3c6675842dfae642e0d9db9ac
3
+ metadata.gz: d785c033c2c9b9f1eaa01641b8e92b8690a1a54eceb1507e58efb4a4437655ab
4
+ data.tar.gz: de0529d9069f0c612b39873c69160eff8eeb52b35bcc05401026cc161b9914c9
5
5
  SHA512:
6
- metadata.gz: 71590ca9d1f926b868d44f6170390d6a795dcab47f17dae1fbc7aed8e010d85d095e7322c5e1fbfe491ef614a2d9abf2863ce67baf57ab013f8d4faac7db823f
7
- data.tar.gz: 3efc246697287100945bd1c247df76ca0db2c5d04df4c44fb711560de9245c5daabe5d73f8a3c9dc4d6c0edf748f8e29b065ad3d30816ddccde0205dcee9c6c2
6
+ metadata.gz: 39e7d8268cde0434747bfb2cc52e0f85c6d294ba18af86b5a415f5c92da2f1dfbe7822dbdc685c55f99520b15e205e2a75867db6e628b5d594730a1b472990ca
7
+ data.tar.gz: efcb54e2da3b21a3c454ff490b2c892336913dde41602aa07b31edf658f4644ebcc4f1a234bff8b72706ebd8fcfc7366de24c1a88891d1a3176d72686cdceb7e
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- query_helper (0.2.7)
4
+ query_helper (0.2.12)
5
5
  activerecord (> 5)
6
6
  activesupport (> 5)
7
7
 
data/README.md CHANGED
@@ -111,6 +111,33 @@ null | is null *or* is not null
111
111
 
112
112
  Note: For the null operator code, toggle *is null* operator with true and *is not null* operator with false
113
113
 
114
+ #### Search
115
+
116
+ QueryHelper supports searching across multiple fields. To implement pass an array of column aliases into the `search_fields` argument when creating or updating a `QueryHelper` object.
117
+
118
+ ```ruby
119
+ @query_helper.update(search_fields: ["column1", "column2"])
120
+ render json: @query_helper.results()
121
+ ```
122
+
123
+ You can then take advantage of the `search_for` url param to do text matching in any of the columns included
124
+
125
+ Request: `http://www.example.com/resources?search_for=foo`
126
+
127
+ Results:
128
+ ```json
129
+ [
130
+ {
131
+ "column1": "foobar",
132
+ "column2": "bar"
133
+ },
134
+ {
135
+ "column1": "bar",
136
+ "column2": "barfoo"
137
+ }
138
+ ]
139
+ ```
140
+
114
141
  #### Associations
115
142
 
116
143
  Include ActiveRecord associations in the payload. The association must be defined in the model.
@@ -13,7 +13,7 @@ require "query_helper/invalid_query_error"
13
13
 
14
14
  class QueryHelper
15
15
 
16
- attr_accessor :model, :bind_variables, :sql_filter, :sql_sort, :page, :per_page, :single_record, :associations, :as_json_options, :executed_query, :api_payload, :preload
16
+ attr_accessor :model, :bind_variables, :sql_filter, :sql_sort, :page, :per_page, :single_record, :associations, :as_json_options, :executed_query, :api_payload, :preload, :search_field, :search_string, :metadata
17
17
  attr_reader :query
18
18
 
19
19
  def initialize(
@@ -29,7 +29,10 @@ class QueryHelper
29
29
  as_json_options: nil, # a list of as_json options you'd like run before returning the payload
30
30
  custom_mappings: {}, # custom keyword => sql_expression mappings
31
31
  api_payload: false, # Return the paginated payload or simply return the result array
32
- preload: [] # preload activerecord associations - used instead of `associations` when you don't want them included in the payload
32
+ preload: [], # preload activerecord associations - used instead of `associations` when you don't want them included in the payload
33
+ search_fields: [],
34
+ search_string: nil,
35
+ metadata: {}
33
36
  )
34
37
  @query = query.class < ActiveRecord::Relation ? query.to_sql : query
35
38
  @model = query.class < ActiveRecord::Relation ? query.base_class : model
@@ -38,21 +41,16 @@ class QueryHelper
38
41
  @sql_sort = sql_sort
39
42
  @page = determine_page(page: page, per_page: per_page)
40
43
  @per_page = determine_per_page(page: page, per_page: per_page)
44
+ set_limit_and_offset()
41
45
  @single_record = single_record
42
46
  @associations = associations
43
47
  @as_json_options = as_json_options
44
48
  @custom_mappings = custom_mappings
45
49
  @api_payload = api_payload
46
50
  @preload = preload
47
-
48
- if @page && @per_page
49
- # Determine limit and offset
50
- limit = @per_page
51
- offset = (@page - 1) * @per_page
52
-
53
- # Merge limit/offset variables into bind_variables
54
- @bind_variables.merge!({limit: limit, offset: offset})
55
- end
51
+ @search_fields = search_fields
52
+ @search_string = search_string
53
+ @metadata = metadata
56
54
  end
57
55
 
58
56
  def update(
@@ -64,7 +62,14 @@ class QueryHelper
64
62
  as_json_options: nil,
65
63
  single_record: nil,
66
64
  custom_mappings: nil,
67
- preload: []
65
+ preload: [],
66
+ search_fields: nil,
67
+ sql_filter: nil,
68
+ sql_sort: nil,
69
+ page: nil,
70
+ per_page: nil,
71
+ search_string: nil,
72
+ metadata: nil
68
73
  )
69
74
  @query = query.class < ActiveRecord::Relation ? query.to_sql : query if query
70
75
  @model = query.class < ActiveRecord::Relation ? query.base_class : model if model || query
@@ -75,6 +80,14 @@ class QueryHelper
75
80
  @as_json_options = as_json_options if as_json_options
76
81
  @custom_mappings = custom_mappings if custom_mappings
77
82
  @preload = preload if preload
83
+ @search_fields = search_fields if search_fields
84
+ @sql_filter = sql_filter if sql_filter
85
+ @sql_sort = sql_sort if sql_sort
86
+ @search_string = search_string if search_string
87
+ @page = determine_page(page: page, per_page: per_page) if page
88
+ @per_page = determine_per_page(page: page, per_page: per_page) if per_page
89
+ @metadata = metadata if metadata
90
+ set_limit_and_offset()
78
91
  return self
79
92
  end
80
93
 
@@ -102,14 +115,27 @@ class QueryHelper
102
115
  # create the filters from the column maps
103
116
  @sql_filter.create_filters()
104
117
 
118
+ having_clauses = @sql_filter.having_clauses
119
+ where_clauses = @sql_filter.where_clauses
120
+
121
+ if @search_string
122
+ search_filter = search_filter(column_maps)
123
+ if search_filter[:placement] == :where
124
+ where_clauses << search_filter[:filter]
125
+ else
126
+ having_clauses << search_filter[:filter]
127
+ end
128
+ end
129
+
130
+
105
131
  # merge the filter bind variables into the query bind variables
106
132
  @bind_variables.merge!(@sql_filter.bind_variables)
107
-
133
+
108
134
  # Execute Sql Query
109
135
  manipulator = SqlManipulator.new(
110
136
  sql: @query,
111
- where_clauses: @sql_filter.where_clauses,
112
- having_clauses: @sql_filter.having_clauses,
137
+ where_clauses: where_clauses,
138
+ having_clauses: having_clauses,
113
139
  order_by_clauses: @sql_sort.parse_sort_string,
114
140
  include_limit_clause: @page && @per_page ? true : false,
115
141
  additional_select_clauses: @sql_sort.select_strings
@@ -167,9 +193,22 @@ class QueryHelper
167
193
  return nil
168
194
  end
169
195
 
196
+ def set_limit_and_offset
197
+ if @page && @per_page
198
+ # Determine limit and offset
199
+ limit = @per_page
200
+ offset = (@page - 1) * @per_page
201
+
202
+ # Merge limit/offset variables into bind_variables
203
+ @bind_variables[:limit] = limit
204
+ @bind_variables[:offset] = offset
205
+ end
206
+ end
207
+
170
208
  def paginated_results
171
209
  { pagination: pagination_results(),
172
- data: @results }
210
+ data: @results,
211
+ metadata: @metadata }
173
212
  end
174
213
 
175
214
  def determine_count
@@ -202,22 +241,22 @@ class QueryHelper
202
241
 
203
242
  def pagination_results
204
243
  # Set pagination params if they aren't provided
205
- @per_page = @count unless @per_page
206
- @page = 1 unless @page
244
+ results_per_page = @per_page || @count
245
+ results_page = @page || 1
207
246
 
208
- total_pages = (@count/(@per_page.nonzero? || 1).to_f).ceil
209
- next_page = @page + 1 if @page.between?(1, total_pages - 1)
210
- previous_page = @page - 1 if @page.between?(2, total_pages)
211
- first_page = @page == 1
212
- last_page = @page == total_pages
213
- out_of_range = !@page.between?(1,total_pages)
247
+ total_pages = (@count/(results_per_page.nonzero? || 1).to_f).ceil
248
+ next_page = results_page + 1 if results_page.between?(1, total_pages - 1)
249
+ previous_page = results_page - 1 if results_page.between?(2, total_pages)
250
+ first_page = results_page == 1
251
+ last_page = results_page == total_pages
252
+ out_of_range = !results_page.between?(1,total_pages)
214
253
 
215
254
  { count: @count,
216
- current_page: @page,
255
+ current_page: results_page,
217
256
  next_page: next_page,
218
257
  previous_page: previous_page,
219
258
  total_pages: total_pages,
220
- per_page: @per_page,
259
+ per_page: results_per_page,
221
260
  first_page: first_page,
222
261
  last_page: last_page,
223
262
  out_of_range: out_of_range }
@@ -230,4 +269,20 @@ class QueryHelper
230
269
  model: @model
231
270
  )
232
271
  end
272
+
273
+ def search_filter(column_maps)
274
+ raise ArgumentError.new("search_fields not defined") unless @search_fields.length > 0
275
+ placement = :where
276
+ maps = column_maps.select do |cm|
277
+ placement = :having if cm.aggregate
278
+ @search_fields.include? cm.alias_name
279
+ end
280
+ bind_variable = ('a'..'z').to_a.shuffle[0,20].join.to_sym
281
+ @bind_variables[bind_variable] = "%#{@search_string}%"
282
+ filter = "#{maps.map{|m| "#{m.sql_expression}::varchar"}.join(" || ")} ilike :#{bind_variable}"
283
+ return {
284
+ filter: filter,
285
+ placement: placement
286
+ }
287
+ end
233
288
  end
@@ -9,10 +9,22 @@ class QueryHelper
9
9
  @query_helper
10
10
  end
11
11
 
12
+ def query_helper_with_no_pagination
13
+ QueryHelper.new(**query_helper_params_no_pagination)
14
+ end
15
+
12
16
  def create_query_helper
13
17
  @query_helper = QueryHelper.new(**query_helper_params, api_payload: true)
14
18
  end
15
19
 
20
+ def create_query_helper_with_no_pagination
21
+ @query_helper = query_helper_with_no_pagination()
22
+ end
23
+
24
+ def reload_query_params(query_helper=@query_helper)
25
+ query_helper.update(**query_helper_params)
26
+ end
27
+
16
28
  def create_query_helper_filter
17
29
  filter_values = params[:filter].permit!.to_h
18
30
  QueryHelper::SqlFilter.new(filter_values: filter_values)
@@ -27,12 +39,18 @@ class QueryHelper
27
39
  end
28
40
 
29
41
  def query_helper_params
30
- helpers = {}
42
+ helpers = query_helper_params_no_pagination
31
43
  helpers[:page] = params[:page] if params[:page]
32
44
  helpers[:per_page] = params[:per_page] if params[:per_page]
45
+ helpers
46
+ end
47
+
48
+ def query_helper_params_no_pagination
49
+ helpers = {}
33
50
  helpers[:sql_filter] = create_query_helper_filter() if params[:filter]
34
51
  helpers[:sql_sort] = create_query_helper_sort() if params[:sort]
35
52
  helpers[:associations] = create_query_helper_associations() if params[:include]
53
+ helpers[:search_string] = params[:search_for] if params[:search_for]
36
54
  helpers
37
55
  end
38
56
  end
@@ -1,3 +1,3 @@
1
1
  class QueryHelper
2
- VERSION = "0.2.7"
2
+ VERSION = "0.2.12"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: query_helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan McDaniel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-31 00:00:00.000000000 Z
11
+ date: 2020-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler