tabulatr2 0.9.20 → 0.9.21
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/.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')
|