query_helper 0.2.7 → 0.2.12

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: 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