tabulatr2 0.9.4 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|