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.
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')