tabulatr2 0.9.4 → 0.9.6
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 +4 -4
- data/CHANGELOG.md +29 -0
- data/Gemfile +1 -2
- data/README.md +155 -95
- data/app/assets/javascripts/tabulatr/_storage.js +41 -0
- data/app/assets/javascripts/tabulatr/_tabulatr.js +598 -0
- data/app/assets/javascripts/tabulatr/application.js +3 -553
- data/app/assets/stylesheets/tabulatr/application.css.scss +21 -12
- data/app/assets/stylesheets/tabulatr.css +1 -0
- data/app/views/tabulatr/_tabulatr_actual_table.html.slim +18 -18
- data/app/views/tabulatr/_tabulatr_filter_dialog.html.slim +1 -1
- data/app/views/tabulatr/_tabulatr_fuzzy_search_field.html.slim +1 -1
- data/app/views/tabulatr/_tabulatr_static_table.html.slim +3 -3
- data/app/views/tabulatr/_tabulatr_table.html.slim +17 -12
- data/lib/tabulatr/data/data.rb +7 -9
- data/lib/tabulatr/data/dsl.rb +36 -21
- data/lib/tabulatr/data/filtering.rb +41 -13
- data/lib/tabulatr/data/formatting.rb +7 -20
- data/lib/tabulatr/data/pagination.rb +1 -2
- data/lib/tabulatr/data/proxy.rb +2 -0
- data/lib/tabulatr/data/sorting.rb +24 -13
- data/lib/tabulatr/engine.rb +1 -0
- data/lib/tabulatr/generators/tabulatr/templates/tabulatr.yml +2 -2
- data/lib/tabulatr/json_builder.rb +23 -25
- data/lib/tabulatr/rails/action_controller.rb +4 -0
- data/lib/tabulatr/rails/action_view.rb +3 -2
- data/lib/tabulatr/renderer/checkbox.rb +3 -1
- data/lib/tabulatr/renderer/column.rb +47 -5
- data/lib/tabulatr/renderer/columns_from_block.rb +24 -6
- data/lib/tabulatr/renderer/renderer.rb +26 -17
- data/lib/tabulatr/utility/unexpected_search_result_error.rb +9 -0
- data/lib/tabulatr/utility/utility.rb +4 -0
- data/lib/tabulatr/version.rb +1 -1
- data/spec/dummy/app/controllers/products_controller.rb +9 -0
- data/spec/dummy/app/views/products/local_storage.html.slim +4 -0
- data/spec/dummy/app/views/products/simple_index.html.erb +1 -1
- data/spec/dummy/app/views/products/stupid_array.html.erb +1 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/locales/tabulatr.yml +2 -2
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/features/tabulatrs_spec.rb +27 -27
- data/spec/lib/tabulatr/data/data_spec.rb +12 -16
- data/spec/lib/tabulatr/data/filtering_spec.rb +48 -7
- data/spec/lib/tabulatr/data/formatting_spec.rb +32 -0
- data/spec/lib/tabulatr/data/sorting_spec.rb +81 -0
- data/spec/lib/tabulatr/json_builder_spec.rb +23 -9
- data/spec/lib/tabulatr/renderer/checkbox_spec.rb +14 -0
- data/spec/lib/tabulatr/renderer/renderer_spec.rb +20 -8
- data/tabulatr.gemspec +4 -3
- metadata +45 -9
- data/lib/tabulatr/data/column_name_builder.rb +0 -86
@@ -23,19 +23,30 @@
|
|
23
23
|
|
24
24
|
class Tabulatr::Renderer
|
25
25
|
class ColumnsFromBlock
|
26
|
-
attr_accessor :columns, :klass
|
26
|
+
attr_accessor :columns, :klass, :table_data
|
27
27
|
|
28
|
-
def initialize(klass)
|
28
|
+
def initialize(klass, table_data_object)
|
29
29
|
@klass = klass
|
30
|
+
@table_data = table_data_object
|
30
31
|
@columns ||= []
|
31
32
|
end
|
32
33
|
|
33
34
|
def column(name, opts={}, &block)
|
34
|
-
|
35
|
+
if table_data
|
36
|
+
@columns << fetch_column_from_table_data(klass.table_name.to_sym, name, opts, &block)
|
37
|
+
else
|
38
|
+
@columns << Column.from(opts.merge(klass: klass, table_name: klass.table_name.to_sym, name: name), &block)
|
39
|
+
end
|
35
40
|
end
|
36
41
|
|
37
42
|
def association(table_name, name, opts={}, &block)
|
38
|
-
|
43
|
+
if table_data
|
44
|
+
@columns << fetch_column_from_table_data(table_name, name, opts, &block)
|
45
|
+
else
|
46
|
+
assoc_klass = klass.reflect_on_association(table_name.to_sym)
|
47
|
+
@columns << Association.from(opts.merge(klass: assoc_klass.try(:klass),
|
48
|
+
name: name, table_name: table_name), &block)
|
49
|
+
end
|
39
50
|
end
|
40
51
|
|
41
52
|
def checkbox(opts={})
|
@@ -46,11 +57,18 @@ class Tabulatr::Renderer
|
|
46
57
|
@columns << Action.from(opts.merge(klass: klass, filter: false, sortable: false), &block)
|
47
58
|
end
|
48
59
|
|
49
|
-
def self.process(klass, &block)
|
50
|
-
i = self.new(klass)
|
60
|
+
def self.process(klass, table_data_object = nil, &block)
|
61
|
+
i = self.new(klass, table_data_object)
|
51
62
|
yield(i)
|
52
63
|
c = i.columns
|
53
64
|
c
|
54
65
|
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def fetch_column_from_table_data table_name, name, opts={}, &block
|
70
|
+
column = table_data.table_columns.find{|tc| tc.table_name == table_name && tc.name == name}
|
71
|
+
column.update_options(opts, &block)
|
72
|
+
end
|
55
73
|
end
|
56
74
|
end
|
@@ -32,7 +32,10 @@ class Tabulatr::Renderer
|
|
32
32
|
batch_actions: false, # :name => value hash of batch action stuff
|
33
33
|
footer_content: false, # if given, add a <%= content_for <footer_content> %> before the </table>
|
34
34
|
path: '#', # where to send the AJAX-requests to
|
35
|
-
order_by: nil
|
35
|
+
order_by: nil, # default order
|
36
|
+
html_class: '',
|
37
|
+
pagination_position: :top,
|
38
|
+
persistent: true)
|
36
39
|
@klass = klass
|
37
40
|
@view = view
|
38
41
|
@table_options = {
|
@@ -44,21 +47,27 @@ class Tabulatr::Renderer
|
|
44
47
|
batch_actions: batch_actions,
|
45
48
|
footer_content: footer_content,
|
46
49
|
path: path,
|
47
|
-
order_by: order_by
|
50
|
+
order_by: order_by,
|
51
|
+
html_class: 'table tabulatr_table '.concat(html_class),
|
52
|
+
pagination_position: pagination_position,
|
53
|
+
persistent: paginate ? persistent : false
|
48
54
|
}
|
49
55
|
@classname = @klass.name.underscore
|
50
56
|
end
|
51
57
|
|
52
|
-
def build_table(columns, &block)
|
53
|
-
|
58
|
+
def build_table(columns, tabulatr_data_class, &block)
|
59
|
+
if tabulatr_data_class.present?
|
60
|
+
tdc = tabulatr_data_class.constantize.new(@klass)
|
61
|
+
else
|
62
|
+
tdc = "#{@klass.name}TabulatrData".constantize.new(@klass)
|
63
|
+
end
|
54
64
|
if block_given?
|
55
|
-
@columns = ColumnsFromBlock.process @klass, &block
|
65
|
+
@columns = ColumnsFromBlock.process @klass, tdc, &block
|
56
66
|
elsif columns.any?
|
57
67
|
@columns = get_requested_columns(tdc.table_columns, columns)
|
58
68
|
else
|
59
69
|
@columns = tdc.table_columns
|
60
70
|
end
|
61
|
-
|
62
71
|
@view.render(partial: '/tabulatr/tabulatr_table', locals: {
|
63
72
|
columns: @columns,
|
64
73
|
table_options: @table_options,
|
@@ -66,7 +75,7 @@ class Tabulatr::Renderer
|
|
66
75
|
classname: @classname,
|
67
76
|
tabulatr_data: tdc,
|
68
77
|
table_id: generate_id,
|
69
|
-
formatted_name: formatted_name
|
78
|
+
formatted_name: Tabulatr::Utility.formatted_name(@klass.name)
|
70
79
|
})
|
71
80
|
end
|
72
81
|
|
@@ -83,11 +92,7 @@ class Tabulatr::Renderer
|
|
83
92
|
end
|
84
93
|
|
85
94
|
def generate_id
|
86
|
-
"#{formatted_name}_table_#{
|
87
|
-
end
|
88
|
-
|
89
|
-
def formatted_name
|
90
|
-
"#{@klass.to_s.gsub(/::/, '--').downcase}"
|
95
|
+
"#{Tabulatr::Utility.formatted_name(@klass.name)}_table_#{@view.controller.controller_name}_#{@view.controller.action_name}_#{@view.instance_variable_get(:@_tabulatr_table_index)}"
|
91
96
|
end
|
92
97
|
|
93
98
|
def self.build_static_table(records, view, toptions={}, &block)
|
@@ -96,16 +101,21 @@ class Tabulatr::Renderer
|
|
96
101
|
new(klass, view, toptions).build_static_table(records, &block)
|
97
102
|
end
|
98
103
|
|
99
|
-
def self.build_table(klass, view, toptions={}, columns, &block)
|
100
|
-
new(klass, view, toptions).build_table(columns, &block)
|
104
|
+
def self.build_table(klass, view, toptions={}, columns, tabulatr_data_class, &block)
|
105
|
+
new(klass, view, toptions).build_table(columns, tabulatr_data_class, &block)
|
101
106
|
end
|
102
107
|
|
103
108
|
private
|
104
109
|
|
105
110
|
def get_requested_columns(available_columns, requested_columns)
|
111
|
+
main_table_name = @klass.table_name.to_sym
|
106
112
|
requested_columns.collect do |r|
|
107
|
-
|
108
|
-
|
113
|
+
if r.is_a?(Hash) && r.count == 1
|
114
|
+
r = "#{r.keys.first}:#{r.values.first}"
|
115
|
+
end
|
116
|
+
result = available_columns.find{|column| column.full_name.to_sym == r.to_sym }
|
117
|
+
result = available_columns.find{|column| column.name.to_sym == r.to_sym && column.table_name == main_table_name} if result.nil?
|
118
|
+
result
|
109
119
|
end.flatten
|
110
120
|
end
|
111
121
|
|
@@ -116,4 +126,3 @@ require_relative './association'
|
|
116
126
|
require_relative './action'
|
117
127
|
require_relative './checkbox'
|
118
128
|
require_relative './columns_from_block'
|
119
|
-
|
data/lib/tabulatr/version.rb
CHANGED
@@ -5,7 +5,7 @@ en:
|
|
5
5
|
batch_actions: 'Batch actions'
|
6
6
|
count: 'Showing: %{current} of total %{total}. %{per_page} items per page.'
|
7
7
|
apply_filters: 'Apply'
|
8
|
-
search: 'Search'
|
8
|
+
search: 'Search...'
|
9
9
|
date_filter:
|
10
10
|
none: ''
|
11
11
|
today: "Today"
|
@@ -27,7 +27,7 @@ de:
|
|
27
27
|
batch_actions: 'Batch-Aktionen'
|
28
28
|
count: 'Zeige %{current} von insgesamt %{total}. %{per_page} pro Seite.'
|
29
29
|
apply_filters: 'Anwenden'
|
30
|
-
search: 'Suche'
|
30
|
+
search: 'Suche...'
|
31
31
|
date_filter:
|
32
32
|
none: ''
|
33
33
|
today: "Heute"
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -100,7 +100,7 @@ describe "Tabulatr" do
|
|
100
100
|
Product.create!(:title => "test #{i}")
|
101
101
|
end
|
102
102
|
visit one_item_per_page_with_pagination_products_path
|
103
|
-
page.all('.pagination li a').count.should eq 5
|
103
|
+
page.all('.pagination li a[data-page]').count.should eq 5
|
104
104
|
end
|
105
105
|
|
106
106
|
it 'shows some pages when there are 20', js: true do
|
@@ -108,7 +108,7 @@ describe "Tabulatr" do
|
|
108
108
|
Product.create!
|
109
109
|
end
|
110
110
|
visit one_item_per_page_with_pagination_products_path
|
111
|
-
pages = page.all('.pagination li a').map{|a| a['data-page'].to_i}
|
111
|
+
pages = page.all('.pagination li a[data-page]').map{|a| a['data-page'].to_i}
|
112
112
|
pages.should eq [1,2,3,10,20]
|
113
113
|
end
|
114
114
|
end
|
@@ -136,21 +136,21 @@ describe "Tabulatr" do
|
|
136
136
|
expect(find('.dropdown-menu').visible?)
|
137
137
|
find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
|
138
138
|
within(".tabulatr_filter_form") do
|
139
|
-
fill_in("product_filter[title][like]", with: "ore")
|
139
|
+
fill_in("product_filter[products:title][like]", with: "ore")
|
140
140
|
expect{find('#title_like').visible?}.to be_true
|
141
141
|
find_button("Apply").trigger('click')
|
142
142
|
end
|
143
|
-
expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'lorem')
|
144
|
-
expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'labore')
|
145
|
-
expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'dolore')
|
143
|
+
expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'lorem')
|
144
|
+
expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'labore')
|
145
|
+
expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'dolore')
|
146
146
|
|
147
147
|
within(".tabulatr_filter_form") do
|
148
|
-
fill_in("product_filter[title][like]", :with => "loreem")
|
148
|
+
fill_in("product_filter[products:title][like]", :with => "loreem")
|
149
149
|
find_button("Apply").trigger('click')
|
150
150
|
end
|
151
|
-
expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'lorem')
|
152
|
-
expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'labore')
|
153
|
-
expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'dolore')
|
151
|
+
expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'lorem')
|
152
|
+
expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'labore')
|
153
|
+
expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'dolore')
|
154
154
|
end
|
155
155
|
|
156
156
|
it "filters", js: true do
|
@@ -178,15 +178,15 @@ describe "Tabulatr" do
|
|
178
178
|
end
|
179
179
|
find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
|
180
180
|
within('.tabulatr_filter_form') do
|
181
|
-
fill_in("product_filter[price][from]", :with => 4)
|
182
|
-
fill_in("product_filter[price][to]", :with => 10)
|
181
|
+
fill_in("product_filter[products:price][from]", :with => 4)
|
182
|
+
fill_in("product_filter[products:price][to]", :with => 10)
|
183
183
|
find_button("Apply").trigger('click')
|
184
184
|
end
|
185
185
|
page.find(".tabulatr_table tbody tr[data-id='#{Product.first.id}']").should have_content('foo')
|
186
186
|
page.has_no_css?(".tabulatr_table tbody tr[data-id='#{Product.last.id}']")
|
187
187
|
within('.tabulatr_filter_form') do
|
188
|
-
fill_in("product_filter[price][from]", :with => 12)
|
189
|
-
fill_in("product_filter[price][to]", :with => 19)
|
188
|
+
fill_in("product_filter[products:price][from]", :with => 12)
|
189
|
+
fill_in("product_filter[products:price][to]", :with => 19)
|
190
190
|
find_button("Apply").trigger('click')
|
191
191
|
end
|
192
192
|
page.should have_selector(".tabulatr_table tbody tr[data-id='#{Product.last.id}']")
|
@@ -203,19 +203,19 @@ describe "Tabulatr" do
|
|
203
203
|
expect(find('.dropdown-menu').visible?)
|
204
204
|
find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
|
205
205
|
within(".tabulatr_filter_form") do
|
206
|
-
fill_in("product_filter[title][like]", with: "foo")
|
207
|
-
expect(find('#title_like').visible?)
|
206
|
+
fill_in("product_filter[products:title][like]", with: "foo")
|
207
|
+
# expect(find('#products--title_like').visible?)
|
208
208
|
find_button("Apply").trigger('click')
|
209
209
|
end
|
210
210
|
# expect(page).to have_content('foo')
|
211
211
|
# expect(page).to have_no_content('bar')
|
212
|
-
expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'bar')
|
213
|
-
expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'foo')
|
214
|
-
find("a[data-hide-table-filter='title']").trigger('click')
|
212
|
+
expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'bar')
|
213
|
+
expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'foo')
|
214
|
+
find("a[data-hide-table-filter='products:title']").trigger('click')
|
215
215
|
# expect(page).to have_content('foo')
|
216
216
|
# expect(page).to have_content('bar')
|
217
|
-
expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'bar')
|
218
|
-
expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'foo')
|
217
|
+
expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'bar')
|
218
|
+
expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'foo')
|
219
219
|
end
|
220
220
|
end
|
221
221
|
|
@@ -231,14 +231,14 @@ describe "Tabulatr" do
|
|
231
231
|
page.should have_content names[l-i]
|
232
232
|
end
|
233
233
|
within('.tabulatr_table thead') do
|
234
|
-
find('th[data-tabulatr-column-name=title]').click
|
234
|
+
find('th[data-tabulatr-column-name="products:title"]').click
|
235
235
|
end
|
236
236
|
snames = names.sort
|
237
237
|
(1..10).each do |i|
|
238
238
|
page.should have_content snames[i-1]
|
239
239
|
end
|
240
240
|
within('.tabulatr_table thead') do
|
241
|
-
find('th[data-tabulatr-column-name=title]').click
|
241
|
+
find('th[data-tabulatr-column-name="products:title"]').click
|
242
242
|
end
|
243
243
|
(1..10).each do |i|
|
244
244
|
page.should have_content snames[-i]
|
@@ -303,10 +303,10 @@ describe "Tabulatr" do
|
|
303
303
|
it 'applys the given style' do
|
304
304
|
p = Product.create!(:title => names[0], :active => true, :price => 10.0)
|
305
305
|
visit with_styling_products_path
|
306
|
-
cell = find(".tabulatr_table tbody td[data-tabulatr-column-name='title']")
|
307
|
-
header = find(".tabulatr_table thead th[data-tabulatr-column-name='title']")
|
308
|
-
cell_without_style = find(".tabulatr_table tbody td[data-tabulatr-column-name='price']")
|
309
|
-
header_without_style = find(".tabulatr_table thead th[data-tabulatr-column-name='price']")
|
306
|
+
cell = find(".tabulatr_table tbody td[data-tabulatr-column-name='products:title']")
|
307
|
+
header = find(".tabulatr_table thead th[data-tabulatr-column-name='products:title']")
|
308
|
+
cell_without_style = find(".tabulatr_table tbody td[data-tabulatr-column-name='products:price']")
|
309
|
+
header_without_style = find(".tabulatr_table thead th[data-tabulatr-column-name='products:price']")
|
310
310
|
expect(cell[:style]).to eql 'text-align:left;width:60px;vertical-align:top;white-space:nowrap;background-color:green'
|
311
311
|
expect(header[:style]).to eql 'text-align:left;width:60px;vertical-align:top;white-space:nowrap;color:orange'
|
312
312
|
expect(cell_without_style[:style]).to be_empty
|
@@ -3,8 +3,15 @@ require 'spec_helper'
|
|
3
3
|
describe Tabulatr::Data do
|
4
4
|
|
5
5
|
before do
|
6
|
-
Tabulatr::
|
7
|
-
|
6
|
+
column = Tabulatr::Renderer::Column.from(
|
7
|
+
name: :title,
|
8
|
+
klass: Product,
|
9
|
+
table_name: :products,
|
10
|
+
sort_sql: "products.title",
|
11
|
+
filter_sql: "products.title",
|
12
|
+
output: ->(record){record.send(:title)}
|
13
|
+
)
|
14
|
+
Tabulatr::Data.any_instance.stub(:table_columns).and_return([column])
|
8
15
|
end
|
9
16
|
|
10
17
|
it 'prefilters the result' do
|
@@ -17,24 +24,13 @@ describe Tabulatr::Data do
|
|
17
24
|
it 'uses default order' do
|
18
25
|
Product.create([{title: 'foo', price: 5}, {title: 'bar', price: 10}, {title: 'fuzz', price: 7}])
|
19
26
|
|
20
|
-
cols = {
|
21
|
-
title: {
|
22
|
-
name: 'title',
|
23
|
-
sort_sql: nil,
|
24
|
-
filter_sql: nil,
|
25
|
-
output: nil,
|
26
|
-
table_column: Tabulatr::Renderer::Column.from(name: 'title', klass: Product)
|
27
|
-
}
|
28
|
-
}
|
29
|
-
Tabulatr::Data.instance_variable_set('@columns', cols)
|
30
27
|
td = Tabulatr::Data.new(Product)
|
31
|
-
|
32
|
-
# raise mod_params.inspect
|
33
|
-
records = td.data_for_table(HashWithIndifferentAccess.new(example_params.merge(product_sort: 'products.title DESC')))
|
28
|
+
records = td.data_for_table(HashWithIndifferentAccess.new(example_params.merge(product_sort: 'title DESC')))
|
34
29
|
expect(records.count).to eql 3
|
35
30
|
titles = ['fuzz', 'foo', 'bar']
|
31
|
+
# raise records.inspect
|
36
32
|
records.each_with_index do |r, ix|
|
37
|
-
expect(r[:title]).to eql titles[ix]
|
33
|
+
expect(r[:products][:title]).to eql titles[ix]
|
38
34
|
end
|
39
35
|
end
|
40
36
|
end
|
@@ -21,40 +21,46 @@ describe Tabulatr::Data::Filtering do
|
|
21
21
|
end
|
22
22
|
describe '.apply_date_condition' do
|
23
23
|
it "filters for 'today'" do
|
24
|
-
|
24
|
+
fake_obj = double(filter_sql: 'publish_at')
|
25
|
+
@dummy.apply_date_condition(fake_obj, {simple: 'today'})
|
25
26
|
result = @dummy.instance_variable_get('@relation')
|
26
27
|
expect(result.count).to be 1
|
27
28
|
expect(result[0].id).to be @today.id
|
28
29
|
end
|
29
30
|
|
30
31
|
it "filters for 'yesterday'" do
|
31
|
-
|
32
|
+
fake_obj = double(filter_sql: 'publish_at')
|
33
|
+
@dummy.apply_date_condition(fake_obj, {simple: 'yesterday'})
|
32
34
|
result = @dummy.instance_variable_get('@relation')
|
33
35
|
expect(result.count).to be 1
|
34
36
|
expect(result[0].id).to be @yesterday.id
|
35
37
|
end
|
36
38
|
|
37
39
|
it "filters for 'this week'" do
|
38
|
-
|
40
|
+
fake_obj = double(filter_sql: 'publish_at')
|
41
|
+
@dummy.apply_date_condition(fake_obj, {simple: 'this_week'})
|
39
42
|
result = @dummy.instance_variable_get('@relation')
|
40
43
|
expect(result.count).to be 4
|
41
44
|
expect(result.map(&:id).sort).to eq [@yesterday.id, @today.id, @week_one.id, @week_two.id].sort
|
42
45
|
end
|
43
46
|
|
44
47
|
it "filters for 'last 7 days'" do
|
45
|
-
|
48
|
+
fake_obj = double(filter_sql: 'publish_at')
|
49
|
+
@dummy.apply_date_condition(fake_obj, {simple: 'last_7_days'})
|
46
50
|
result = @dummy.instance_variable_get('@relation')
|
47
51
|
expect(result.map(&:id).sort).to eq ([@last_seven_days.id, @yesterday.id, @today.id, @week_one.id].sort)
|
48
52
|
end
|
49
53
|
|
50
54
|
it "filters for 'this month'" do
|
51
|
-
|
55
|
+
fake_obj = double(filter_sql: 'publish_at')
|
56
|
+
@dummy.apply_date_condition(fake_obj, {simple: 'this_month'})
|
52
57
|
result = @dummy.instance_variable_get('@relation')
|
53
58
|
expect(result.map(&:id).sort).to eq ([@today.id, @week_two.id, @this_month.id])
|
54
59
|
end
|
55
60
|
|
56
61
|
it "filters for 'last 30 days'" do
|
57
|
-
|
62
|
+
fake_obj = double(filter_sql: 'publish_at')
|
63
|
+
@dummy.apply_date_condition(fake_obj, {simple: 'last_30_days'})
|
58
64
|
result = @dummy.instance_variable_get('@relation')
|
59
65
|
expect(result.map(&:id).sort).to eq ([
|
60
66
|
@last_thirty_days.id, @yesterday.id, @last_seven_days.id, @today.id,
|
@@ -62,11 +68,46 @@ describe Tabulatr::Data::Filtering do
|
|
62
68
|
end
|
63
69
|
|
64
70
|
it "filters from 'start_date' to 'end_date'" do
|
65
|
-
|
71
|
+
fake_obj = double(filter_sql: 'publish_at')
|
72
|
+
@dummy.apply_date_condition(fake_obj, {
|
66
73
|
simple: 'from_to', from: '31.12.2013 15:00',
|
67
74
|
to: '15.01.2014 00:00'})
|
68
75
|
result = @dummy.instance_variable_get('@relation')
|
69
76
|
expect(result.map(&:id)).to eq ([@yesterday.id, @today.id, @week_two.id].sort)
|
70
77
|
end
|
71
78
|
end
|
79
|
+
|
80
|
+
describe '.apply_search' do
|
81
|
+
it 'allows to alter the ActiveRecord::Relation' do
|
82
|
+
@dummy.instance_variable_set('@search',
|
83
|
+
->(query, relation){ relation.joins(:vendor).where(%{vendors.name LIKE '%#{query}%'})})
|
84
|
+
expect{@dummy.apply_search('awesome vendor')}.to_not raise_error
|
85
|
+
sql = @dummy.instance_variable_get('@relation').to_sql
|
86
|
+
expect(sql).to match(/INNER JOIN \"vendors\" ON \"vendors\".\"id\" = \"products\".\"vendor_id\"/)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'allows to provide only one argument' do
|
90
|
+
@dummy.instance_variable_set('@search', ->(query){ nil })
|
91
|
+
expect{@dummy.apply_search('awesome product')}.to_not raise_error
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'allows to return a Hash' do
|
95
|
+
@dummy.instance_variable_set('@search', ->(query){ {title: query} })
|
96
|
+
expect{@dummy.apply_search('awesome product')}.to_not raise_error
|
97
|
+
sql = @dummy.instance_variable_get('@relation').to_sql
|
98
|
+
expect(sql).to match(/WHERE \"products\".\"title\"/)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'allows to return an Array' do
|
102
|
+
@dummy.instance_variable_set('@search', ->(query){["title = ?", query]})
|
103
|
+
expect{@dummy.apply_search('awesome product')}.to_not raise_error
|
104
|
+
sql = @dummy.instance_variable_get('@relation').to_sql
|
105
|
+
expect(sql).to match(/WHERE \(title = 'awesome product'\)/)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'can not be called without a block variable' do
|
109
|
+
@dummy.instance_variable_set('@search', ->{'hi'})
|
110
|
+
expect{@dummy.apply_search('test')}.to raise_error
|
111
|
+
end
|
112
|
+
end
|
72
113
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tabulatr::Data::Formatting do
|
4
|
+
class DummySpecClass
|
5
|
+
include Tabulatr::Data::Formatting
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@dummy = DummySpecClass.new
|
10
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
11
|
+
column = Tabulatr::Renderer::Column.from(
|
12
|
+
name: :title,
|
13
|
+
klass: Product,
|
14
|
+
table_name: :products,
|
15
|
+
sort_sql: "products.title",
|
16
|
+
filter_sql: "products.title"
|
17
|
+
)
|
18
|
+
allow(@dummy).to receive(:table_columns).and_return([column])
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#apply_formats' do
|
22
|
+
it 'applies given formatting block to a column' do
|
23
|
+
allow(@dummy).to receive(:format_row).and_return(nil)
|
24
|
+
p = Product.create!(title: 'title of product')
|
25
|
+
@dummy.table_columns.first.output = ->(record){record.title.upcase}
|
26
|
+
result = @dummy.apply_formats
|
27
|
+
expect(result.count).to be 1
|
28
|
+
expect(result.first[:products][:title]).to eql 'TITLE OF PRODUCT'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tabulatr::Data::Sorting do
|
4
|
+
class DummySpecClass
|
5
|
+
include Tabulatr::Data::Sorting
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@dummy = DummySpecClass.new
|
10
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
11
|
+
@dummy.instance_variable_set('@table_name', 'products')
|
12
|
+
@dummy.instance_variable_set('@base', Product)
|
13
|
+
column = Tabulatr::Renderer::Column.from(
|
14
|
+
name: :title,
|
15
|
+
klass: Product,
|
16
|
+
sort_sql: "products.title",
|
17
|
+
filter_sql: "products.title",
|
18
|
+
table_name: :products
|
19
|
+
)
|
20
|
+
allow(@dummy).to receive(:table_columns).and_return([column])
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.apply_sorting' do
|
24
|
+
|
25
|
+
context 'no sortparam' do
|
26
|
+
|
27
|
+
context 'with no default order given' do
|
28
|
+
it 'sorts by primary_key descending' do
|
29
|
+
@dummy.apply_sorting(nil)
|
30
|
+
expect(@dummy.instance_variable_get('@relation').to_sql)
|
31
|
+
.to match /ORDER BY products.id desc/
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'sortparam given' do
|
37
|
+
context 'sort by column of main table' do
|
38
|
+
context 'sort by "title"' do
|
39
|
+
it 'uses the given sortparam' do
|
40
|
+
@dummy.apply_sorting('products.title desc')
|
41
|
+
expect(@dummy.instance_variable_get('@relation').to_sql)
|
42
|
+
.to match /ORDER BY products.title desc/
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'sort by association column' do
|
48
|
+
it 'sorts by vendor.name' do
|
49
|
+
@dummy.instance_variable_set('@includes', [])
|
50
|
+
assoc = Tabulatr::Renderer::Association.from(
|
51
|
+
name: :name,
|
52
|
+
table_name: :vendor,
|
53
|
+
klass: Product,
|
54
|
+
sort_sql: "vendors.name",
|
55
|
+
filter_sql: "vendors.name"
|
56
|
+
)
|
57
|
+
allow(@dummy).to receive(:table_columns).and_return([assoc])
|
58
|
+
@dummy.apply_sorting('vendor:name desc')
|
59
|
+
expect(@dummy.instance_variable_get('@relation').to_sql)
|
60
|
+
.to match /ORDER BY vendors.name desc/
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'sort by custom sql' do
|
65
|
+
it "sorts by products.title || '' || vendors.name" do
|
66
|
+
@dummy.instance_variable_set('@includes', [])
|
67
|
+
column = Tabulatr::Renderer::Column.from(
|
68
|
+
name: :custom_column,
|
69
|
+
klass: Product,
|
70
|
+
sort_sql: "products.title || '' || vendors.name",
|
71
|
+
filter_sql: "products.title"
|
72
|
+
)
|
73
|
+
allow(@dummy).to receive(:table_columns).and_return([column])
|
74
|
+
@dummy.apply_sorting('custom_column asc')
|
75
|
+
expect(@dummy.instance_variable_get('@relation').to_sql)
|
76
|
+
.to match /ORDER BY products.title \|\| '' \|\| vendors.name asc/
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|