tabulatr2 0.9.20 → 0.9.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +17 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/app/assets/javascripts/tabulatr/_events.js +252 -0
- data/app/assets/javascripts/tabulatr/_pagination.js +85 -0
- data/app/assets/javascripts/tabulatr/_tabulatr.js +70 -372
- data/app/assets/javascripts/tabulatr/application.js +2 -0
- data/app/views/tabulatr/_tabulatr_actual_table.html.slim +7 -7
- data/app/views/tabulatr/_tabulatr_filter_dialog.html.slim +1 -1
- data/app/views/tabulatr/_tabulatr_static_table.html.slim +5 -3
- data/lib/tabulatr/data/data.rb +1 -1
- data/lib/tabulatr/data/dsl.rb +62 -86
- data/lib/tabulatr/data/filtering.rb +32 -52
- data/lib/tabulatr/data/sorting.rb +1 -1
- data/lib/tabulatr/params_builder.rb +50 -0
- data/lib/tabulatr/rails/action_view.rb +2 -2
- data/lib/tabulatr/rails/active_record.rb +3 -8
- data/lib/tabulatr/renderer/action.rb +1 -1
- data/lib/tabulatr/renderer/association.rb +3 -3
- data/lib/tabulatr/renderer/buttons.rb +1 -1
- data/lib/tabulatr/renderer/column.rb +40 -125
- data/lib/tabulatr/renderer/columns_from_block.rb +10 -7
- data/lib/tabulatr/renderer/renderer.rb +26 -15
- data/lib/tabulatr/version.rb +1 -1
- data/lib/tabulatr.rb +1 -0
- data/spec/dummy/app/controllers/products_controller.rb +5 -6
- data/spec/dummy/app/tabulatr_data/product_tabulatr_data.rb +6 -6
- data/spec/dummy/app/views/products/stupid_array.html.erb +20 -6
- data/spec/dummy/app/views/products/with_styling.html.erb +1 -1
- data/spec/dummy/app/views/products/without_filters.html.erb +1 -0
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/features/tabulatrs_spec.rb +7 -2
- data/spec/lib/tabulatr/data/data_spec.rb +2 -2
- data/spec/lib/tabulatr/data/dsl_spec.rb +54 -4
- data/spec/lib/tabulatr/data/filtering_spec.rb +164 -7
- data/spec/lib/tabulatr/data/formatting_spec.rb +2 -2
- data/spec/lib/tabulatr/data/sorting_spec.rb +6 -6
- data/spec/lib/tabulatr/params_builder_spec.rb +19 -0
- data/spec/lib/tabulatr/renderer/association_spec.rb +29 -0
- data/spec/lib/tabulatr/renderer/renderer_spec.rb +8 -0
- data/spec/rails_helper.rb +4 -0
- metadata +13 -3
@@ -36,7 +36,7 @@ class Tabulatr::Renderer
|
|
36
36
|
if table_data
|
37
37
|
@columns << fetch_column_from_table_data(klass.table_name.to_sym, name, opts, &block)
|
38
38
|
else
|
39
|
-
@columns << Column.from(
|
39
|
+
@columns << Column.from(klass: klass, table_name: klass.table_name.to_sym, name: name, col_options: Tabulatr::ParamsBuilder.new(opts), &block)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -45,17 +45,17 @@ class Tabulatr::Renderer
|
|
45
45
|
@columns << fetch_column_from_table_data(table_name, name, opts, &block)
|
46
46
|
else
|
47
47
|
assoc_klass = klass.reflect_on_association(table_name.to_sym)
|
48
|
-
@columns << Association.from(
|
49
|
-
name: name, table_name: table_name), &block)
|
48
|
+
@columns << Association.from(klass: assoc_klass.try(:klass),
|
49
|
+
name: name, table_name: table_name, col_options: Tabulatr::ParamsBuilder.new(opts), &block)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
def checkbox(opts={})
|
54
|
-
@columns << Checkbox.from(
|
54
|
+
@columns << Checkbox.from(klass: klass, col_options: Tabulatr::ParamsBuilder.new(opts.merge(filter: false, sortable: false)))
|
55
55
|
end
|
56
56
|
|
57
57
|
def action(opts={}, &block)
|
58
|
-
@columns << Action.from(
|
58
|
+
@columns << Action.from(klass: klass, col_options: Tabulatr::ParamsBuilder.new(opts.merge(filter: false, sortable: false)), &block)
|
59
59
|
end
|
60
60
|
|
61
61
|
def buttons(opts={}, &block)
|
@@ -63,7 +63,8 @@ class Tabulatr::Renderer
|
|
63
63
|
bb = self.instance_exec Tabulatr::Data::ButtonBuilder.new, r, &block
|
64
64
|
self.controller.render_to_string partial: '/tabulatr/tabulatr_buttons', locals: {buttons: bb}, formats: [:html]
|
65
65
|
}
|
66
|
-
|
66
|
+
opts = {filter: false, sortable: false}.merge(opts)
|
67
|
+
@columns << Buttons.from(klass: klass, col_options: Tabulatr::ParamsBuilder.new(opts), output: output, &block)
|
67
68
|
end
|
68
69
|
|
69
70
|
def filter(name, partial: nil, &block)
|
@@ -85,7 +86,9 @@ class Tabulatr::Renderer
|
|
85
86
|
|
86
87
|
def fetch_column_from_table_data table_name, name, opts={}, &block
|
87
88
|
column = table_data.table_columns.find{|tc| tc.table_name == table_name && tc.name == name}
|
88
|
-
column.
|
89
|
+
column.col_options.update(opts)
|
90
|
+
column.output = block if block_given?
|
91
|
+
column
|
89
92
|
end
|
90
93
|
|
91
94
|
def fetch_filter_from_table_data name
|
@@ -58,19 +58,8 @@ class Tabulatr::Renderer
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def build_table(columns, filters, tabulatr_data_class, &block)
|
61
|
-
|
62
|
-
|
63
|
-
else
|
64
|
-
tdc = "#{@klass.name}TabulatrData".constantize.new(@klass)
|
65
|
-
end
|
66
|
-
if block_given?
|
67
|
-
@columns = ColumnsFromBlock.process(@klass, tdc, &block).columns
|
68
|
-
elsif columns.any? || filters.any?
|
69
|
-
@columns = get_requested_columns(tdc.table_columns, columns)
|
70
|
-
@filters = get_requested_filters(tdc.filters, filters)
|
71
|
-
else
|
72
|
-
@columns = tdc.table_columns
|
73
|
-
end
|
61
|
+
tdc = get_data_class(tabulatr_data_class)
|
62
|
+
set_columns_and_filters(tdc, columns, filters, &block)
|
74
63
|
@view.render(partial: '/tabulatr/tabulatr_table', locals: {
|
75
64
|
columns: @columns,
|
76
65
|
table_options: @table_options,
|
@@ -125,11 +114,33 @@ class Tabulatr::Renderer
|
|
125
114
|
|
126
115
|
def get_requested_filters(available_filters, requested_filters)
|
127
116
|
requested_filters.collect do |f|
|
128
|
-
|
129
|
-
|
117
|
+
available_filters.find("Can't find filter '#{f}'") do |filter|
|
118
|
+
filter.name.to_sym == f.to_sym
|
119
|
+
end
|
130
120
|
end.flatten
|
131
121
|
end
|
132
122
|
|
123
|
+
def get_data_class(name = '')
|
124
|
+
if name.present?
|
125
|
+
name.constantize.new(@klass)
|
126
|
+
else
|
127
|
+
"#{@klass.name}TabulatrData".constantize.new(@klass)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def set_columns_and_filters(data_class, columns, filters, &block)
|
132
|
+
if block_given?
|
133
|
+
@columns = ColumnsFromBlock.process(@klass, data_class, &block).columns
|
134
|
+
elsif columns.any?
|
135
|
+
@columns = get_requested_columns(data_class.table_columns, columns)
|
136
|
+
else
|
137
|
+
@columns = data_class.table_columns
|
138
|
+
end
|
139
|
+
if filters && filters.any?
|
140
|
+
@filters = get_requested_filters(data_class.filters, filters)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
133
144
|
end
|
134
145
|
|
135
146
|
require_relative './column'
|
data/lib/tabulatr/version.rb
CHANGED
data/lib/tabulatr.rb
CHANGED
@@ -1,12 +1,7 @@
|
|
1
1
|
class ProductsController < ApplicationController
|
2
2
|
|
3
3
|
def simple_index
|
4
|
-
|
5
|
-
tabulatr_for Product
|
6
|
-
rescue Exception => e
|
7
|
-
puts e.backtrace
|
8
|
-
raise e
|
9
|
-
end
|
4
|
+
tabulatr_for Product
|
10
5
|
end
|
11
6
|
|
12
7
|
def one_item_per_page_with_pagination
|
@@ -58,4 +53,8 @@ class ProductsController < ApplicationController
|
|
58
53
|
raise e
|
59
54
|
end
|
60
55
|
end
|
56
|
+
|
57
|
+
def without_filters
|
58
|
+
tabulatr_for Product
|
59
|
+
end
|
61
60
|
end
|
@@ -9,7 +9,7 @@ class ProductTabulatrData < Tabulatr::Data
|
|
9
9
|
column :title
|
10
10
|
column :id
|
11
11
|
column :status
|
12
|
-
column :price,
|
12
|
+
column :price, filter: :range do "#{record.price} EUR" end
|
13
13
|
column :edit_link do link_to "edit #{record.title}", product_path(record) end
|
14
14
|
# column :name,
|
15
15
|
# sort: "firstname || ' ' || lastname"
|
@@ -24,8 +24,8 @@ class ProductTabulatrData < Tabulatr::Data
|
|
24
24
|
"#{record.title} from #{record.vendor.try(:name)}"
|
25
25
|
end
|
26
26
|
column :active, sortable: false
|
27
|
-
column :updated_at,
|
28
|
-
association :vendor, :name,
|
27
|
+
column :updated_at, filter: :date do "#{record.updated_at.strftime('%H:%M %d.%m.%Y')}" end
|
28
|
+
association :vendor, :name, filter: :exact
|
29
29
|
association :tags, :title do |r|
|
30
30
|
"'#{r.tags.map(&:title).map(&:upcase).join(', ')}'"
|
31
31
|
end
|
@@ -35,10 +35,10 @@ class ProductTabulatrData < Tabulatr::Data
|
|
35
35
|
b.button :eye, product_path(r), class: 'btn-success'
|
36
36
|
b.button :pencil, edit_product_path(r), class: 'btn-warning'
|
37
37
|
b.submenu do |s|
|
38
|
-
s.button :star, product_path(r), label: '
|
38
|
+
s.button :star, product_path(r), label: 'Great product!'
|
39
39
|
s.divider
|
40
|
-
s.button :'trash-o', product_path(r), label: '
|
40
|
+
s.button :'trash-o', product_path(r), label: 'Remove', class: 'btn-danger', method: :delete, data: {confirm: 'are you sure?'}
|
41
41
|
end
|
42
|
-
"
|
42
|
+
"test!"
|
43
43
|
end
|
44
44
|
end
|
@@ -1,9 +1,15 @@
|
|
1
1
|
<%= static_table_for @products do |t|
|
2
2
|
t.column :title
|
3
|
-
t.column :title
|
4
|
-
|
3
|
+
t.column :title do |a|
|
4
|
+
foo_me(a.title)
|
5
|
+
end
|
6
|
+
t.column :title do |a|
|
7
|
+
bar_me(a.title)
|
8
|
+
end
|
5
9
|
t.column :price
|
6
|
-
t.column :price
|
10
|
+
t.column :price do |b|
|
11
|
+
"%08.4f" % b.price
|
12
|
+
end
|
7
13
|
t.column :active
|
8
14
|
t.column :updated_at
|
9
15
|
t.column :updated_at do |r|
|
@@ -11,9 +17,17 @@
|
|
11
17
|
end
|
12
18
|
t.association :vendor, :name
|
13
19
|
t.association :tags, :title
|
14
|
-
t.association :tags, :title
|
15
|
-
|
16
|
-
|
20
|
+
t.association :tags, :title do |record|
|
21
|
+
record.tags.map(&:title).map do |v|
|
22
|
+
bar_me(v)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
t.association :tags, :title do |record|
|
26
|
+
record.tags.map(&:title).map do |v|
|
27
|
+
foo_me(v)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
t.association :tags, :count
|
17
31
|
t.action header: "ACTION!" do |t|
|
18
32
|
t.title.upcase
|
19
33
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<%= table_for Product, :paginate => true do |t|
|
2
2
|
t.checkbox
|
3
|
-
t.column :title, sortable: true, width: '60px', align: 'left',
|
3
|
+
t.column :title, sortable: true, width: '60px', align: 'left', wrap: 'nowrap', data_html: {style: 'background-color: green;'}, header_html: {style: 'color: orange;'}
|
4
4
|
t.column :price, filter: :range
|
5
5
|
t.column :active, sortable: false
|
6
6
|
t.column :vendor_product_name, header: 'Product by vendor'
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= table_for Product, filter: false %>
|
data/spec/dummy/config/routes.rb
CHANGED
@@ -153,6 +153,11 @@ feature "Tabulatr" do
|
|
153
153
|
expect(page).to have_selector('td[data-tabulatr-column-name="vendor:name"]', text: @vendor2.name)
|
154
154
|
end
|
155
155
|
|
156
|
+
scenario "without filters", js: true do
|
157
|
+
visit without_filters_products_path
|
158
|
+
expect(page).to have_no_content('Filter')
|
159
|
+
end
|
160
|
+
|
156
161
|
scenario "filters with range", js: true do
|
157
162
|
n = names.length
|
158
163
|
Product.create!([{title: 'foo', price: 5}, {title: 'bar', price: 17}])
|
@@ -334,8 +339,8 @@ feature "Tabulatr" do
|
|
334
339
|
header = find(".tabulatr_table thead th[data-tabulatr-column-name='products:title']")
|
335
340
|
cell_without_style = find(".tabulatr_table tbody td[data-tabulatr-column-name='products:price']")
|
336
341
|
header_without_style = find(".tabulatr_table thead th[data-tabulatr-column-name='products:price']")
|
337
|
-
expect(cell[:style]).to eql 'text-align:left;width:60px;
|
338
|
-
expect(header[:style]).to eql 'text-align:left;width:60px;
|
342
|
+
expect(cell[:style]).to eql 'background-color: green;text-align: left;width: 60px;white-space: nowrap;'
|
343
|
+
expect(header[:style]).to eql 'color: orange;text-align: left;width: 60px;white-space: nowrap;'
|
339
344
|
expect(cell_without_style[:style]).to be_empty
|
340
345
|
expect(header_without_style[:style]).to be_empty
|
341
346
|
end
|
@@ -3,12 +3,12 @@ require 'rails_helper'
|
|
3
3
|
describe Tabulatr::Data do
|
4
4
|
|
5
5
|
before do
|
6
|
+
col_options = Tabulatr::ParamsBuilder.new(sort_sql: 'products.title', filter_sql: 'products.title')
|
6
7
|
column = Tabulatr::Renderer::Column.from(
|
7
8
|
name: :title,
|
8
9
|
klass: Product,
|
9
10
|
table_name: :products,
|
10
|
-
|
11
|
-
filter_sql: "products.title",
|
11
|
+
col_options: col_options,
|
12
12
|
output: ->(record){record.send(:title)}
|
13
13
|
)
|
14
14
|
allow_any_instance_of(Tabulatr::Data).to receive(:table_columns).and_return([column])
|
@@ -9,14 +9,40 @@ describe Tabulatr::Data::DSL do
|
|
9
9
|
DummyDSLClass.instance_variable_set('@table_columns', [])
|
10
10
|
DummyDSLClass.instance_variable_set('@filters', [])
|
11
11
|
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
12
|
+
DummyDSLClass.instance_variable_set('@target_class', nil)
|
13
|
+
DummyDSLClass.instance_variable_set('@target_class_name', nil)
|
12
14
|
end
|
13
15
|
|
14
16
|
describe '#column' do
|
15
17
|
it 'escapes table and column names' do
|
16
18
|
DummyDSLClass.column(:active)
|
17
19
|
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
18
|
-
expect(table_column.filter_sql).to match(/\"products\".\"active\"/)
|
19
|
-
expect(table_column.sort_sql).to match(/\"products\".\"active\"/)
|
20
|
+
expect(table_column.col_options.filter_sql).to match(/\"products\".\"active\"/)
|
21
|
+
expect(table_column.col_options.sort_sql).to match(/\"products\".\"active\"/)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'uses the sql option as both sort_sql and filter_sql' do
|
25
|
+
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
26
|
+
DummyDSLClass.column(:active, sql: 'products.activated')
|
27
|
+
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
28
|
+
expect(table_column.col_options.filter_sql).to match(/products\.activated/)
|
29
|
+
expect(table_column.col_options.sort_sql).to match(/products\.activated/)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'uses the block as output if given' do
|
33
|
+
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
34
|
+
output = ->(record){record.title}
|
35
|
+
DummyDSLClass.column(:active, &output)
|
36
|
+
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
37
|
+
expect(table_column.output).to eq output
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'uses a standard output if no block is given' do
|
41
|
+
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
42
|
+
DummyDSLClass.column(:title)
|
43
|
+
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
44
|
+
test_obj = double(title: 'Hello world!')
|
45
|
+
expect(table_column.output.call(test_obj)).to eq(test_obj.title)
|
20
46
|
end
|
21
47
|
end
|
22
48
|
|
@@ -24,8 +50,32 @@ describe Tabulatr::Data::DSL do
|
|
24
50
|
it 'escapes table and column names' do
|
25
51
|
DummyDSLClass.association(:vendor, :name)
|
26
52
|
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
27
|
-
expect(table_column.filter_sql).to match(/\"vendors\".\"name\"/)
|
28
|
-
expect(table_column.sort_sql).to match(/\"vendors\".\"name\"/)
|
53
|
+
expect(table_column.col_options.filter_sql).to match(/\"vendors\".\"name\"/)
|
54
|
+
expect(table_column.col_options.sort_sql).to match(/\"vendors\".\"name\"/)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'uses the block as output if given' do
|
58
|
+
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
59
|
+
output = ->(record){ 'test this thing' }
|
60
|
+
DummyDSLClass.association(:vendor, :name, &output)
|
61
|
+
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
62
|
+
expect(table_column.output).to eq output
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'uses a standard output if no block is given' do
|
66
|
+
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
67
|
+
DummyDSLClass.association(:vendor, :name)
|
68
|
+
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
69
|
+
test_obj = double(vendor: double(name: 'Hello world!'))
|
70
|
+
expect(table_column.output.call(test_obj)).to eq(test_obj.vendor.name)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#main_class' do
|
75
|
+
it 'returns the target_class' do
|
76
|
+
DummyDSLClass.instance_variable_set('@target_class', Product)
|
77
|
+
allow(DummyDSLClass).to receive(:target_class_name).and_return('')
|
78
|
+
expect(DummyDSLClass.main_class).to eq(Product)
|
29
79
|
end
|
30
80
|
end
|
31
81
|
|
@@ -6,6 +6,7 @@ describe Tabulatr::Data::Filtering do
|
|
6
6
|
|
7
7
|
def table_columns; []; end
|
8
8
|
def filters; []; end
|
9
|
+
def table_name_for_association(assoc); nil; end
|
9
10
|
end
|
10
11
|
|
11
12
|
describe '.apply_date_condition' do
|
@@ -26,7 +27,8 @@ describe Tabulatr::Data::Filtering do
|
|
26
27
|
|
27
28
|
|
28
29
|
it "filters for 'today'" do
|
29
|
-
fake_obj = double(
|
30
|
+
fake_obj = double()
|
31
|
+
allow(fake_obj).to receive_message_chain('col_options.filter_sql') { 'publish_at'}
|
30
32
|
@dummy.apply_date_condition(fake_obj, {simple: 'today'})
|
31
33
|
result = @dummy.instance_variable_get('@relation')
|
32
34
|
expect(result.count).to be 1
|
@@ -34,7 +36,8 @@ describe Tabulatr::Data::Filtering do
|
|
34
36
|
end
|
35
37
|
|
36
38
|
it "filters for 'yesterday'" do
|
37
|
-
fake_obj = double(
|
39
|
+
fake_obj = double()
|
40
|
+
allow(fake_obj).to receive_message_chain('col_options.filter_sql') { 'publish_at'}
|
38
41
|
@dummy.apply_date_condition(fake_obj, {simple: 'yesterday'})
|
39
42
|
result = @dummy.instance_variable_get('@relation')
|
40
43
|
expect(result.count).to be 1
|
@@ -42,7 +45,8 @@ describe Tabulatr::Data::Filtering do
|
|
42
45
|
end
|
43
46
|
|
44
47
|
it "filters for 'this week'" do
|
45
|
-
fake_obj = double(
|
48
|
+
fake_obj = double()
|
49
|
+
allow(fake_obj).to receive_message_chain('col_options.filter_sql') { 'publish_at'}
|
46
50
|
@dummy.apply_date_condition(fake_obj, {simple: 'this_week'})
|
47
51
|
result = @dummy.instance_variable_get('@relation')
|
48
52
|
expect(result.count).to be 4
|
@@ -50,21 +54,24 @@ describe Tabulatr::Data::Filtering do
|
|
50
54
|
end
|
51
55
|
|
52
56
|
it "filters for 'last 7 days'" do
|
53
|
-
fake_obj = double(
|
57
|
+
fake_obj = double()
|
58
|
+
allow(fake_obj).to receive_message_chain('col_options.filter_sql') { 'publish_at' }
|
54
59
|
@dummy.apply_date_condition(fake_obj, {simple: 'last_7_days'})
|
55
60
|
result = @dummy.instance_variable_get('@relation')
|
56
61
|
expect(result.map(&:id).sort).to eq ([@last_seven_days.id, @yesterday.id, @today.id, @week_one.id].sort)
|
57
62
|
end
|
58
63
|
|
59
64
|
it "filters for 'this month'" do
|
60
|
-
fake_obj = double(
|
65
|
+
fake_obj = double()
|
66
|
+
allow(fake_obj).to receive_message_chain('col_options.filter_sql') { 'publish_at'}
|
61
67
|
@dummy.apply_date_condition(fake_obj, {simple: 'this_month'})
|
62
68
|
result = @dummy.instance_variable_get('@relation')
|
63
69
|
expect(result.map(&:id).sort).to eq ([@today.id, @week_two.id, @this_month.id])
|
64
70
|
end
|
65
71
|
|
66
72
|
it "filters for 'last 30 days'" do
|
67
|
-
fake_obj = double(
|
73
|
+
fake_obj = double()
|
74
|
+
allow(fake_obj).to receive_message_chain('col_options.filter_sql') { 'publish_at'}
|
68
75
|
@dummy.apply_date_condition(fake_obj, {simple: 'last_30_days'})
|
69
76
|
result = @dummy.instance_variable_get('@relation')
|
70
77
|
expect(result.map(&:id).sort).to eq ([
|
@@ -73,13 +80,21 @@ describe Tabulatr::Data::Filtering do
|
|
73
80
|
end
|
74
81
|
|
75
82
|
it "filters from 'start_date' to 'end_date'" do
|
76
|
-
fake_obj = double(
|
83
|
+
fake_obj = double()
|
84
|
+
allow(fake_obj).to receive_message_chain('col_options.filter_sql') { 'publish_at'}
|
77
85
|
@dummy.apply_date_condition(fake_obj, {
|
78
86
|
simple: 'from_to', from: '31.12.2013 15:00',
|
79
87
|
to: '15.01.2014 00:00'})
|
80
88
|
result = @dummy.instance_variable_get('@relation')
|
81
89
|
expect(result.map(&:id)).to eq ([@yesterday.id, @today.id, @week_two.id].sort)
|
82
90
|
end
|
91
|
+
|
92
|
+
it "exits early if condition is 'none'" do
|
93
|
+
relation_before = @dummy.instance_variable_get('@relation')
|
94
|
+
@dummy.apply_date_condition(nil, {simple: 'none'})
|
95
|
+
relation_after = @dummy.instance_variable_get('@relation')
|
96
|
+
expect(relation_after).to eq relation_before
|
97
|
+
end
|
83
98
|
end
|
84
99
|
|
85
100
|
describe '.apply_search' do
|
@@ -120,6 +135,13 @@ describe Tabulatr::Data::Filtering do
|
|
120
135
|
@dummy.instance_variable_set('@search', ->{'hi'})
|
121
136
|
expect{@dummy.apply_search('test')}.to raise_error
|
122
137
|
end
|
138
|
+
|
139
|
+
it 'accepts an array of searchable columns' do
|
140
|
+
@dummy.instance_variable_set('@search', ['title', 'vendors:name'])
|
141
|
+
expect{@dummy.apply_search('awesome product')}.to_not raise_error
|
142
|
+
sql = @dummy.instance_variable_get('@relation').to_sql
|
143
|
+
expect(sql).to match(/WHERE \(\(title LIKE '%awesome%product%'\) OR \(vendors:name LIKE '%awesome%product%'\)\)/)
|
144
|
+
end
|
123
145
|
end
|
124
146
|
|
125
147
|
describe '.apply_filters' do
|
@@ -146,4 +168,139 @@ describe Tabulatr::Data::Filtering do
|
|
146
168
|
@dummy.apply_filters({'custom' => '10'})
|
147
169
|
end
|
148
170
|
end
|
171
|
+
|
172
|
+
describe '.apply_condition' do
|
173
|
+
before(:each) do
|
174
|
+
@dummy = DummyFilteringClass.new
|
175
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'handles `:checkbox`' do
|
179
|
+
expect(@dummy).to receive(:apply_boolean_condition)
|
180
|
+
fake_column = double(filter: :checkbox)
|
181
|
+
@dummy.apply_condition(fake_column, true)
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'handles `:decimal`' do
|
185
|
+
expect(@dummy).to receive(:apply_string_condition)
|
186
|
+
fake_column = double(filter: :decimal)
|
187
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { ''}
|
188
|
+
@dummy.apply_condition(fake_column, 3)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'handles `:integer`' do
|
192
|
+
expect(@dummy).to receive(:apply_string_condition)
|
193
|
+
fake_column = double(filter: :integer)
|
194
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { ''}
|
195
|
+
@dummy.apply_condition(fake_column, 3)
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'handles `:enum`' do
|
199
|
+
expect(@dummy).to receive(:apply_string_condition)
|
200
|
+
fake_column = double(filter: :enum)
|
201
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { ''}
|
202
|
+
@dummy.apply_condition(fake_column, 3)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'handles `:enum_multiselect`' do
|
206
|
+
expect(@dummy).to receive(:apply_array_condition)
|
207
|
+
fake_column = double(filter: :enum_multiselect)
|
208
|
+
@dummy.apply_condition(fake_column, 3)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'handles `:exact`' do
|
212
|
+
expect(@dummy).to receive(:apply_string_condition)
|
213
|
+
fake_column = double(filter: :exact)
|
214
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { ''}
|
215
|
+
@dummy.apply_condition(fake_column, 3)
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'handles a Hash' do
|
219
|
+
expect(@dummy).to receive(:apply_string_condition)
|
220
|
+
fake_column = double(filter: {})
|
221
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { ''}
|
222
|
+
@dummy.apply_condition(fake_column, 3)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'handles an Array' do
|
226
|
+
expect(@dummy).to receive(:apply_string_condition)
|
227
|
+
fake_column = double(filter: [])
|
228
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { ''}
|
229
|
+
@dummy.apply_condition(fake_column, 3)
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'handles `:like`' do
|
233
|
+
expect(@dummy).to receive(:apply_like_condition)
|
234
|
+
fake_column = double(filter: :like)
|
235
|
+
@dummy.apply_condition(fake_column, {like: 'foobar'})
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'handles `:date`' do
|
239
|
+
expect(@dummy).to receive(:apply_date_condition)
|
240
|
+
fake_column = double(filter: :date)
|
241
|
+
@dummy.apply_condition(fake_column, {date: '05/08/2010'})
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'handles `:range`' do
|
245
|
+
expect(@dummy).to receive(:apply_range_condition)
|
246
|
+
fake_column = double(filter: :range)
|
247
|
+
@dummy.apply_condition(fake_column, 2)
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'raises an exception for unknown filter types' do
|
251
|
+
fake_column = double(filter: :foobar, name: 'fake')
|
252
|
+
expect{ @dummy.apply_condition(fake_column, 0) }.to raise_error(/Wrong filter type/)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe '.apply_boolean_condition' do
|
257
|
+
before(:each) do
|
258
|
+
@dummy = DummyFilteringClass.new
|
259
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'applies a boolean condition to the relation' do
|
263
|
+
fake_column = double()
|
264
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { 'products.active'}
|
265
|
+
expect{@dummy.apply_boolean_condition(fake_column, 'true')}.to_not raise_error
|
266
|
+
sql = @dummy.instance_variable_get('@relation').to_sql
|
267
|
+
expect(sql).to match(/WHERE \(products\.active = 't'\)/)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe '.apply_like_condition' do
|
272
|
+
before(:each) do
|
273
|
+
@dummy = DummyFilteringClass.new
|
274
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'applies a LIKE condition to the relation' do
|
278
|
+
fake_column = double()
|
279
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { 'products.title'}
|
280
|
+
expect{@dummy.apply_like_condition(fake_column, 'hello world')}.to_not raise_error
|
281
|
+
sql = @dummy.instance_variable_get('@relation').to_sql
|
282
|
+
expect(sql).to match(/WHERE \(products.title LIKE '%hello world%'\)/)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe '.apply_range_condition' do
|
287
|
+
it 'calls `apply_string_condition` twice' do
|
288
|
+
@dummy = DummyFilteringClass.new
|
289
|
+
fake_column = double()
|
290
|
+
allow(fake_column).to receive_message_chain('col_options.filter_sql') { 'products.price'}
|
291
|
+
expect(@dummy).to receive(:apply_string_condition).twice
|
292
|
+
@dummy.apply_range_condition(fake_column, {from: 2, to: 10.5})
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe '.array_condition' do
|
297
|
+
it 'applies an IN condition to the relation' do
|
298
|
+
@dummy = DummyFilteringClass.new
|
299
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
300
|
+
fake_column = double(table_name: 'products', name: 'id')
|
301
|
+
expect{@dummy.apply_array_condition(fake_column, [19, 9])}.to_not raise_error
|
302
|
+
sql = @dummy.instance_variable_get('@relation').to_sql
|
303
|
+
expect(sql).to match(/WHERE \"products\".\"id\" IN \(19, 9\)/)
|
304
|
+
end
|
305
|
+
end
|
149
306
|
end
|
@@ -9,12 +9,12 @@ describe Tabulatr::Data::Formatting do
|
|
9
9
|
before(:each) do
|
10
10
|
@dummy = DummyFormattingClass.new
|
11
11
|
@dummy.instance_variable_set('@relation', Product.all)
|
12
|
+
col_options = Tabulatr::ParamsBuilder.new(sort_sql: 'products.title', filter_sql: 'products.title')
|
12
13
|
column = Tabulatr::Renderer::Column.from(
|
13
14
|
name: :title,
|
14
15
|
klass: Product,
|
15
16
|
table_name: :products,
|
16
|
-
|
17
|
-
filter_sql: "products.title"
|
17
|
+
col_options: col_options
|
18
18
|
)
|
19
19
|
allow(@dummy).to receive(:table_columns).and_return([column])
|
20
20
|
end
|
@@ -11,11 +11,11 @@ describe Tabulatr::Data::Sorting do
|
|
11
11
|
@dummy.instance_variable_set('@relation', Product.all)
|
12
12
|
@dummy.instance_variable_set('@table_name', 'products')
|
13
13
|
@dummy.instance_variable_set('@base', Product)
|
14
|
+
col_options = Tabulatr::ParamsBuilder.new(sort_sql: 'products.title', filter_sql: 'products.title')
|
14
15
|
column = Tabulatr::Renderer::Column.from(
|
15
16
|
name: :title,
|
16
17
|
klass: Product,
|
17
|
-
|
18
|
-
filter_sql: "products.title",
|
18
|
+
col_options: col_options,
|
19
19
|
table_name: :products
|
20
20
|
)
|
21
21
|
allow(@dummy).to receive(:table_columns).and_return([column])
|
@@ -48,12 +48,12 @@ describe Tabulatr::Data::Sorting do
|
|
48
48
|
context 'sort by association column' do
|
49
49
|
it 'sorts by vendor.name' do
|
50
50
|
@dummy.instance_variable_set('@includes', [])
|
51
|
+
col_options = Tabulatr::ParamsBuilder.new(sort_sql: 'vendors.name', filter_sql: 'vendors.name')
|
51
52
|
assoc = Tabulatr::Renderer::Association.from(
|
52
53
|
name: :name,
|
53
54
|
table_name: :vendor,
|
54
55
|
klass: Product,
|
55
|
-
|
56
|
-
filter_sql: "vendors.name"
|
56
|
+
col_options: col_options
|
57
57
|
)
|
58
58
|
allow(@dummy).to receive(:table_columns).and_return([assoc])
|
59
59
|
@dummy.apply_sorting('vendor:name desc')
|
@@ -65,11 +65,11 @@ describe Tabulatr::Data::Sorting do
|
|
65
65
|
context 'sort by custom sql' do
|
66
66
|
it "sorts by products.title || '' || vendors.name" do
|
67
67
|
@dummy.instance_variable_set('@includes', [])
|
68
|
+
col_options = Tabulatr::ParamsBuilder.new(sort_sql: "products.title || '' || vendors.name", filter_sql: 'products.title')
|
68
69
|
column = Tabulatr::Renderer::Column.from(
|
69
70
|
name: :custom_column,
|
70
71
|
klass: Product,
|
71
|
-
|
72
|
-
filter_sql: "products.title"
|
72
|
+
col_options: col_options
|
73
73
|
)
|
74
74
|
allow(@dummy).to receive(:table_columns).and_return([column])
|
75
75
|
@dummy.apply_sorting('custom_column asc')
|