tabulatr2 0.9.4 → 0.9.6

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/Gemfile +1 -2
  4. data/README.md +155 -95
  5. data/app/assets/javascripts/tabulatr/_storage.js +41 -0
  6. data/app/assets/javascripts/tabulatr/_tabulatr.js +598 -0
  7. data/app/assets/javascripts/tabulatr/application.js +3 -553
  8. data/app/assets/stylesheets/tabulatr/application.css.scss +21 -12
  9. data/app/assets/stylesheets/tabulatr.css +1 -0
  10. data/app/views/tabulatr/_tabulatr_actual_table.html.slim +18 -18
  11. data/app/views/tabulatr/_tabulatr_filter_dialog.html.slim +1 -1
  12. data/app/views/tabulatr/_tabulatr_fuzzy_search_field.html.slim +1 -1
  13. data/app/views/tabulatr/_tabulatr_static_table.html.slim +3 -3
  14. data/app/views/tabulatr/_tabulatr_table.html.slim +17 -12
  15. data/lib/tabulatr/data/data.rb +7 -9
  16. data/lib/tabulatr/data/dsl.rb +36 -21
  17. data/lib/tabulatr/data/filtering.rb +41 -13
  18. data/lib/tabulatr/data/formatting.rb +7 -20
  19. data/lib/tabulatr/data/pagination.rb +1 -2
  20. data/lib/tabulatr/data/proxy.rb +2 -0
  21. data/lib/tabulatr/data/sorting.rb +24 -13
  22. data/lib/tabulatr/engine.rb +1 -0
  23. data/lib/tabulatr/generators/tabulatr/templates/tabulatr.yml +2 -2
  24. data/lib/tabulatr/json_builder.rb +23 -25
  25. data/lib/tabulatr/rails/action_controller.rb +4 -0
  26. data/lib/tabulatr/rails/action_view.rb +3 -2
  27. data/lib/tabulatr/renderer/checkbox.rb +3 -1
  28. data/lib/tabulatr/renderer/column.rb +47 -5
  29. data/lib/tabulatr/renderer/columns_from_block.rb +24 -6
  30. data/lib/tabulatr/renderer/renderer.rb +26 -17
  31. data/lib/tabulatr/utility/unexpected_search_result_error.rb +9 -0
  32. data/lib/tabulatr/utility/utility.rb +4 -0
  33. data/lib/tabulatr/version.rb +1 -1
  34. data/spec/dummy/app/controllers/products_controller.rb +9 -0
  35. data/spec/dummy/app/views/products/local_storage.html.slim +4 -0
  36. data/spec/dummy/app/views/products/simple_index.html.erb +1 -1
  37. data/spec/dummy/app/views/products/stupid_array.html.erb +1 -1
  38. data/spec/dummy/config/application.rb +1 -1
  39. data/spec/dummy/config/locales/tabulatr.yml +2 -2
  40. data/spec/dummy/config/routes.rb +1 -0
  41. data/spec/features/tabulatrs_spec.rb +27 -27
  42. data/spec/lib/tabulatr/data/data_spec.rb +12 -16
  43. data/spec/lib/tabulatr/data/filtering_spec.rb +48 -7
  44. data/spec/lib/tabulatr/data/formatting_spec.rb +32 -0
  45. data/spec/lib/tabulatr/data/sorting_spec.rb +81 -0
  46. data/spec/lib/tabulatr/json_builder_spec.rb +23 -9
  47. data/spec/lib/tabulatr/renderer/checkbox_spec.rb +14 -0
  48. data/spec/lib/tabulatr/renderer/renderer_spec.rb +20 -8
  49. data/tabulatr.gemspec +4 -3
  50. metadata +45 -9
  51. data/lib/tabulatr/data/column_name_builder.rb +0 -86
@@ -23,19 +23,30 @@
23
23
 
24
24
  class Tabulatr::Renderer
25
25
  class ColumnsFromBlock
26
- attr_accessor :columns, :klass
26
+ attr_accessor :columns, :klass, :table_data
27
27
 
28
- def initialize(klass)
28
+ def initialize(klass, table_data_object)
29
29
  @klass = klass
30
+ @table_data = table_data_object
30
31
  @columns ||= []
31
32
  end
32
33
 
33
34
  def column(name, opts={}, &block)
34
- @columns << Column.from(opts.merge(klass: klass, name: name), &block)
35
+ if table_data
36
+ @columns << fetch_column_from_table_data(klass.table_name.to_sym, name, opts, &block)
37
+ else
38
+ @columns << Column.from(opts.merge(klass: klass, table_name: klass.table_name.to_sym, name: name), &block)
39
+ end
35
40
  end
36
41
 
37
42
  def association(table_name, name, opts={}, &block)
38
- @columns << Association.from(opts.merge(klass: klass, name: name, table_name: table_name), &block)
43
+ if table_data
44
+ @columns << fetch_column_from_table_data(table_name, name, opts, &block)
45
+ else
46
+ assoc_klass = klass.reflect_on_association(table_name.to_sym)
47
+ @columns << Association.from(opts.merge(klass: assoc_klass.try(:klass),
48
+ name: name, table_name: table_name), &block)
49
+ end
39
50
  end
40
51
 
41
52
  def checkbox(opts={})
@@ -46,11 +57,18 @@ class Tabulatr::Renderer
46
57
  @columns << Action.from(opts.merge(klass: klass, filter: false, sortable: false), &block)
47
58
  end
48
59
 
49
- def self.process(klass, &block)
50
- i = self.new(klass)
60
+ def self.process(klass, table_data_object = nil, &block)
61
+ i = self.new(klass, table_data_object)
51
62
  yield(i)
52
63
  c = i.columns
53
64
  c
54
65
  end
66
+
67
+ private
68
+
69
+ def fetch_column_from_table_data table_name, name, opts={}, &block
70
+ column = table_data.table_columns.find{|tc| tc.table_name == table_name && tc.name == name}
71
+ column.update_options(opts, &block)
72
+ end
55
73
  end
56
74
  end
@@ -32,7 +32,10 @@ class Tabulatr::Renderer
32
32
  batch_actions: false, # :name => value hash of batch action stuff
33
33
  footer_content: false, # if given, add a <%= content_for <footer_content> %> before the </table>
34
34
  path: '#', # where to send the AJAX-requests to
35
- order_by: nil) # default order
35
+ order_by: nil, # default order
36
+ html_class: '',
37
+ pagination_position: :top,
38
+ persistent: true)
36
39
  @klass = klass
37
40
  @view = view
38
41
  @table_options = {
@@ -44,21 +47,27 @@ class Tabulatr::Renderer
44
47
  batch_actions: batch_actions,
45
48
  footer_content: footer_content,
46
49
  path: path,
47
- order_by: order_by
50
+ order_by: order_by,
51
+ html_class: 'table tabulatr_table '.concat(html_class),
52
+ pagination_position: pagination_position,
53
+ persistent: paginate ? persistent : false
48
54
  }
49
55
  @classname = @klass.name.underscore
50
56
  end
51
57
 
52
- def build_table(columns, &block)
53
- tdc = "#{@klass.name}TabulatrData".constantize.new(@klass)
58
+ def build_table(columns, tabulatr_data_class, &block)
59
+ if tabulatr_data_class.present?
60
+ tdc = tabulatr_data_class.constantize.new(@klass)
61
+ else
62
+ tdc = "#{@klass.name}TabulatrData".constantize.new(@klass)
63
+ end
54
64
  if block_given?
55
- @columns = ColumnsFromBlock.process @klass, &block
65
+ @columns = ColumnsFromBlock.process @klass, tdc, &block
56
66
  elsif columns.any?
57
67
  @columns = get_requested_columns(tdc.table_columns, columns)
58
68
  else
59
69
  @columns = tdc.table_columns
60
70
  end
61
-
62
71
  @view.render(partial: '/tabulatr/tabulatr_table', locals: {
63
72
  columns: @columns,
64
73
  table_options: @table_options,
@@ -66,7 +75,7 @@ class Tabulatr::Renderer
66
75
  classname: @classname,
67
76
  tabulatr_data: tdc,
68
77
  table_id: generate_id,
69
- formatted_name: formatted_name
78
+ formatted_name: Tabulatr::Utility.formatted_name(@klass.name)
70
79
  })
71
80
  end
72
81
 
@@ -83,11 +92,7 @@ class Tabulatr::Renderer
83
92
  end
84
93
 
85
94
  def generate_id
86
- "#{formatted_name}_table_#{SecureRandom.uuid}"
87
- end
88
-
89
- def formatted_name
90
- "#{@klass.to_s.gsub(/::/, '--').downcase}"
95
+ "#{Tabulatr::Utility.formatted_name(@klass.name)}_table_#{@view.controller.controller_name}_#{@view.controller.action_name}_#{@view.instance_variable_get(:@_tabulatr_table_index)}"
91
96
  end
92
97
 
93
98
  def self.build_static_table(records, view, toptions={}, &block)
@@ -96,16 +101,21 @@ class Tabulatr::Renderer
96
101
  new(klass, view, toptions).build_static_table(records, &block)
97
102
  end
98
103
 
99
- def self.build_table(klass, view, toptions={}, columns, &block)
100
- new(klass, view, toptions).build_table(columns, &block)
104
+ def self.build_table(klass, view, toptions={}, columns, tabulatr_data_class, &block)
105
+ new(klass, view, toptions).build_table(columns, tabulatr_data_class, &block)
101
106
  end
102
107
 
103
108
  private
104
109
 
105
110
  def get_requested_columns(available_columns, requested_columns)
111
+ main_table_name = @klass.table_name.to_sym
106
112
  requested_columns.collect do |r|
107
- r = "#{r.keys.first}:#{r.values.first}" if r.is_a?(Hash) && r.count == 1
108
- available_columns.select{|column| column.full_name.to_sym == r.to_sym }
113
+ if r.is_a?(Hash) && r.count == 1
114
+ r = "#{r.keys.first}:#{r.values.first}"
115
+ end
116
+ result = available_columns.find{|column| column.full_name.to_sym == r.to_sym }
117
+ result = available_columns.find{|column| column.name.to_sym == r.to_sym && column.table_name == main_table_name} if result.nil?
118
+ result
109
119
  end.flatten
110
120
  end
111
121
 
@@ -116,4 +126,3 @@ require_relative './association'
116
126
  require_relative './action'
117
127
  require_relative './checkbox'
118
128
  require_relative './columns_from_block'
119
-
@@ -0,0 +1,9 @@
1
+ module Tabulatr
2
+ class UnexpectedSearchResultError < StandardError
3
+
4
+ def self.raise_error(klass)
5
+ raise self, "Your search block returned a '#{klass}'.\n
6
+ You need to return a String, a Hash, an Array or an ActiveRecord::Relation instead."
7
+ end
8
+ end
9
+ end
@@ -43,4 +43,8 @@ module Tabulatr::Utility
43
43
  false
44
44
  end
45
45
  end
46
+
47
+ def self.formatted_name class_name
48
+ "#{class_name.gsub(/::/, '--').downcase}"
49
+ end
46
50
  end
@@ -22,5 +22,5 @@
22
22
  #++
23
23
 
24
24
  module Tabulatr
25
- VERSION = "0.9.4"
25
+ VERSION = "0.9.6"
26
26
  end
@@ -49,4 +49,13 @@ class ProductsController < ApplicationController
49
49
  def implicit_columns
50
50
  tabulatr_for Product
51
51
  end
52
+
53
+ def local_storage
54
+ begin
55
+ tabulatr_for Product
56
+ rescue Exception => e
57
+ puts e.backtrace
58
+ raise e
59
+ end
60
+ end
52
61
  end
@@ -0,0 +1,4 @@
1
+ = table_for Product, :paginate => true, persistent: true, pagesize: 2,
2
+ batch_actions: {a: "Hallo", b: "Du da!"},
3
+ columns: [:title, :price, :active, :vendor_product_name, :updated_at,
4
+ {vendor: :name}, 'tags:title']
@@ -1,4 +1,4 @@
1
- <%= table_for Product, :paginate => true,
1
+ <%= table_for Product, paginate: true, persistent: false,
2
2
  batch_actions: {a: "Hallo", b: "Du da!"},
3
3
  columns: [:title, :price, :active, :vendor_product_name, :updated_at,
4
4
  {vendor: :name}, 'tags:title'] %>
@@ -7,7 +7,7 @@
7
7
  t.column :active
8
8
  t.column :updated_at
9
9
  t.column :updated_at do |r|
10
- r.updated_at.strftime('%d.%M.%Y')
10
+ r.updated_at.strftime('%d.%m.%Y')
11
11
  end
12
12
  t.association :vendor, :name
13
13
  t.association :tags, :title
@@ -1,6 +1,7 @@
1
1
  require File.expand_path('../boot', __FILE__)
2
2
 
3
3
  require 'rails/all'
4
+ require 'font-awesome-rails'
4
5
 
5
6
  Bundler.require(*Rails.groups)
6
7
 
@@ -20,4 +21,3 @@ module Dummy
20
21
  # config.i18n.default_locale = :de
21
22
  end
22
23
  end
23
-
@@ -5,7 +5,7 @@ en:
5
5
  batch_actions: 'Batch actions'
6
6
  count: 'Showing: %{current} of total %{total}. %{per_page} items per page.'
7
7
  apply_filters: 'Apply'
8
- search: 'Search'
8
+ search: 'Search...'
9
9
  date_filter:
10
10
  none: ''
11
11
  today: "Today"
@@ -27,7 +27,7 @@ de:
27
27
  batch_actions: 'Batch-Aktionen'
28
28
  count: 'Zeige %{current} von insgesamt %{total}. %{per_page} pro Seite.'
29
29
  apply_filters: 'Anwenden'
30
- search: 'Suche'
30
+ search: 'Suche...'
31
31
  date_filter:
32
32
  none: ''
33
33
  today: "Heute"
@@ -9,6 +9,7 @@ Rails.application.routes.draw do
9
9
  get :with_batch_actions
10
10
  get :implicit_columns
11
11
  get :with_styling
12
+ get :local_storage
12
13
  end
13
14
  end
14
15
 
@@ -100,7 +100,7 @@ describe "Tabulatr" do
100
100
  Product.create!(:title => "test #{i}")
101
101
  end
102
102
  visit one_item_per_page_with_pagination_products_path
103
- page.all('.pagination li a').count.should eq 5
103
+ page.all('.pagination li a[data-page]').count.should eq 5
104
104
  end
105
105
 
106
106
  it 'shows some pages when there are 20', js: true do
@@ -108,7 +108,7 @@ describe "Tabulatr" do
108
108
  Product.create!
109
109
  end
110
110
  visit one_item_per_page_with_pagination_products_path
111
- pages = page.all('.pagination li a').map{|a| a['data-page'].to_i}
111
+ pages = page.all('.pagination li a[data-page]').map{|a| a['data-page'].to_i}
112
112
  pages.should eq [1,2,3,10,20]
113
113
  end
114
114
  end
@@ -136,21 +136,21 @@ describe "Tabulatr" do
136
136
  expect(find('.dropdown-menu').visible?)
137
137
  find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
138
138
  within(".tabulatr_filter_form") do
139
- fill_in("product_filter[title][like]", with: "ore")
139
+ fill_in("product_filter[products:title][like]", with: "ore")
140
140
  expect{find('#title_like').visible?}.to be_true
141
141
  find_button("Apply").trigger('click')
142
142
  end
143
- expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'lorem')
144
- expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'labore')
145
- expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'dolore')
143
+ expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'lorem')
144
+ expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'labore')
145
+ expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'dolore')
146
146
 
147
147
  within(".tabulatr_filter_form") do
148
- fill_in("product_filter[title][like]", :with => "loreem")
148
+ fill_in("product_filter[products:title][like]", :with => "loreem")
149
149
  find_button("Apply").trigger('click')
150
150
  end
151
- expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'lorem')
152
- expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'labore')
153
- expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'dolore')
151
+ expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'lorem')
152
+ expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'labore')
153
+ expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'dolore')
154
154
  end
155
155
 
156
156
  it "filters", js: true do
@@ -178,15 +178,15 @@ describe "Tabulatr" do
178
178
  end
179
179
  find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
180
180
  within('.tabulatr_filter_form') do
181
- fill_in("product_filter[price][from]", :with => 4)
182
- fill_in("product_filter[price][to]", :with => 10)
181
+ fill_in("product_filter[products:price][from]", :with => 4)
182
+ fill_in("product_filter[products:price][to]", :with => 10)
183
183
  find_button("Apply").trigger('click')
184
184
  end
185
185
  page.find(".tabulatr_table tbody tr[data-id='#{Product.first.id}']").should have_content('foo')
186
186
  page.has_no_css?(".tabulatr_table tbody tr[data-id='#{Product.last.id}']")
187
187
  within('.tabulatr_filter_form') do
188
- fill_in("product_filter[price][from]", :with => 12)
189
- fill_in("product_filter[price][to]", :with => 19)
188
+ fill_in("product_filter[products:price][from]", :with => 12)
189
+ fill_in("product_filter[products:price][to]", :with => 19)
190
190
  find_button("Apply").trigger('click')
191
191
  end
192
192
  page.should have_selector(".tabulatr_table tbody tr[data-id='#{Product.last.id}']")
@@ -203,19 +203,19 @@ describe "Tabulatr" do
203
203
  expect(find('.dropdown-menu').visible?)
204
204
  find(".tabulatr-filter-menu-wrapper a.btn").trigger('click')
205
205
  within(".tabulatr_filter_form") do
206
- fill_in("product_filter[title][like]", with: "foo")
207
- expect(find('#title_like').visible?)
206
+ fill_in("product_filter[products:title][like]", with: "foo")
207
+ # expect(find('#products--title_like').visible?)
208
208
  find_button("Apply").trigger('click')
209
209
  end
210
210
  # expect(page).to have_content('foo')
211
211
  # expect(page).to have_no_content('bar')
212
- expect(page).not_to have_selector('td[data-tabulatr-column-name="title"]', text: 'bar')
213
- expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'foo')
214
- find("a[data-hide-table-filter='title']").trigger('click')
212
+ expect(page).not_to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'bar')
213
+ expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'foo')
214
+ find("a[data-hide-table-filter='products:title']").trigger('click')
215
215
  # expect(page).to have_content('foo')
216
216
  # expect(page).to have_content('bar')
217
- expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'bar')
218
- expect(page).to have_selector('td[data-tabulatr-column-name="title"]', text: 'foo')
217
+ expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'bar')
218
+ expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'foo')
219
219
  end
220
220
  end
221
221
 
@@ -231,14 +231,14 @@ describe "Tabulatr" do
231
231
  page.should have_content names[l-i]
232
232
  end
233
233
  within('.tabulatr_table thead') do
234
- find('th[data-tabulatr-column-name=title]').click
234
+ find('th[data-tabulatr-column-name="products:title"]').click
235
235
  end
236
236
  snames = names.sort
237
237
  (1..10).each do |i|
238
238
  page.should have_content snames[i-1]
239
239
  end
240
240
  within('.tabulatr_table thead') do
241
- find('th[data-tabulatr-column-name=title]').click
241
+ find('th[data-tabulatr-column-name="products:title"]').click
242
242
  end
243
243
  (1..10).each do |i|
244
244
  page.should have_content snames[-i]
@@ -303,10 +303,10 @@ describe "Tabulatr" do
303
303
  it 'applys the given style' do
304
304
  p = Product.create!(:title => names[0], :active => true, :price => 10.0)
305
305
  visit with_styling_products_path
306
- cell = find(".tabulatr_table tbody td[data-tabulatr-column-name='title']")
307
- header = find(".tabulatr_table thead th[data-tabulatr-column-name='title']")
308
- cell_without_style = find(".tabulatr_table tbody td[data-tabulatr-column-name='price']")
309
- header_without_style = find(".tabulatr_table thead th[data-tabulatr-column-name='price']")
306
+ cell = find(".tabulatr_table tbody td[data-tabulatr-column-name='products:title']")
307
+ header = find(".tabulatr_table thead th[data-tabulatr-column-name='products:title']")
308
+ cell_without_style = find(".tabulatr_table tbody td[data-tabulatr-column-name='products:price']")
309
+ header_without_style = find(".tabulatr_table thead th[data-tabulatr-column-name='products:price']")
310
310
  expect(cell[:style]).to eql 'text-align:left;width:60px;vertical-align:top;white-space:nowrap;background-color:green'
311
311
  expect(header[:style]).to eql 'text-align:left;width:60px;vertical-align:top;white-space:nowrap;color:orange'
312
312
  expect(cell_without_style[:style]).to be_empty
@@ -3,8 +3,15 @@ require 'spec_helper'
3
3
  describe Tabulatr::Data do
4
4
 
5
5
  before do
6
- Tabulatr::Data.any_instance.stub_chain(:table_columns, :klass=).and_return(Product)
7
- Tabulatr::Data.any_instance.stub_chain(:table_columns, :map).as_null_object
6
+ column = Tabulatr::Renderer::Column.from(
7
+ name: :title,
8
+ klass: Product,
9
+ table_name: :products,
10
+ sort_sql: "products.title",
11
+ filter_sql: "products.title",
12
+ output: ->(record){record.send(:title)}
13
+ )
14
+ Tabulatr::Data.any_instance.stub(:table_columns).and_return([column])
8
15
  end
9
16
 
10
17
  it 'prefilters the result' do
@@ -17,24 +24,13 @@ describe Tabulatr::Data do
17
24
  it 'uses default order' do
18
25
  Product.create([{title: 'foo', price: 5}, {title: 'bar', price: 10}, {title: 'fuzz', price: 7}])
19
26
 
20
- cols = {
21
- title: {
22
- name: 'title',
23
- sort_sql: nil,
24
- filter_sql: nil,
25
- output: nil,
26
- table_column: Tabulatr::Renderer::Column.from(name: 'title', klass: Product)
27
- }
28
- }
29
- Tabulatr::Data.instance_variable_set('@columns', cols)
30
27
  td = Tabulatr::Data.new(Product)
31
- # mod_params = example_params.merge(product_sort: 'products.title DESC')
32
- # raise mod_params.inspect
33
- records = td.data_for_table(HashWithIndifferentAccess.new(example_params.merge(product_sort: 'products.title DESC')))
28
+ records = td.data_for_table(HashWithIndifferentAccess.new(example_params.merge(product_sort: 'title DESC')))
34
29
  expect(records.count).to eql 3
35
30
  titles = ['fuzz', 'foo', 'bar']
31
+ # raise records.inspect
36
32
  records.each_with_index do |r, ix|
37
- expect(r[:title]).to eql titles[ix]
33
+ expect(r[:products][:title]).to eql titles[ix]
38
34
  end
39
35
  end
40
36
  end
@@ -21,40 +21,46 @@ describe Tabulatr::Data::Filtering do
21
21
  end
22
22
  describe '.apply_date_condition' do
23
23
  it "filters for 'today'" do
24
- @dummy.apply_date_condition('publish_at', {simple: 'today'})
24
+ fake_obj = double(filter_sql: 'publish_at')
25
+ @dummy.apply_date_condition(fake_obj, {simple: 'today'})
25
26
  result = @dummy.instance_variable_get('@relation')
26
27
  expect(result.count).to be 1
27
28
  expect(result[0].id).to be @today.id
28
29
  end
29
30
 
30
31
  it "filters for 'yesterday'" do
31
- @dummy.apply_date_condition('publish_at', {simple: 'yesterday'})
32
+ fake_obj = double(filter_sql: 'publish_at')
33
+ @dummy.apply_date_condition(fake_obj, {simple: 'yesterday'})
32
34
  result = @dummy.instance_variable_get('@relation')
33
35
  expect(result.count).to be 1
34
36
  expect(result[0].id).to be @yesterday.id
35
37
  end
36
38
 
37
39
  it "filters for 'this week'" do
38
- @dummy.apply_date_condition('publish_at', {simple: 'this_week'})
40
+ fake_obj = double(filter_sql: 'publish_at')
41
+ @dummy.apply_date_condition(fake_obj, {simple: 'this_week'})
39
42
  result = @dummy.instance_variable_get('@relation')
40
43
  expect(result.count).to be 4
41
44
  expect(result.map(&:id).sort).to eq [@yesterday.id, @today.id, @week_one.id, @week_two.id].sort
42
45
  end
43
46
 
44
47
  it "filters for 'last 7 days'" do
45
- @dummy.apply_date_condition('publish_at', {simple: 'last_7_days'})
48
+ fake_obj = double(filter_sql: 'publish_at')
49
+ @dummy.apply_date_condition(fake_obj, {simple: 'last_7_days'})
46
50
  result = @dummy.instance_variable_get('@relation')
47
51
  expect(result.map(&:id).sort).to eq ([@last_seven_days.id, @yesterday.id, @today.id, @week_one.id].sort)
48
52
  end
49
53
 
50
54
  it "filters for 'this month'" do
51
- @dummy.apply_date_condition('publish_at', {simple: 'this_month'})
55
+ fake_obj = double(filter_sql: 'publish_at')
56
+ @dummy.apply_date_condition(fake_obj, {simple: 'this_month'})
52
57
  result = @dummy.instance_variable_get('@relation')
53
58
  expect(result.map(&:id).sort).to eq ([@today.id, @week_two.id, @this_month.id])
54
59
  end
55
60
 
56
61
  it "filters for 'last 30 days'" do
57
- @dummy.apply_date_condition('publish_at', {simple: 'last_30_days'})
62
+ fake_obj = double(filter_sql: 'publish_at')
63
+ @dummy.apply_date_condition(fake_obj, {simple: 'last_30_days'})
58
64
  result = @dummy.instance_variable_get('@relation')
59
65
  expect(result.map(&:id).sort).to eq ([
60
66
  @last_thirty_days.id, @yesterday.id, @last_seven_days.id, @today.id,
@@ -62,11 +68,46 @@ describe Tabulatr::Data::Filtering do
62
68
  end
63
69
 
64
70
  it "filters from 'start_date' to 'end_date'" do
65
- @dummy.apply_date_condition('publish_at', {
71
+ fake_obj = double(filter_sql: 'publish_at')
72
+ @dummy.apply_date_condition(fake_obj, {
66
73
  simple: 'from_to', from: '31.12.2013 15:00',
67
74
  to: '15.01.2014 00:00'})
68
75
  result = @dummy.instance_variable_get('@relation')
69
76
  expect(result.map(&:id)).to eq ([@yesterday.id, @today.id, @week_two.id].sort)
70
77
  end
71
78
  end
79
+
80
+ describe '.apply_search' do
81
+ it 'allows to alter the ActiveRecord::Relation' do
82
+ @dummy.instance_variable_set('@search',
83
+ ->(query, relation){ relation.joins(:vendor).where(%{vendors.name LIKE '%#{query}%'})})
84
+ expect{@dummy.apply_search('awesome vendor')}.to_not raise_error
85
+ sql = @dummy.instance_variable_get('@relation').to_sql
86
+ expect(sql).to match(/INNER JOIN \"vendors\" ON \"vendors\".\"id\" = \"products\".\"vendor_id\"/)
87
+ end
88
+
89
+ it 'allows to provide only one argument' do
90
+ @dummy.instance_variable_set('@search', ->(query){ nil })
91
+ expect{@dummy.apply_search('awesome product')}.to_not raise_error
92
+ end
93
+
94
+ it 'allows to return a Hash' do
95
+ @dummy.instance_variable_set('@search', ->(query){ {title: query} })
96
+ expect{@dummy.apply_search('awesome product')}.to_not raise_error
97
+ sql = @dummy.instance_variable_get('@relation').to_sql
98
+ expect(sql).to match(/WHERE \"products\".\"title\"/)
99
+ end
100
+
101
+ it 'allows to return an Array' do
102
+ @dummy.instance_variable_set('@search', ->(query){["title = ?", query]})
103
+ expect{@dummy.apply_search('awesome product')}.to_not raise_error
104
+ sql = @dummy.instance_variable_get('@relation').to_sql
105
+ expect(sql).to match(/WHERE \(title = 'awesome product'\)/)
106
+ end
107
+
108
+ it 'can not be called without a block variable' do
109
+ @dummy.instance_variable_set('@search', ->{'hi'})
110
+ expect{@dummy.apply_search('test')}.to raise_error
111
+ end
112
+ end
72
113
  end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tabulatr::Data::Formatting do
4
+ class DummySpecClass
5
+ include Tabulatr::Data::Formatting
6
+ end
7
+
8
+ before(:each) do
9
+ @dummy = DummySpecClass.new
10
+ @dummy.instance_variable_set('@relation', Product.all)
11
+ column = Tabulatr::Renderer::Column.from(
12
+ name: :title,
13
+ klass: Product,
14
+ table_name: :products,
15
+ sort_sql: "products.title",
16
+ filter_sql: "products.title"
17
+ )
18
+ allow(@dummy).to receive(:table_columns).and_return([column])
19
+ end
20
+
21
+ describe '#apply_formats' do
22
+ it 'applies given formatting block to a column' do
23
+ allow(@dummy).to receive(:format_row).and_return(nil)
24
+ p = Product.create!(title: 'title of product')
25
+ @dummy.table_columns.first.output = ->(record){record.title.upcase}
26
+ result = @dummy.apply_formats
27
+ expect(result.count).to be 1
28
+ expect(result.first[:products][:title]).to eql 'TITLE OF PRODUCT'
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tabulatr::Data::Sorting do
4
+ class DummySpecClass
5
+ include Tabulatr::Data::Sorting
6
+ end
7
+
8
+ before(:each) do
9
+ @dummy = DummySpecClass.new
10
+ @dummy.instance_variable_set('@relation', Product.all)
11
+ @dummy.instance_variable_set('@table_name', 'products')
12
+ @dummy.instance_variable_set('@base', Product)
13
+ column = Tabulatr::Renderer::Column.from(
14
+ name: :title,
15
+ klass: Product,
16
+ sort_sql: "products.title",
17
+ filter_sql: "products.title",
18
+ table_name: :products
19
+ )
20
+ allow(@dummy).to receive(:table_columns).and_return([column])
21
+ end
22
+
23
+ describe '.apply_sorting' do
24
+
25
+ context 'no sortparam' do
26
+
27
+ context 'with no default order given' do
28
+ it 'sorts by primary_key descending' do
29
+ @dummy.apply_sorting(nil)
30
+ expect(@dummy.instance_variable_get('@relation').to_sql)
31
+ .to match /ORDER BY products.id desc/
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'sortparam given' do
37
+ context 'sort by column of main table' do
38
+ context 'sort by "title"' do
39
+ it 'uses the given sortparam' do
40
+ @dummy.apply_sorting('products.title desc')
41
+ expect(@dummy.instance_variable_get('@relation').to_sql)
42
+ .to match /ORDER BY products.title desc/
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'sort by association column' do
48
+ it 'sorts by vendor.name' do
49
+ @dummy.instance_variable_set('@includes', [])
50
+ assoc = Tabulatr::Renderer::Association.from(
51
+ name: :name,
52
+ table_name: :vendor,
53
+ klass: Product,
54
+ sort_sql: "vendors.name",
55
+ filter_sql: "vendors.name"
56
+ )
57
+ allow(@dummy).to receive(:table_columns).and_return([assoc])
58
+ @dummy.apply_sorting('vendor:name desc')
59
+ expect(@dummy.instance_variable_get('@relation').to_sql)
60
+ .to match /ORDER BY vendors.name desc/
61
+ end
62
+ end
63
+
64
+ context 'sort by custom sql' do
65
+ it "sorts by products.title || '' || vendors.name" do
66
+ @dummy.instance_variable_set('@includes', [])
67
+ column = Tabulatr::Renderer::Column.from(
68
+ name: :custom_column,
69
+ klass: Product,
70
+ sort_sql: "products.title || '' || vendors.name",
71
+ filter_sql: "products.title"
72
+ )
73
+ allow(@dummy).to receive(:table_columns).and_return([column])
74
+ @dummy.apply_sorting('custom_column asc')
75
+ expect(@dummy.instance_variable_get('@relation').to_sql)
76
+ .to match /ORDER BY products.title \|\| '' \|\| vendors.name asc/
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end