datagrid 2.0.5 → 2.0.8

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: c86512c8f1419a81e769bc5341867e20071dcf1424ce55200a496e529a3b275c
4
- data.tar.gz: b192c0bd6a90ce4085255de178ef732cbef691c7e529905138b47b6edd122fa1
3
+ metadata.gz: f5ac6077bea5b3ee95001a94f7c862a2430dec10d5d35602ac763ad748b2bd6f
4
+ data.tar.gz: 86a7e62eebc8044e215708ce2aa29f63955e5c7c0635a4e48e1e41f35bffc291
5
5
  SHA512:
6
- metadata.gz: da1baacc64d7e8502ce8738ff4de3c6346f2e1b486a49337c7194a64fcabbf9c38ba8839e1cd1f1be181419b185b79b41147cc0536581846625ca6386c21e1fd
7
- data.tar.gz: af4ababb2213b465ef1fbac48a406166d336d917becbde4cb58ad0643aa78032f0f23fcf4461c730582cf5a162edfec5817f794bea54d9b3310d9801ba5aca63
6
+ metadata.gz: 3f695cc908307c31ae745621b6afe99ef86422b685549d3084e9b5610c7420eea8c0de9318a25849f0e0042bdc0c95d11b6163ebf0d01ea1b4d62d6de8bd2b81
7
+ data.tar.gz: 3fe0c0cde94487679ec67ba563b8668f26fa4f977700a25ae58c35a1908bdc73d1558b83a4593eaaf51810844baa26e99e834f7a280edae01ad55f6bc83c3051
data/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.8]
4
+
5
+ * Rescue StatementInvalid when guessing column type from a query
6
+ * Prevent typecasting of date into timestamp when `:date` filter has a block
7
+
8
+ ``` ruby
9
+ class MyGrid < Datagrid::Base
10
+ scope { User }
11
+
12
+ filter(:created_at, :date) do |scope, value|
13
+ value.is_a?(Date) # => true
14
+ scope.joins(:registration).where(registrations: { registration_date: value })
15
+ end
16
+ end
17
+ ```
18
+
19
+ ## [2.0.7]
20
+
21
+ * Raise `Datagrid::ConfigurationError` when column or filter name
22
+ specified in `before` or `after` option not found.
23
+ * Fixed `as_query` method when dynamic filter is used. Fixes [#344](https://github.com/bogdan/datagrid/issues/344)
24
+
25
+ ``` ruby
26
+ grid = ProductsGrid.new(category: 'dresses', available: true, condition: ["price", ">=", 25])
27
+ # Before
28
+ grid.as_query
29
+ # => {
30
+ # category: 'dresses',
31
+ # available: true,
32
+ # condition: #<Object>
33
+ # }
34
+ # After
35
+ grid.as_query
36
+ # => {
37
+ # "category" => 'dresses',
38
+ # "available" => true,
39
+ # "condition" => { "field" => "price", "operation" => ">=", "value" => "25" }
40
+ # }
41
+ ```
42
+
43
+
44
+ ## [2.0.6]
45
+
46
+ * Validate dummy filter can not accept block
47
+
3
48
  ## [2.0.5]
4
49
 
5
50
  * Add support for timestamptz ActiveRecord column type
@@ -378,6 +378,9 @@ module Datagrid
378
378
  end
379
379
 
380
380
  position = Datagrid::Utils.extract_position_from_options(columns, options)
381
+ unless position
382
+ raise Datagrid::ConfigurationError, "#{self}##{options[:before] || options[:after]} column not found"
383
+ end
381
384
  column = Datagrid::Columns::Column.new(
382
385
  self, name, query, options, &block
383
386
  )
data/lib/datagrid/core.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "datagrid/drivers"
4
4
  require "active_support/core_ext/class/attribute"
5
+ require "active_support/core_ext/object/json"
5
6
  require "active_model/attribute_assignment"
6
7
 
7
8
  module Datagrid
@@ -210,16 +211,15 @@ module Datagrid
210
211
  scope
211
212
  end
212
213
 
213
- # @return [Hash{Symbol => Object}] serializable query arguments skipping all nil values
214
+ # @return [Hash{String => Object}] serializable query arguments skipping all nil values
214
215
  # @example
215
216
  # grid = ProductsGrid.new(category: 'dresses', available: true)
216
217
  # grid.as_query # => {category: 'dresses', available: true}
217
218
  def as_query
218
- attributes = self.attributes.clone
219
- attributes.each do |key, value|
220
- attributes.delete(key) if value.nil?
219
+ self.attributes.reduce({}) do |result, (k,v)|
220
+ result[k.to_s] = v.as_json unless v.nil?
221
+ result
221
222
  end
222
- attributes
223
223
  end
224
224
 
225
225
  # @return [Hash{Symbol => Hash{Symbol => Object}}] query parameters to link this grid from a page
@@ -228,7 +228,18 @@ module Datagrid
228
228
  # Rails.application.routes.url_helpers.products_path(grid.query_params)
229
229
  # # => "/products?products_grid[category]=dresses&products_grid[available]=true"
230
230
  def query_params(attributes = {})
231
- { param_name.to_sym => as_query.merge(attributes) }
231
+ { param_name.to_s => as_query.merge(attributes.stringify_keys) }
232
+ end
233
+
234
+ # @return [Hash{String => Object}] JSON representation of datagrid attributes
235
+ # @example
236
+ # grid = ProductsGrid.new(category: 'dresses', available: true)
237
+ # grid.as_json # => {"category" => 'dresses', "available" => true}
238
+ def as_json(options = nil)
239
+ attributes.reduce({}) do |result, (k,v)|
240
+ result[k.to_s] = v.as_json(options)
241
+ result
242
+ end
232
243
  end
233
244
 
234
245
  # @return [void] redefines scope at instance level
@@ -31,12 +31,10 @@ module Datagrid
31
31
  end
32
32
 
33
33
  def append_column_queries(assets, columns)
34
- if columns.present?
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}" }
37
- assets = assets.select(*columns)
38
- end
39
- assets
34
+ return assets if columns.empty?
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}" }
37
+ assets.select(*columns)
40
38
  end
41
39
 
42
40
  def where(scope, attribute, value)
@@ -88,20 +86,34 @@ module Datagrid
88
86
  scope.where("#{field} #{contains_predicate} ?", "%#{value}%")
89
87
  end
90
88
 
89
+ def builtin_type(scope, field)
90
+ if scope_has_column?(scope, field)
91
+ scope.columns_hash[field.to_s].type
92
+ else
93
+ begin
94
+ scope.connection.select_all(
95
+ scope.unscope(:select, :order).select(field => "custom_field").limit(0).arel
96
+ ).column_types['custom_field']&.type
97
+ rescue ActiveRecord::StatementInvalid
98
+ nil
99
+ end
100
+ end
101
+ end
102
+
91
103
  def normalized_column_type(scope, field)
92
- return nil unless scope_has_column?(scope, field)
93
-
94
- builtin_type = scope.columns_hash[field.to_s].type
95
- {
96
- %i[string text time binary] => :string,
97
- %i[integer primary_key] => :integer,
98
- %i[float decimal] => :float,
99
- [:date] => :date,
100
- %i[datetime timestamp timestamptz] => :timestamp,
101
- [:boolean] => :boolean,
102
- }.each do |keys, value|
103
- return value if keys.include?(builtin_type)
104
+ if builtin_type = builtin_type(scope, field)
105
+ {
106
+ %i[string text time binary] => :string,
107
+ %i[integer primary_key] => :integer,
108
+ %i[float decimal] => :float,
109
+ [:date] => :date,
110
+ %i[datetime timestamp timestamptz] => :timestamp,
111
+ [:boolean] => :boolean,
112
+ }.each do |keys, value|
113
+ return value if keys.include?(builtin_type)
114
+ end
104
115
  end
116
+ nil
105
117
  end
106
118
 
107
119
  def batch_each(scope, batch_size, &block)
@@ -17,10 +17,13 @@ module Datagrid
17
17
  self.name = name.to_sym
18
18
  self.options = Datagrid::Utils.callable(grid_class.default_filter_options, self).merge(options)
19
19
  self.block = block
20
+ if dummy? && block
21
+ raise Datagrid::ConfigurationError, "#{grid_class}##{name} filter is dummy and can not accept block"
22
+ end
20
23
  end
21
24
 
22
25
  def parse(value)
23
- raise NotImplementedError, "#parse(value) suppose to be overwritten"
26
+ raise NotImplementedError, "#{self.class}#parse(value) suppose to be overwritten"
24
27
  end
25
28
 
26
29
  def default_input_options
@@ -32,7 +35,7 @@ module Datagrid
32
35
  end
33
36
 
34
37
  def apply(grid_object, scope, value)
35
- return scope if unapplicable_value?(value)
38
+ return scope if dummy? || unapplicable_value?(value)
36
39
 
37
40
  result = execute(value, scope, grid_object)
38
41
 
@@ -12,7 +12,9 @@ module Datagrid
12
12
  end
13
13
 
14
14
  def apply(grid_object, scope, value)
15
- value = Datagrid::Utils.format_date_as_timestamp(value) if grid_object.driver.timestamp_column?(scope, name)
15
+ if !dummy? && !block && grid_object.driver.timestamp_column?(scope, name)
16
+ value = Datagrid::Utils.format_date_as_timestamp(value)
17
+ end
16
18
  super
17
19
  end
18
20
 
@@ -128,7 +128,7 @@ module Datagrid
128
128
  end
129
129
 
130
130
  def inspect
131
- { field: field, operation: operation, value: value }
131
+ "#<#{self.class} #{to_h.inspect}>"
132
132
  end
133
133
 
134
134
  def to_ary
@@ -143,6 +143,10 @@ module Datagrid
143
143
  { field: field, operation: operation, value: value }
144
144
  end
145
145
 
146
+ def as_json
147
+ { "field" => field, "operation" => operation, "value" => value }
148
+ end
149
+
146
150
  protected
147
151
 
148
152
  def type_cast(type, value)
@@ -244,6 +244,9 @@ module Datagrid
244
244
  raise ConfigurationError, "filter class #{type.inspect} not found" unless klass
245
245
 
246
246
  position = Datagrid::Utils.extract_position_from_options(filters_array, options)
247
+ unless position
248
+ raise Datagrid::ConfigurationError, "#{self}##{options[:before] || options[:after]} filter not found"
249
+ end
247
250
  filter = klass.new(self, name, **options, &block)
248
251
  filters_array.insert(position, filter)
249
252
 
@@ -436,7 +436,7 @@ module Datagrid
436
436
  query = request&.query_parameters || {}
437
437
  ActionDispatch::Http::URL.path_for(
438
438
  path: request&.path || "/",
439
- params: query.merge(grid.query_params(order: column.name, descending: descending)),
439
+ params: query.merge(grid.query_params("order" => column.name, "descending" => descending)),
440
440
  )
441
441
  end
442
442
 
@@ -4,7 +4,7 @@ module Datagrid
4
4
  # @!visibility private
5
5
  module Utils
6
6
  class << self
7
- TRUTH = [true, 1, "1", "true", "yes", "on"].freeze
7
+ TRUTH = [true, 1, "1", "true", "yes", "on", "y"].freeze
8
8
 
9
9
  def booleanize(value)
10
10
  value = value.downcase if value.respond_to?(:downcase)
@@ -68,7 +68,9 @@ module Datagrid
68
68
  array.index { |c| c.name.to_sym == before }
69
69
  elsif after
70
70
  after = after.to_sym
71
- array.index { |c| c.name.to_sym == after } + 1
71
+ if index = array.index { |c| c.name.to_sym == after }
72
+ index + 1
73
+ end
72
74
  else
73
75
  -1
74
76
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Datagrid
4
- VERSION = "2.0.5"
4
+ VERSION = "2.0.8"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datagrid
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.5
4
+ version: 2.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bogdan Gusiev