tabulatr2 0.9.4 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
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