datagrid 1.8.1 → 2.0.0.pre.alpha

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -7
  3. data/{Readme.markdown → README.md} +46 -29
  4. data/app/assets/stylesheets/datagrid.css +145 -0
  5. data/app/views/datagrid/_enum_checkboxes.html.erb +5 -3
  6. data/app/views/datagrid/_form.html.erb +4 -5
  7. data/app/views/datagrid/_head.html.erb +26 -3
  8. data/app/views/datagrid/_range_filter.html.erb +5 -3
  9. data/app/views/datagrid/_row.html.erb +12 -1
  10. data/app/views/datagrid/_table.html.erb +4 -4
  11. data/datagrid.gemspec +8 -8
  12. data/lib/datagrid/active_model.rb +9 -17
  13. data/lib/datagrid/base.rb +39 -0
  14. data/lib/datagrid/column_names_attribute.rb +12 -12
  15. data/lib/datagrid/columns/column.rb +155 -133
  16. data/lib/datagrid/columns.rb +495 -282
  17. data/lib/datagrid/configuration.rb +23 -10
  18. data/lib/datagrid/core.rb +184 -150
  19. data/lib/datagrid/deprecated_object.rb +20 -0
  20. data/lib/datagrid/drivers/abstract_driver.rb +13 -25
  21. data/lib/datagrid/drivers/active_record.rb +24 -26
  22. data/lib/datagrid/drivers/array.rb +26 -17
  23. data/lib/datagrid/drivers/mongo_mapper.rb +15 -14
  24. data/lib/datagrid/drivers/mongoid.rb +16 -18
  25. data/lib/datagrid/drivers/sequel.rb +14 -19
  26. data/lib/datagrid/drivers.rb +2 -1
  27. data/lib/datagrid/engine.rb +11 -3
  28. data/lib/datagrid/filters/base_filter.rb +166 -142
  29. data/lib/datagrid/filters/boolean_filter.rb +19 -5
  30. data/lib/datagrid/filters/date_filter.rb +33 -35
  31. data/lib/datagrid/filters/date_time_filter.rb +24 -16
  32. data/lib/datagrid/filters/default_filter.rb +9 -3
  33. data/lib/datagrid/filters/dynamic_filter.rb +151 -105
  34. data/lib/datagrid/filters/enum_filter.rb +43 -19
  35. data/lib/datagrid/filters/extended_boolean_filter.rb +39 -27
  36. data/lib/datagrid/filters/float_filter.rb +16 -5
  37. data/lib/datagrid/filters/integer_filter.rb +21 -10
  38. data/lib/datagrid/filters/ranged_filter.rb +66 -45
  39. data/lib/datagrid/filters/select_options.rb +58 -49
  40. data/lib/datagrid/filters/string_filter.rb +9 -4
  41. data/lib/datagrid/filters.rb +234 -106
  42. data/lib/datagrid/form_builder.rb +116 -128
  43. data/lib/datagrid/generators/scaffold.rb +185 -0
  44. data/lib/datagrid/generators/views.rb +20 -0
  45. data/lib/datagrid/helper.rb +397 -22
  46. data/lib/datagrid/ordering.rb +81 -87
  47. data/lib/datagrid/rspec.rb +8 -12
  48. data/lib/datagrid/utils.rb +42 -38
  49. data/lib/datagrid/version.rb +3 -1
  50. data/lib/datagrid.rb +18 -28
  51. data/templates/base.rb.erb +33 -7
  52. data/templates/grid.rb.erb +1 -1
  53. metadata +18 -19
  54. data/app/assets/stylesheets/datagrid.sass +0 -134
  55. data/lib/datagrid/filters/composite_filters.rb +0 -49
  56. data/lib/datagrid/renderer.rb +0 -157
  57. data/lib/datagrid/scaffold.rb +0 -129
  58. data/lib/tasks/datagrid_tasks.rake +0 -15
  59. data/templates/controller.rb.erb +0 -6
  60. data/templates/index.html.erb +0 -5
@@ -1,14 +1,27 @@
1
- module Datagrid
2
-
3
- def self.configuration
4
- @configuration ||= Configuration.new
5
- end
1
+ # frozen_string_literal: true
6
2
 
7
- def self.configure
8
- yield(configuration)
9
- end
10
-
11
- # Datagrid configuration object
3
+ module Datagrid
4
+ # ## Configuration
5
+ #
6
+ # Datagrid provides several configuration options.
7
+ #
8
+ # Here is the API reference and a description of the available options:
9
+ #
10
+ # ``` ruby
11
+ # Datagrid.configure do |config|
12
+ # # Defines date formats that can be used to parse dates.
13
+ # # Note: Multiple formats can be specified. The first format is used to format dates as strings,
14
+ # # while other formats are used only for parsing dates from strings (e.g., if your app supports multiple formats).
15
+ # config.date_formats = ["%m/%d/%Y", "%Y-%m-%d"]
16
+ #
17
+ # # Defines timestamp formats that can be used to parse timestamps.
18
+ # # Note: Multiple formats can be specified. The first format is used to format timestamps as strings,
19
+ # # while other formats are used only for parsing timestamps from strings (e.g., if your app supports multiple formats).
20
+ # config.datetime_formats = ["%m/%d/%Y %h:%M", "%Y-%m-%d %h:%M:%s"]
21
+ # end
22
+ # ```
23
+ #
24
+ # These options can be set globally in your application to customize Datagrid’s behavior.
12
25
  class Configuration
13
26
  # @return [Array<String>] Date parsing formats
14
27
  attr_accessor :date_formats
data/lib/datagrid/core.rb CHANGED
@@ -1,48 +1,77 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "datagrid/drivers"
2
4
  require "active_support/core_ext/class/attribute"
5
+ require "active_model/attribute_assignment"
3
6
 
4
7
  module Datagrid
8
+ # Simple example of using Datagrid scope as the assets source to be queried from the database.
9
+ #
10
+ # In most cases, the scope is a model class with some default ORM scopes, like `order` or `includes`:
11
+ #
12
+ # The scope is also used to:
13
+ # - Choose an ORM driver (e.g., Mongoid, ActiveRecord, etc.).
14
+ # - Association preloading
15
+ # - Columns Providing default order
16
+ #
17
+ # You can set the scope at class level or instance level.
18
+ # Both having appropriate use cases
19
+ #
20
+ # @example Defining a scope in a grid class
21
+ # class ProjectsGrid
22
+ # include Datagrid
23
+ # scope { Project.includes(:category) }
24
+ # end
25
+ #
26
+ # @example Setting a scope at the instance level
27
+ # grid = ProjectsGrid.new(grid_params) do |scope|
28
+ # scope.where(owner_id: current_user.id)
29
+ # end
30
+ #
31
+ # grid.assets # => SELECT * FROM projects WHERE projects.owner_id = ? AND [other filtering conditions]
32
+ #
33
+ # @example Retrieving and redefining the scope
34
+ # grid.scope # => SELECT * FROM projects WHERE projects.user_id = ?
35
+ # grid.redefined_scope? # => true
36
+ #
37
+ # # Reset scope to default class value
38
+ # grid.reset_scope
39
+ # grid.assets # => SELECT * FROM projects
40
+ # grid.redefined_scope? # => false
41
+ #
42
+ # # Overwriting the scope (ignoring previously defined)
43
+ # grid.scope { current_user.projects }
44
+ # grid.redefined_scope? # => true
5
45
  module Core
46
+ include ::ActiveModel::AttributeAssignment
6
47
 
7
48
  # @!visibility private
8
49
  def self.included(base)
9
50
  base.extend ClassMethods
10
51
  base.class_eval do
11
52
  class_attribute :scope_value
12
-
13
- class_attribute :datagrid_attributes, instance_writer: false
14
- self.datagrid_attributes = []
15
-
53
+ class_attribute :datagrid_attributes, instance_writer: false, default: []
16
54
  class_attribute :dynamic_block, instance_writer: false
17
- class_attribute :forbidden_attributes_protection, instance_writer: false
18
- self.forbidden_attributes_protection = false
19
- if defined?(::ActiveModel::AttributeAssignment)
20
- include ::ActiveModel::AttributeAssignment
21
- end
55
+ class_attribute :forbidden_attributes_protection, instance_writer: false, default: false
22
56
  end
23
- base.include InstanceMethods
24
57
  end
25
58
 
26
59
  module ClassMethods
27
-
28
60
  # @!visibility private
29
61
  def datagrid_attribute(name, &block)
30
- unless datagrid_attributes.include?(name)
31
- block ||= lambda do |value|
32
- value
33
- end
34
- datagrid_attributes << name
35
- define_method name do
36
- instance_variable_get("@#{name}")
37
- end
62
+ return if datagrid_attributes.include?(name)
38
63
 
39
- define_method :"#{name}=" do |value|
40
- instance_variable_set("@#{name}", instance_exec(value, &block))
41
- end
64
+ datagrid_attributes << name
65
+ define_method name do
66
+ instance_variable_get("@#{name}")
67
+ end
68
+
69
+ define_method :"#{name}=" do |value|
70
+ instance_variable_set("@#{name}", block ? instance_exec(value, &block) : value)
42
71
  end
43
72
  end
44
73
 
45
- # Defines a scope at class level
74
+ # Defines a relation scope of database models to be filtered
46
75
  # @return [void]
47
76
  # @example
48
77
  # scope { User }
@@ -115,163 +144,168 @@ module Datagrid
115
144
  end
116
145
  end
117
146
 
118
- protected
119
-
147
+ # @!visibility private
120
148
  def check_scope_defined!(message = nil)
121
149
  message ||= "#{self}.scope is not defined"
122
150
  raise(Datagrid::ConfigurationError, message) unless scope_value
123
151
  end
124
152
 
153
+ protected
154
+
155
+ # @!visibility private
125
156
  def inherited(child_class)
126
- super(child_class)
127
- child_class.datagrid_attributes = self.datagrid_attributes.clone
157
+ super
158
+ child_class.datagrid_attributes = datagrid_attributes.clone
128
159
  end
129
-
130
160
  end
131
161
 
132
- module InstanceMethods
162
+ # @param [Hash{String, Symbol => Object}] attributes a hash of attributes to initialize the object
163
+ # @yield [block] an optional block that is passed to the scope method for further customization
164
+ # @return [void] Initializes a new instance with optional attributes and an optional block.
165
+ def initialize(attributes = nil, &block)
166
+ super()
133
167
 
134
- def initialize(attributes = nil, &block)
135
- super()
168
+ self.attributes = attributes if attributes
136
169
 
137
- if attributes
138
- self.attributes = attributes
139
- end
170
+ instance_eval(&dynamic_block) if dynamic_block
171
+ return unless block_given?
140
172
 
141
- instance_eval(&dynamic_block) if dynamic_block
142
- if block_given?
143
- self.scope(&block)
144
- end
145
- end
173
+ scope(&block)
174
+ end
146
175
 
147
- # @return [Hash<Symbol, Object>] grid attributes including filter values and ordering values
148
- def attributes
149
- result = {}
150
- self.datagrid_attributes.each do |name|
151
- result[name] = self[name]
152
- end
153
- result
176
+ # @return [Hash{Symbol => Object}] grid attributes including filter values and ordering values
177
+ # @example
178
+ # class UsersGrid < ApplicationGrid
179
+ # scope { User }
180
+ # filter(:first_name, :string)
181
+ # filter(:last_name, :string)
182
+ # end
183
+ #
184
+ # grid = UsersGrid.new(first_name: 'John', last_name: 'Smith')
185
+ # grid.attributes # => {first_name: 'John', last_name: 'Smith', order: nil, descending: nil}
186
+ def attributes
187
+ result = {}
188
+ datagrid_attributes.each do |name|
189
+ result[name] = self[name]
154
190
  end
191
+ result
192
+ end
155
193
 
156
- # @return [Object] Any datagrid attribute value
157
- def [](attribute)
158
- self.send(attribute)
159
- end
194
+ # @param [String, Symbol] attribute attribute name
195
+ # @return [Object] Any datagrid attribute value
196
+ def [](attribute)
197
+ public_send(attribute)
198
+ end
160
199
 
161
- # Assigns any datagrid attribute
162
- # @param attribute [Symbol, String] Datagrid attribute name
163
- # @param value [Object] Datagrid attribute value
164
- # @return [void]
165
- def []=(attribute, value)
166
- self.send(:"#{attribute}=", value)
167
- end
200
+ # Assigns any datagrid attribute
201
+ # @param attribute [Symbol, String] Datagrid attribute name
202
+ # @param value [Object] Datagrid attribute value
203
+ # @return [void]
204
+ def []=(attribute, value)
205
+ public_send(:"#{attribute}=", value)
206
+ end
168
207
 
169
- # @return [Object] a scope relation (e.g ActiveRecord::Relation) with all applied filters
170
- def assets
171
- scope
172
- end
208
+ # @return [Object] a scope relation (e.g ActiveRecord::Relation) with all applied filters
209
+ def assets
210
+ scope
211
+ end
173
212
 
174
- # Updates datagrid attributes with a passed hash argument
175
- def attributes=(attributes)
176
- if respond_to?(:assign_attributes)
177
- if !forbidden_attributes_protection && attributes.respond_to?(:permit!)
178
- attributes.permit!
179
- end
180
- assign_attributes(attributes)
181
- else
182
- attributes.each do |name, value|
183
- self[name] = value
184
- end
185
- self
186
- end
213
+ # @return [Hash{Symbol => Object}] serializable query arguments skipping all nil values
214
+ # @example
215
+ # grid = ProductsGrid.new(category: 'dresses', available: true)
216
+ # grid.as_query # => {category: 'dresses', available: true}
217
+ def as_query
218
+ attributes = self.attributes.clone
219
+ attributes.each do |key, value|
220
+ attributes.delete(key) if value.nil?
187
221
  end
222
+ attributes
223
+ end
188
224
 
189
- # Returns serializable query arguments skipping all nil values
190
- # @example
191
- # grid = ProductsGrid.new(category: 'dresses', available: true)
192
- # grid.as_query # => {category: 'dresses', available: true}
193
- def as_query
194
- attributes = self.attributes.clone
195
- attributes.each do |key, value|
196
- attributes.delete(key) if value.nil?
197
- end
198
- attributes
199
- end
225
+ # @return [Hash{Symbol => Hash{Symbol => Object}}] query parameters to link this grid from a page
226
+ # @example
227
+ # grid = ProductsGrid.new(category: 'dresses', available: true)
228
+ # Rails.application.routes.url_helpers.products_path(grid.query_params)
229
+ # # => "/products?products_grid[category]=dresses&products_grid[available]=true"
230
+ def query_params(attributes = {})
231
+ { param_name.to_sym => as_query.merge(attributes) }
232
+ end
200
233
 
201
- # @return [Hash<Symbol, Hash<Symbol, Object>>] query parameters to link this grid from a page
202
- # @example
203
- # grid = ProductsGrid.new(category: 'dresses', available: true)
204
- # Rails.application.routes.url_helpers.products_path(grid.query_params)
205
- # # => "/products?products_grid[category]=dresses&products_grid[available]=true"
206
- def query_params(attributes = {})
207
- { param_name.to_sym => as_query.merge(attributes) }
234
+ # @return [void] redefines scope at instance level
235
+ # @example
236
+ # class MyGrid
237
+ # scope { Article.order('created_at desc') }
238
+ # end
239
+ #
240
+ # grid = MyGrid.new
241
+ # grid.scope do |scope|
242
+ # scope.where(author_id: current_user.id)
243
+ # end
244
+ # grid.assets
245
+ # # => SELECT * FROM articles WHERE author_id = ?
246
+ # # ORDER BY created_at desc
247
+ def scope(&block)
248
+ if block_given?
249
+ current_scope = scope
250
+ self.scope_value = proc {
251
+ Datagrid::Utils.apply_args(current_scope, &block)
252
+ }
253
+ self
254
+ else
255
+ scope = original_scope
256
+ driver.to_scope(scope)
208
257
  end
258
+ end
209
259
 
210
- # Redefines scope at instance level
211
- # @example
212
- # class MyGrid
213
- # scope { Article.order('created_at desc') }
214
- # end
215
- #
216
- # grid = MyGrid.new
217
- # grid.scope do |scope|
218
- # scope.where(author_id: current_user.id)
219
- # end
220
- # grid.assets
221
- # # => SELECT * FROM articles WHERE author_id = ?
222
- # # ORDER BY created_at desc
223
- def scope(&block)
224
- if block_given?
225
- current_scope = scope
226
- self.scope_value = proc {
227
- Datagrid::Utils.apply_args(current_scope, &block)
228
- }
229
- self
230
- else
231
- scope = original_scope
232
- driver.to_scope(scope)
233
- end
234
- end
260
+ # @!visibility private
261
+ def original_scope
262
+ self.class.check_scope_defined!
263
+ scope_value.call
264
+ end
235
265
 
236
- # @!visibility private
237
- def original_scope
238
- check_scope_defined!
239
- scope_value.call
240
- end
266
+ # @return [void] Resets current instance scope to default scope defined in a class
267
+ def reset_scope
268
+ self.scope_value = self.class.scope_value
269
+ end
241
270
 
242
- # Resets current instance scope to default scope defined in a class
243
- # @return [void]
244
- def reset_scope
245
- self.scope_value = self.class.scope_value
246
- end
271
+ # @return [Boolean] true if the scope was redefined for this instance of grid object
272
+ def redefined_scope?
273
+ self.class.scope_value != scope_value
274
+ end
247
275
 
248
- # @return [Boolean] true if the scope was redefined for this instance of grid object
249
- def redefined_scope?
250
- self.class.scope_value != scope_value
251
- end
276
+ # @!visibility private
277
+ def driver
278
+ self.class.driver
279
+ end
252
280
 
253
- # @!visibility private
254
- def driver
255
- self.class.driver
256
- end
281
+ # @return [String] a datagrid attributes and their values in inspection form
282
+ def inspect
283
+ attrs = attributes.map do |key, value|
284
+ "#{key}: #{value.inspect}"
285
+ end.join(", ")
286
+ "#<#{self.class} #{attrs}>"
287
+ end
257
288
 
258
- # @!visibility private
259
- def check_scope_defined!(message = nil)
260
- self.class.send :check_scope_defined!, message
261
- end
289
+ def ==(other)
290
+ self.class == other.class &&
291
+ attributes == other.attributes &&
292
+ scope == other.scope
293
+ end
262
294
 
263
- # @return [String] a datagrid attributes and their values in inspection form
264
- def inspect
265
- attrs = attributes.map do |key, value|
266
- "#{key}: #{value.inspect}"
267
- end.join(", ")
268
- "#<#{self.class} #{attrs}>"
269
- end
295
+ # @return [void] Resets loaded assets and column values cache
296
+ def reset
297
+ assets.reset
298
+ end
270
299
 
271
- def ==(other)
272
- self.class == other.class &&
273
- attributes == other.attributes &&
274
- scope == other.scope
300
+ protected
301
+
302
+ def sanitize_for_mass_assignment(attributes)
303
+ if forbidden_attributes_protection
304
+ super
305
+ elsif defined?(ActionController::Parameters) && attributes.is_a?(ActionController::Parameters)
306
+ attributes.to_unsafe_h
307
+ else
308
+ attributes
275
309
  end
276
310
  end
277
311
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datagrid
4
+ # @!visibility private
5
+ class DeprecatedObject < BasicObject
6
+ def initialize(real_object, &block)
7
+ @real_object = real_object
8
+ @block = block
9
+ end
10
+
11
+ def method_missing(method_name, ...)
12
+ @block.call
13
+ @real_object.public_send(method_name, ...)
14
+ end
15
+
16
+ def respond_to_missing?(method_name, include_private = false)
17
+ @real_object.respond_to?(method_name, include_private)
18
+ end
19
+ end
20
+ end
@@ -1,20 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Datagrid
2
4
  module Drivers
3
5
  # @!visibility private
4
6
  class AbstractDriver
7
+ TIMESTAMP_CLASSES = [DateTime, Time, ActiveSupport::TimeWithZone].freeze
5
8
 
6
- TIMESTAMP_CLASSES = [DateTime, Time, ActiveSupport::TimeWithZone]
7
-
8
- class_attribute :subclasses
9
+ class_attribute :subclasses, default: []
9
10
 
10
11
  def self.inherited(base)
11
- super(base)
12
- self.subclasses ||= []
13
- self.subclasses << base
12
+ super
13
+ subclasses << base
14
14
  end
15
15
 
16
16
  def self.guess_driver(scope)
17
- self.subclasses.find do |driver_class|
17
+ subclasses.find do |driver_class|
18
18
  driver_class.match?(scope)
19
19
  end || raise(Datagrid::ConfigurationError, "ORM Driver not found for scope: #{scope.inspect}.")
20
20
  end
@@ -55,7 +55,7 @@ module Datagrid
55
55
  raise NotImplementedError
56
56
  end
57
57
 
58
- def has_column?(scope, column_name)
58
+ def scope_has_column?(scope, column_name)
59
59
  raise NotImplementedError
60
60
  end
61
61
 
@@ -63,7 +63,7 @@ module Datagrid
63
63
  raise NotImplementedError
64
64
  end
65
65
 
66
- def is_timestamp?(scope, field)
66
+ def timestamp_column?(scope, field)
67
67
  normalized_column_type(scope, field) == :timestamp
68
68
  end
69
69
 
@@ -84,28 +84,15 @@ module Datagrid
84
84
  end
85
85
 
86
86
  def append_column_queries(assets, columns)
87
- if columns.present?
88
- raise NotImplementedError
89
- else
90
- assets
91
- end
87
+ raise NotImplementedError if columns.present?
88
+
89
+ assets
92
90
  end
93
91
 
94
92
  def default_cache_key(asset)
95
93
  raise NotImplementedError
96
94
  end
97
95
 
98
- def where_by_timestamp_gotcha(scope, name, value)
99
- value = Datagrid::Utils.format_date_as_timestamp(value)
100
- if value.first
101
- scope = greater_equal(scope, name, value.first)
102
- end
103
- if value.last
104
- scope = less_equal(scope, name, value.last)
105
- end
106
- scope
107
- end
108
-
109
96
  def default_preload(scope, value)
110
97
  raise NotImplementedError
111
98
  end
@@ -115,6 +102,7 @@ module Datagrid
115
102
  end
116
103
 
117
104
  protected
105
+
118
106
  def timestamp_class?(klass)
119
107
  TIMESTAMP_CLASSES.include?(klass)
120
108
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Datagrid
2
4
  module Drivers
3
5
  # @!visibility private
4
6
  class ActiveRecord < AbstractDriver
5
-
6
7
  def self.match?(scope)
7
8
  return false unless defined?(::ActiveRecord)
9
+
8
10
  if scope.is_a?(Class)
9
11
  scope.ancestors.include?(::ActiveRecord::Base)
10
12
  else
@@ -14,6 +16,7 @@ module Datagrid
14
16
 
15
17
  def to_scope(scope)
16
18
  return scope if scope.is_a?(::ActiveRecord::Relation)
19
+
17
20
  # Model class or Active record association
18
21
  # ActiveRecord association class hides itself under an Array
19
22
  # We can only reveal it by checking if it respond to some specific
@@ -29,10 +32,8 @@ module Datagrid
29
32
 
30
33
  def append_column_queries(assets, columns)
31
34
  if columns.present?
32
- if assets.select_values.empty?
33
- assets = assets.select(Arel.respond_to?(:star) ? assets.klass.arel_table[Arel.star] : "#{assets.quoted_table_name}.*")
34
- end
35
- columns = columns.map {|c| "#{c.query} AS #{c.name}"}
35
+ assets = assets.select(assets.klass.arel_table[Arel.star]) if assets.select_values.empty?
36
+ columns = columns.map { |c| "#{c.query} AS #{c.name}" }
36
37
  assets = assets.select(*columns)
37
38
  end
38
39
  assets
@@ -61,7 +62,7 @@ module Datagrid
61
62
  end
62
63
 
63
64
  def default_order(scope, column_name)
64
- has_column?(scope, column_name) ? prefix_table_name(scope, column_name) : nil
65
+ scope_has_column?(scope, column_name) ? prefix_table_name(scope, column_name) : nil
65
66
  end
66
67
 
67
68
  def greater_equal(scope, field, value)
@@ -72,7 +73,7 @@ module Datagrid
72
73
  scope.where(["#{prefix_table_name(scope, field)} <= ?", value])
73
74
  end
74
75
 
75
- def has_column?(scope, column_name)
76
+ def scope_has_column?(scope, column_name)
76
77
  scope.column_names.include?(column_name.to_s)
77
78
  rescue ::ActiveRecord::StatementInvalid
78
79
  false
@@ -88,15 +89,16 @@ module Datagrid
88
89
  end
89
90
 
90
91
  def normalized_column_type(scope, field)
91
- return nil unless has_column?(scope, field)
92
+ return nil unless scope_has_column?(scope, field)
93
+
92
94
  builtin_type = scope.columns_hash[field.to_s].type
93
95
  {
94
- [:string, :text, :time, :binary] => :string,
95
- [:integer, :primary_key] => :integer,
96
- [:float, :decimal] => :float,
96
+ %i[string text time binary] => :string,
97
+ %i[integer primary_key] => :integer,
98
+ %i[float decimal] => :float,
97
99
  [:date] => :date,
98
- [:datetime, :timestamp] => :timestamp,
99
- [:boolean] => :boolean
100
+ %i[datetime timestamp] => :timestamp,
101
+ [:boolean] => :boolean,
100
102
  }.each do |keys, value|
101
103
  return value if keys.include?(builtin_type)
102
104
  end
@@ -106,6 +108,7 @@ module Datagrid
106
108
  if scope.limit_value
107
109
  raise Datagrid::ConfigurationError, "ActiveRecord can not use batches in combination with SQL limit"
108
110
  end
111
+
109
112
  options = batch_size ? { batch_size: batch_size } : {}
110
113
  scope.find_each(**options, &block)
111
114
  end
@@ -119,28 +122,23 @@ module Datagrid
119
122
  end
120
123
 
121
124
  def can_preload?(scope, association)
122
- !! scope.klass.reflect_on_association(association)
125
+ !!scope.klass.reflect_on_association(association)
123
126
  end
124
127
 
125
128
  protected
126
129
 
127
130
  def prefix_table_name(scope, field)
128
- has_column?(scope, field) ? [scope.table_name, field].join(".") : field
131
+ scope_has_column?(scope, field) ? [scope.table_name, field].join(".") : field
129
132
  end
130
133
 
131
134
  def contains_predicate
132
- defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) &&
133
- ::ActiveRecord::Base.connection.is_a?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) ?
134
- 'ilike' : 'like'
135
+ if defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) &&
136
+ ::ActiveRecord::Base.connection.is_a?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
137
+ "ilike"
138
+ else
139
+ "like"
140
+ end
135
141
  end
136
142
  end
137
143
  end
138
144
  end
139
-
140
- if defined?(ActiveRecord::Base)
141
- ActiveRecord::Base.class_eval do
142
- def self.datagrid_where_by_timestamp(column, value)
143
- Datagrid::Drivers::ActiveRecord.new.where_by_timestamp_gotcha(self, column, value)
144
- end
145
- end
146
- end