data_tables-responder 0.3.2 → 0.4.0

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
  SHA1:
3
- metadata.gz: 1b8e8b8bde92df9cf464672c0272403a5b10025e
4
- data.tar.gz: f777b05dc78a0b3e2e5cc6cbeeb021069502b162
3
+ metadata.gz: e79c11cbef86746b623368d109260dbc13752ba5
4
+ data.tar.gz: 7420babe2bad5e577d259f337d52edce56c6c54b
5
5
  SHA512:
6
- metadata.gz: a50cabb76cb4539b913fd7a4d839fec3400dfa3a3862a51a1a0106234b2dd4c81a225abe823670ffc300eba6edee6e690ff64d9c47e575c7ab2b8f51402f1927
7
- data.tar.gz: d6a683c1f43ad56869ec4d4adcfed6aec6a785c898e84f57ae9d742f38444632486bb08ecf4465a2f62014b8ef429313f4c1a626e322a1b28827c2467c513196
6
+ metadata.gz: 628bb80e343d030ed42a07735b38c841231cc9b14c3b74dede6e308af88e97b073e38e53aa469b829b7999ca7654c537b54a187b695906d4af530e21df27b02d
7
+ data.tar.gz: 0049ae6598ae3ac3eaa0bd1c15d343f49f72cf99264434f96e5dae80375e293e25c8bb56bd14109e66ccd88d85dedc4b0606dd86c4426c5c5b5131663880fa30
@@ -26,9 +26,14 @@ Gem::Specification.new do |spec|
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ['lib']
28
28
 
29
+ rails_versions = ['>= 4.1', '< 6']
30
+
29
31
  spec.add_dependency 'active_model_serializers', '~> 0.10.4'
30
- spec.add_dependency 'count_estimate'
32
+ spec.add_dependency 'railties', rails_versions
33
+ spec.add_dependency 'quick_count', ['>= 0.0.3', '< 0.1.0']
31
34
 
35
+ spec.add_development_dependency 'activerecord', rails_versions
36
+ spec.add_development_dependency 'pry-byebug'
32
37
  spec.add_development_dependency 'bundler', '~> 1.12'
33
38
  spec.add_development_dependency 'rake', '~> 10.0'
34
39
  spec.add_development_dependency 'rspec', '~> 3.0'
@@ -29,15 +29,16 @@ module DataTables
29
29
  private
30
30
 
31
31
  def get_records_filtered
32
- if records_total < 1_000_000
33
- @collection.unscope(:limit, :offset).count(@collection.model.primary_key).to_i
32
+ to_filter = @collection.unscope(:limit, :offset)
33
+ if !to_filter.respond_to?(:count_estimate) || records_total < 1_000_000
34
+ to_filter.count(@collection.model.primary_key).to_i
34
35
  else
35
- @collection.unscope(:limit, :offset).count_estimate.to_i
36
+ to_filter.count_estimate.to_i
36
37
  end
37
38
  end
38
39
 
39
40
  def get_records_total
40
- count = @collection.model.all.count_estimate.to_i
41
+ count = @collection.model.quick_count
41
42
  if count < 1_000_000
42
43
  count = @collection.model.all.count(@collection.model.primary_key).to_i
43
44
  end
@@ -0,0 +1,63 @@
1
+ module DataTables
2
+ module Modules
3
+ class Order
4
+
5
+ attr_reader :scope, :context
6
+
7
+ def initialize(scope, request_parameters)
8
+ @scope = scope.dup
9
+ @request_parameters = request_parameters
10
+ end
11
+
12
+ def order
13
+ # default_order = @request_parameters.dig(:order, :value)
14
+
15
+ model = @scope.try(:model) || @scope
16
+ columns = orderable_columns(@request_parameters[:order], @request_parameters[:columns])
17
+
18
+ orders = DataTables::Responder.flat_keys_to_nested columns
19
+
20
+ order_by, join_hash = build_order(model, orders)
21
+
22
+ @scope = @scope.joins(join_hash)
23
+
24
+ order_by.inject(@scope) { |r, o| r.order(o) }
25
+ end
26
+
27
+ def build_order(model, in_hash, join_hash = nil)
28
+ # Tuple!
29
+ return in_hash.inject([]) { |sum, (k, h)|
30
+ case h
31
+ when Hash
32
+ if (klass = model.reflect_on_association(k).try(:klass))
33
+
34
+ new_sum, join_class = build_order(klass, h)
35
+
36
+ join_hash = join_class.nil? ? [k] : {k => join_class}
37
+
38
+ sum += new_sum
39
+ else
40
+ warn("trying to reflect on #{k} but #{model.class.name} has no such association.")
41
+ end
42
+ else
43
+ sum << model.arel_table[k].send(h) if model.column_names.include?(k.to_s)
44
+ end
45
+ sum
46
+ }, join_hash
47
+ end
48
+
49
+ protected
50
+
51
+ def orderable_columns(orders, columns)
52
+ sums = {}
53
+ (orders || []).inject(sums) do |sum, order|
54
+ if (name = columns[order[:column]][:data]).present?
55
+ sum[name] = order[:dir]
56
+ end
57
+ end
58
+ sums
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -1,4 +1,3 @@
1
- require 'count_estimate'
2
1
 
3
2
  module DataTables
4
3
  module Modules
@@ -2,67 +2,71 @@ module DataTables
2
2
  module Modules
3
3
  class Search
4
4
 
5
- attr_reader :collection, :context
5
+ attr_reader :scope, :context
6
6
 
7
- def initialize(collection, request_parameters)
8
- @collection = collection
7
+ def initialize(scope, request_parameters)
8
+ @scope = scope
9
9
  @request_parameters = request_parameters
10
10
  end
11
11
 
12
12
  def search
13
13
  default_search = @request_parameters.dig(:search, :value)
14
14
 
15
- model = @collection.try(:model) || @collection
16
- arel_table = model.arel_table
15
+ model = @scope.try(:model) || @scope
17
16
  columns = searchable_columns(default_search)
18
17
 
19
18
  searches = DataTables::Responder.flat_keys_to_nested columns
20
19
 
21
- search_by = build_search(model, searches)
20
+ search_by, join_hash = build_search(model, searches)
22
21
 
23
- @collection.where(search_by.reduce(:and))
24
- end
22
+ @scope = @scope.joins(join_hash)
25
23
 
26
- def build_search(model, searches)
27
- # join_type = Arel::Nodes::OuterJoin
28
- join_type = Arel::Nodes::InnerJoin
24
+ @scope.where(search_by.reduce(:and))
25
+ end
29
26
 
30
- searches.inject([]) do |queries, junk|
31
- column, query = junk
27
+ def build_search(model, in_hash, join_hash = nil)
28
+ # Tuple!
29
+ return in_hash.inject([]) { |queries, (column, query)|
32
30
  case query
33
31
  when Hash
34
- assoc = model.reflect_on_association(column)
35
- assoc_klass = assoc.klass
36
-
37
- join = join_type.new(assoc_klass.arel_table,
38
- Arel::Nodes::On.new(
39
- model.arel_table[assoc.foreign_key].eq(assoc_klass.arel_table[assoc.active_record_primary_key])
40
- ))
41
- @collection = @collection.joins(join)
42
- queries << build_search(assoc_klass, query).reduce(:and)
32
+ if (assoc = model.reflect_on_association(column))
33
+ new_queries, join_class = build_search(assoc.klass, query)
34
+
35
+ join_hash = join_class.nil? ? [column] : {column => join_class}
36
+
37
+ queries << new_queries.reduce(:and)
38
+ else
39
+ warn("trying to reflect on #{column} but #{model.class.name} has no such association.")
40
+ end
43
41
  else
44
- col_s = column.to_s
45
- case (k = model.columns.find(nil) { |c| c.name == col_s })&.type
46
- when :string
47
- # I'm pretty sure this is safe from SQL Injection
48
- queries << model.arel_table[k.name].matches("%#{query}%")
49
- when :integer
50
- if value = query&.to_i
51
- queries << model.arel_table[k.name].eq(value)
52
- end
53
- when :datetime
54
- datetime = Time.parse(query)
55
- range = (datetime-1.second)..(datetime+1.second)
56
- queries << model.arel_table[k.name].between(range)
42
+ search_by_type(model, column, query) do |result|
43
+ queries << result
57
44
  end
58
45
  end
59
-
60
46
  queries
61
- end
47
+ }, join_hash
62
48
  end
63
49
 
64
50
  protected
65
51
 
52
+ def search_by_type(model, column, query, &block)
53
+ result = case model.columns_hash[column.to_s]&.type
54
+ when :string
55
+ # I'm pretty sure this is safe from SQL Injection
56
+ model.arel_table[column].matches("%#{query}%")
57
+ when :integer
58
+ model.arel_table[column].eq(value) if value = query&.to_i
59
+ when :datetime
60
+ datetime = Time.parse(query)
61
+ range = (datetime-1.second)..(datetime+1.second)
62
+ model.arel_table[column].between(range)
63
+ end
64
+
65
+ yield(result) if !result.nil? && block_given?
66
+
67
+ result
68
+ end
69
+
66
70
  def searchable_columns(default_search)
67
71
  @searchable_columns = {}
68
72
  @request_parameters[:columns]&.inject(@searchable_columns) do |a, b|
@@ -77,8 +81,6 @@ module DataTables
77
81
  @searchable_columns
78
82
  end
79
83
 
80
- private
81
-
82
84
  end
83
85
  end
84
86
  end
@@ -1,6 +1,7 @@
1
1
  require 'rails/railtie'
2
2
  require 'action_controller'
3
3
  require 'action_controller/railtie'
4
+ require 'quick_count/railtie'
4
5
 
5
6
  module DataTables
6
7
  module Responder
@@ -1,5 +1,5 @@
1
1
  module DataTables
2
2
  module Responder
3
- VERSION = '0.3.2'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
@@ -1,7 +1,9 @@
1
+ require 'data_tables'
1
2
  require "data_tables/responder/version"
2
3
 
3
4
  require 'data_tables/modules/pagination'
4
5
  require 'data_tables/modules/search'
6
+ require 'data_tables/modules/order'
5
7
 
6
8
  require 'data_tables/active_model_serializers/adapter'
7
9
  require 'data_tables/responder/railtie' if defined? ::Rails::Railtie
@@ -12,26 +14,14 @@ module DataTables
12
14
  def self.respond(original_scope, params)
13
15
  model = original_scope.try(:model) || original_scope
14
16
 
15
- filtered_results = original_scope&.dup || model.none
16
- hashed_orders = transmute_datatable_order(params[:order], params[:columns])
17
- orders = flat_keys_to_nested hashed_orders
17
+ filtered_scope = original_scope&.dup || model.none
18
18
 
19
- order_by = orders.collect do |k, order|
20
- if order.is_a? Hash
21
- if (klass = model.reflect_on_association(k).try(:klass))
22
- filtered_results = filtered_results.joins(k)
23
- klass.arel_table[order.first.first].send(order.first.last)
24
- end
25
- else
26
- { k => order }
27
- end
28
- end
19
+ filtered_scope = order(filtered_scope, params)
29
20
 
30
- filtered_results = search(filtered_results, params)
21
+ filtered_scope = search(filtered_scope, params)
31
22
 
32
23
  # Rails.logger.warn "SEARCH BY: #{search_by}"
33
- filtered_results = order_by.inject(filtered_results) { |r, o| r.order(o) }
34
- filtered_results = paginate(original_scope, filtered_results, params)
24
+ filtered_scope = paginate(original_scope, filtered_scope, params)
35
25
  end
36
26
 
37
27
  def self.flat_keys_to_nested(hash)
@@ -42,27 +32,17 @@ module DataTables
42
32
  end
43
33
  end
44
34
 
45
-
46
- def self.paginate(original_scope, filtered_results, params)
47
- Modules::Pagination.new(original_scope, filtered_results, params).paginate
35
+ def self.paginate(original_scope, filtered_scope, params)
36
+ Modules::Pagination.new(original_scope, filtered_scope, params).paginate
48
37
  end
49
38
 
50
- def self.search(filtered_results, params)
51
- Modules::Search.new(filtered_results, params).search
39
+ def self.search(filtered_scope, params)
40
+ Modules::Search.new(filtered_scope, params).search
52
41
  end
53
42
 
54
- def self.transmute_datatable_order(orders, columns)
55
- Hash[if orders.is_a? Array
56
- orders.collect do |order|
57
- if (name = columns[order[:column]][:data]).present?
58
- [name, order[:dir]]
59
- else
60
- nil
61
- end
62
- end
63
- else
64
- []
65
- end.compact]
43
+ def self.order(filtered_scope, params)
44
+ Modules::Order.new(filtered_scope, params).order
66
45
  end
46
+
67
47
  end
68
48
  end
@@ -0,0 +1,6 @@
1
+
2
+ module DataTables
3
+ def self.root
4
+ @root ||= Pathname.new(File.dirname(File.expand_path(File.dirname(__FILE__), '/../')))
5
+ end
6
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: data_tables-responder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dale Stevens
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-01 00:00:00.000000000 Z
11
+ date: 2017-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -25,14 +25,74 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.10.4
27
27
  - !ruby/object:Gem::Dependency
28
- name: count_estimate
28
+ name: railties
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '4.1'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '6'
34
37
  type: :runtime
35
38
  prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '4.1'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '6'
47
+ - !ruby/object:Gem::Dependency
48
+ name: quick_count
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.0.3
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: 0.1.0
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.0.3
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: 0.1.0
67
+ - !ruby/object:Gem::Dependency
68
+ name: activerecord
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '4.1'
74
+ - - "<"
75
+ - !ruby/object:Gem::Version
76
+ version: '6'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '4.1'
84
+ - - "<"
85
+ - !ruby/object:Gem::Version
86
+ version: '6'
87
+ - !ruby/object:Gem::Dependency
88
+ name: pry-byebug
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ type: :development
95
+ prerelease: false
36
96
  version_requirements: !ruby/object:Gem::Requirement
37
97
  requirements:
38
98
  - - ">="
@@ -96,10 +156,12 @@ files:
96
156
  - bin/console
97
157
  - bin/setup
98
158
  - data_tables-responder.gemspec
159
+ - lib/data_tables.rb
99
160
  - lib/data_tables/active_model_serializers/adapter.rb
100
161
  - lib/data_tables/active_model_serializers/adapter/meta.rb
101
162
  - lib/data_tables/active_model_serializers/adapter/pagination.rb
102
163
  - lib/data_tables/active_model_serializers/register_dt_renderer.rb
164
+ - lib/data_tables/modules/order.rb
103
165
  - lib/data_tables/modules/pagination.rb
104
166
  - lib/data_tables/modules/search.rb
105
167
  - lib/data_tables/responder.rb