tabulatr2 0.9.20 → 0.9.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +4 -0
  5. data/Gemfile +4 -0
  6. data/app/assets/javascripts/tabulatr/_events.js +252 -0
  7. data/app/assets/javascripts/tabulatr/_pagination.js +85 -0
  8. data/app/assets/javascripts/tabulatr/_tabulatr.js +70 -372
  9. data/app/assets/javascripts/tabulatr/application.js +2 -0
  10. data/app/views/tabulatr/_tabulatr_actual_table.html.slim +7 -7
  11. data/app/views/tabulatr/_tabulatr_filter_dialog.html.slim +1 -1
  12. data/app/views/tabulatr/_tabulatr_static_table.html.slim +5 -3
  13. data/lib/tabulatr/data/data.rb +1 -1
  14. data/lib/tabulatr/data/dsl.rb +62 -86
  15. data/lib/tabulatr/data/filtering.rb +32 -52
  16. data/lib/tabulatr/data/sorting.rb +1 -1
  17. data/lib/tabulatr/params_builder.rb +50 -0
  18. data/lib/tabulatr/rails/action_view.rb +2 -2
  19. data/lib/tabulatr/rails/active_record.rb +3 -8
  20. data/lib/tabulatr/renderer/action.rb +1 -1
  21. data/lib/tabulatr/renderer/association.rb +3 -3
  22. data/lib/tabulatr/renderer/buttons.rb +1 -1
  23. data/lib/tabulatr/renderer/column.rb +40 -125
  24. data/lib/tabulatr/renderer/columns_from_block.rb +10 -7
  25. data/lib/tabulatr/renderer/renderer.rb +26 -15
  26. data/lib/tabulatr/version.rb +1 -1
  27. data/lib/tabulatr.rb +1 -0
  28. data/spec/dummy/app/controllers/products_controller.rb +5 -6
  29. data/spec/dummy/app/tabulatr_data/product_tabulatr_data.rb +6 -6
  30. data/spec/dummy/app/views/products/stupid_array.html.erb +20 -6
  31. data/spec/dummy/app/views/products/with_styling.html.erb +1 -1
  32. data/spec/dummy/app/views/products/without_filters.html.erb +1 -0
  33. data/spec/dummy/config/routes.rb +1 -0
  34. data/spec/features/tabulatrs_spec.rb +7 -2
  35. data/spec/lib/tabulatr/data/data_spec.rb +2 -2
  36. data/spec/lib/tabulatr/data/dsl_spec.rb +54 -4
  37. data/spec/lib/tabulatr/data/filtering_spec.rb +164 -7
  38. data/spec/lib/tabulatr/data/formatting_spec.rb +2 -2
  39. data/spec/lib/tabulatr/data/sorting_spec.rb +6 -6
  40. data/spec/lib/tabulatr/params_builder_spec.rb +19 -0
  41. data/spec/lib/tabulatr/renderer/association_spec.rb +29 -0
  42. data/spec/lib/tabulatr/renderer/renderer_spec.rb +8 -0
  43. data/spec/rails_helper.rb +4 -0
  44. 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(opts.merge(klass: klass, table_name: klass.table_name.to_sym, name: name), &block)
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(opts.merge(klass: assoc_klass.try(:klass),
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(opts.merge(klass: klass, filter: false, sortable: false))
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(opts.merge(klass: klass, filter: false, sortable: false), &block)
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
- @columns << Buttons.from(opts.merge(klass: klass, filter: false, sortable: false, output: output), &block)
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.update_options(opts, &block)
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
- if tabulatr_data_class.present?
62
- tdc = tabulatr_data_class.constantize.new(@klass)
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
- result = available_filters.find{|filter| filter.name.to_sym == f.to_sym }
129
- result or raise "Can't find filter '#{f}'"
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'
@@ -22,5 +22,5 @@
22
22
  #++
23
23
 
24
24
  module Tabulatr
25
- VERSION = "0.9.20"
25
+ VERSION = "0.9.21"
26
26
  end
data/lib/tabulatr.rb CHANGED
@@ -37,6 +37,7 @@ require 'tabulatr/engine'
37
37
  require 'tabulatr/renderer/renderer'
38
38
  require 'tabulatr/data/data'
39
39
  require 'tabulatr/json_builder'
40
+ require 'tabulatr/params_builder'
40
41
  require 'tabulatr/generators/railtie' if defined?(Rails)
41
42
 
42
43
  #--
@@ -1,12 +1,7 @@
1
1
  class ProductsController < ApplicationController
2
2
 
3
3
  def simple_index
4
- begin
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, table_column_options: {filter: :range} do "#{record.price} EUR" end # <- Block evaluiert im Kontext EINES Records
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, table_column_options: { filter: :date } do "#{record.updated_at.strftime('%H:%M %d.%m.%Y')}" end
28
- association :vendor, :name, table_column_options: { filter: :exact }
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: 'Dolle Sache'
38
+ s.button :star, product_path(r), label: 'Great product!'
39
39
  s.divider
40
- s.button :'trash-o', product_path(r), label: 'Löschen', class: 'btn-danger', method: :delete, data: {confirm: 'echt?'}
40
+ s.button :'trash-o', product_path(r), label: 'Remove', class: 'btn-danger', method: :delete, data: {confirm: 'are you sure?'}
41
41
  end
42
- "haha!"
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, format: :foo_me
4
- t.column :title, format: ->(a) { bar_me(a) }
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, format: "%08.4f"
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, format: :bar_me
15
- t.association :tags, :title, format: ->(a) { foo_me(a) }
16
- t.association :tags, :count, map: false
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', valign: 'top', wrap: 'nowrap', cell_style: {:'background-color' => 'green'}, header_style: {color: 'orange'}
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 %>
@@ -10,6 +10,7 @@ Rails.application.routes.draw do
10
10
  get :implicit_columns
11
11
  get :with_styling
12
12
  get :local_storage
13
+ get :without_filters
13
14
  end
14
15
  end
15
16
 
@@ -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;vertical-align:top;white-space:nowrap;background-color:green'
338
- expect(header[:style]).to eql 'text-align:left;width:60px;vertical-align:top;white-space:nowrap;color:orange'
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
- sort_sql: "products.title",
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(filter_sql: 'publish_at')
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(filter_sql: 'publish_at')
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(filter_sql: 'publish_at')
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(filter_sql: 'publish_at')
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(filter_sql: 'publish_at')
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(filter_sql: 'publish_at')
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(filter_sql: 'publish_at')
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
- sort_sql: "products.title",
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
- sort_sql: "products.title",
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
- sort_sql: "vendors.name",
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
- sort_sql: "products.title || '' || vendors.name",
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')