ajax-datatables-rails 0.4.3 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +120 -0
  3. data/.rubocop.yml +17 -7
  4. data/Appraisals +15 -20
  5. data/CHANGELOG.md +54 -1
  6. data/Gemfile +0 -5
  7. data/Guardfile +16 -0
  8. data/README.md +238 -112
  9. data/Rakefile +1 -0
  10. data/ajax-datatables-rails.gemspec +24 -20
  11. data/bin/_guard-core +29 -0
  12. data/bin/appraisal +29 -0
  13. data/bin/bundle +114 -0
  14. data/bin/guard +29 -0
  15. data/bin/rake +29 -0
  16. data/bin/rspec +29 -0
  17. data/bin/rubocop +29 -0
  18. data/doc/migrate.md +97 -0
  19. data/doc/webpack.md +7 -2
  20. data/gemfiles/{rails_5.2.0.gemfile → rails_5.2.4.gemfile} +3 -5
  21. data/gemfiles/{rails_5.0.7.gemfile → rails_6.0.3.gemfile} +4 -6
  22. data/gemfiles/{rails_5.1.6.gemfile → rails_6.1.0.gemfile} +4 -6
  23. data/lib/ajax-datatables-rails.rb +12 -1
  24. data/lib/ajax-datatables-rails/active_record.rb +7 -0
  25. data/lib/ajax-datatables-rails/base.rb +47 -46
  26. data/lib/ajax-datatables-rails/datatable.rb +6 -0
  27. data/lib/ajax-datatables-rails/datatable/column.rb +65 -20
  28. data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +12 -21
  29. data/lib/ajax-datatables-rails/datatable/column/order.rb +1 -1
  30. data/lib/ajax-datatables-rails/datatable/column/search.rb +37 -22
  31. data/lib/ajax-datatables-rails/datatable/datatable.rb +16 -7
  32. data/lib/ajax-datatables-rails/datatable/simple_order.rb +23 -10
  33. data/lib/ajax-datatables-rails/datatable/simple_search.rb +2 -0
  34. data/lib/ajax-datatables-rails/error.rb +9 -0
  35. data/lib/ajax-datatables-rails/orm.rb +6 -0
  36. data/lib/ajax-datatables-rails/orm/active_record.rb +11 -12
  37. data/lib/ajax-datatables-rails/version.rb +13 -1
  38. data/lib/generators/rails/templates/datatable.rb +1 -1
  39. data/spec/ajax-datatables-rails/base_spec.rb +129 -93
  40. data/spec/ajax-datatables-rails/datatable/column_spec.rb +105 -37
  41. data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +71 -31
  42. data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +36 -14
  43. data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +4 -2
  44. data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +315 -272
  45. data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +9 -8
  46. data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +17 -14
  47. data/spec/factories/user.rb +3 -1
  48. data/spec/install_oracle.sh +9 -3
  49. data/spec/spec_helper.rb +33 -28
  50. data/spec/support/datatables/complex_datatable.rb +31 -0
  51. data/spec/support/datatables/complex_datatable_array.rb +16 -0
  52. data/spec/support/{datatable_cond_date.rb → datatables/datatable_cond_date.rb} +2 -0
  53. data/spec/support/{datatable_cond_numeric.rb → datatables/datatable_cond_numeric.rb} +3 -1
  54. data/spec/support/{datatable_cond_proc.rb → datatables/datatable_cond_proc.rb} +2 -0
  55. data/spec/support/{datatable_cond_string.rb → datatables/datatable_cond_string.rb} +9 -1
  56. data/spec/support/datatables/datatable_cond_unknown.rb +7 -0
  57. data/spec/support/{datatable_order_nulls_last.rb → datatables/datatable_order_nulls_last.rb} +2 -0
  58. data/spec/support/{test_helpers.rb → helpers/params.rb} +17 -42
  59. data/spec/support/{test_models.rb → models/user.rb} +2 -0
  60. data/spec/support/schema.rb +3 -1
  61. metadata +76 -75
  62. data/.travis.yml +0 -80
  63. data/gemfiles/rails_4.0.13.gemfile +0 -14
  64. data/gemfiles/rails_4.1.16.gemfile +0 -14
  65. data/gemfiles/rails_4.2.10.gemfile +0 -14
  66. data/lib/ajax-datatables-rails/config.rb +0 -31
  67. data/lib/ajax_datatables_rails.rb +0 -15
  68. data/lib/generators/datatable/config_generator.rb +0 -19
  69. data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -12
  70. data/spec/ajax-datatables-rails/configuration_spec.rb +0 -43
  71. data/spec/ajax-datatables-rails/extended_spec.rb +0 -20
  72. data/spec/ajax-datatables-rails/orm/active_record_spec.rb +0 -25
@@ -1,58 +1,58 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe AjaxDatatablesRails::Datatable::Column do
5
+ RSpec.describe AjaxDatatablesRails::Datatable::Column do
4
6
 
5
- let(:view) { double('view', params: sample_params) }
6
- let(:datatable) { ComplexDatatable.new(view) }
7
+ let(:datatable) { ComplexDatatable.new(sample_params) }
7
8
 
8
9
  describe 'username column' do
9
10
 
10
11
  let(:column) { datatable.datatable.columns.first }
11
12
 
12
- before do
13
- datatable.params[:columns] = {'0'=>{'data'=>'username', 'name'=>'', 'searchable'=>'true', 'orderable'=>'true', 'search'=>{'value'=>'searchvalue', 'regex'=>'false'}}}
14
- end
13
+ before { datatable.params[:columns]['0'][:search][:value] = 'searchvalue' }
15
14
 
16
- it 'should be orderable' do
15
+ it 'is orderable' do
17
16
  expect(column.orderable?).to eq(true)
18
17
  end
19
18
 
20
- it 'should sort nulls last' do
19
+ it 'sorts nulls last' do
21
20
  expect(column.nulls_last?).to eq(false)
22
21
  end
23
22
 
24
- it 'should be searchable' do
23
+ it 'is searchable' do
25
24
  expect(column.searchable?).to eq(true)
26
25
  end
27
26
 
28
- it 'should be searched' do
27
+ it 'is searched' do
29
28
  expect(column.searched?).to eq(true)
30
29
  end
31
30
 
32
- it 'should have connected to id column' do
31
+ it 'has connected to id column' do
33
32
  expect(column.data).to eq('username')
34
33
  end
35
34
 
36
35
  describe '#data' do
37
- it 'should return the data from params' do
36
+ it 'returns the data from params' do
38
37
  expect(column.data).to eq 'username'
39
38
  end
40
39
  end
41
40
 
42
41
  describe '#source' do
43
- it 'should return the data source from view_column' do
42
+ it 'returns the data source from view_column' do
44
43
  expect(column.source).to eq 'User.username'
45
44
  end
46
45
  end
47
46
 
48
47
  describe '#table' do
49
48
  context 'with ActiveRecord ORM' do
50
- it 'should return the corresponding AR table' do
49
+ it 'returns the corresponding AR table' do
51
50
  expect(column.table).to eq User.arel_table
52
51
  end
53
52
  end
53
+
54
54
  context 'with other ORM' do
55
- it 'should return the corresponding model' do
55
+ it 'returns the corresponding model' do
56
56
  expect(User).to receive(:respond_to?).with(:arel_table).and_return(false)
57
57
  expect(column.table).to eq User
58
58
  end
@@ -60,19 +60,19 @@ describe AjaxDatatablesRails::Datatable::Column do
60
60
  end
61
61
 
62
62
  describe '#model' do
63
- it 'should return the corresponding AR model' do
63
+ it 'returns the corresponding AR model' do
64
64
  expect(column.model).to eq User
65
65
  end
66
66
  end
67
67
 
68
68
  describe '#field' do
69
- it 'should return the corresponding field in DB' do
69
+ it 'returns the corresponding field in DB' do
70
70
  expect(column.field).to eq :username
71
71
  end
72
72
  end
73
73
 
74
74
  describe '#custom_field?' do
75
- it 'should return false if field is bound to an AR field' do
75
+ it 'returns false if field is bound to an AR field' do
76
76
  expect(column.custom_field?).to be false
77
77
  end
78
78
  end
@@ -82,73 +82,141 @@ describe AjaxDatatablesRails::Datatable::Column do
82
82
  expect(column.search).to be_a(AjaxDatatablesRails::Datatable::SimpleSearch)
83
83
  end
84
84
 
85
- it 'should have search value' do
85
+ it 'has search value' do
86
86
  expect(column.search.value).to eq('searchvalue')
87
87
  end
88
88
 
89
- it 'should not regex' do
89
+ it 'does not regex' do
90
90
  expect(column.search.regexp?).to eq false
91
91
  end
92
92
  end
93
93
 
94
94
  describe '#cond' do
95
- it 'should be :like by default' do
95
+ it 'is :like by default' do
96
96
  expect(column.cond).to eq(:like)
97
97
  end
98
98
  end
99
99
 
100
100
  describe '#source' do
101
- it 'should be :like by default' do
101
+ it 'is :like by default' do
102
102
  expect(column.source).to eq('User.username')
103
103
  end
104
104
  end
105
105
 
106
106
  describe '#search_query' do
107
- it 'should buld search query' do
107
+ it 'bulds search query' do
108
108
  expect(column.search_query.to_sql).to include('%searchvalue%')
109
109
  end
110
110
  end
111
111
 
112
112
  describe '#sort_query' do
113
- it 'should build sort query' do
113
+ it 'builds sort query' do
114
114
  expect(column.sort_query).to eq('users.username')
115
115
  end
116
116
  end
117
117
 
118
118
  describe '#use_regex?' do
119
- it 'should be true by default' do
119
+ it 'is true by default' do
120
120
  expect(column.use_regex?).to be true
121
121
  end
122
122
  end
123
123
 
124
- unless AjaxDatatablesRails.old_rails?
125
- describe '#delimiter' do
126
- it 'should be - by default' do
127
- expect(column.delimiter).to eq('-')
128
- end
124
+ describe '#delimiter' do
125
+ it 'is - by default' do
126
+ expect(column.delimiter).to eq('-')
129
127
  end
130
128
  end
131
129
  end
132
130
 
133
- describe '#formater' do
134
- let(:datatable) { DatatableWithFormater.new(view) }
131
+ describe '#formatter' do
132
+ let(:datatable) { DatatableWithFormater.new(sample_params) }
135
133
  let(:column) { datatable.datatable.columns.find { |c| c.data == 'last_name' } }
136
134
 
137
- it 'should be a proc' do
138
- expect(column.formater).to be_a(Proc)
135
+ it 'is a proc' do
136
+ expect(column.formatter).to be_a(Proc)
139
137
  end
140
138
  end
141
139
 
142
140
  describe '#filter' do
143
- let(:datatable) { DatatableCondProc.new(view) }
141
+ let(:datatable) { DatatableCondProc.new(sample_params) }
144
142
  let(:column) { datatable.datatable.columns.find { |c| c.data == 'username' } }
145
143
 
146
- it 'should be a proc' do
144
+ it 'is a proc' do
147
145
  config = column.instance_variable_get('@view_column')
148
146
  filter = config[:cond]
149
147
  expect(filter).to be_a(Proc)
150
- expect(filter).to receive(:call).with(column, column.formated_value)
148
+ expect(filter).to receive(:call).with(column, column.formatted_value)
151
149
  column.filter
152
150
  end
153
151
  end
152
+
153
+ describe '#type_cast' do
154
+ let(:column) { datatable.datatable.columns.first }
155
+
156
+ it 'returns VARCHAR if :db_adapter is :pg' do
157
+ expect(datatable).to receive(:db_adapter) { :pg }
158
+ expect(column.send(:type_cast)).to eq('VARCHAR')
159
+ end
160
+
161
+ it 'returns VARCHAR if :db_adapter is :postgre' do
162
+ expect(datatable).to receive(:db_adapter) { :postgre }
163
+ expect(column.send(:type_cast)).to eq('VARCHAR')
164
+ end
165
+
166
+ it 'returns VARCHAR if :db_adapter is :postgresql' do
167
+ expect(datatable).to receive(:db_adapter) { :postgresql }
168
+ expect(column.send(:type_cast)).to eq('VARCHAR')
169
+ end
170
+
171
+ it 'returns VARCHAR2(4000) if :db_adapter is :oracle' do
172
+ expect(datatable).to receive(:db_adapter) { :oracle }
173
+ expect(column.send(:type_cast)).to eq('VARCHAR2(4000)')
174
+ end
175
+
176
+ it 'returns VARCHAR2(4000) if :db_adapter is :oracleenhanced' do
177
+ expect(datatable).to receive(:db_adapter) { :oracleenhanced }
178
+ expect(column.send(:type_cast)).to eq('VARCHAR2(4000)')
179
+ end
180
+
181
+ it 'returns CHAR if :db_adapter is :mysql2' do
182
+ expect(datatable).to receive(:db_adapter) { :mysql2 }
183
+ expect(column.send(:type_cast)).to eq('CHAR')
184
+ end
185
+
186
+ it 'returns CHAR if :db_adapter is :mysql' do
187
+ expect(datatable).to receive(:db_adapter) { :mysql }
188
+ expect(column.send(:type_cast)).to eq('CHAR')
189
+ end
190
+
191
+ it 'returns TEXT if :db_adapter is :sqlite' do
192
+ expect(datatable).to receive(:db_adapter) { :sqlite }
193
+ expect(column.send(:type_cast)).to eq('TEXT')
194
+ end
195
+
196
+ it 'returns TEXT if :db_adapter is :sqlite3' do
197
+ expect(datatable).to receive(:db_adapter) { :sqlite3 }
198
+ expect(column.send(:type_cast)).to eq('TEXT')
199
+ end
200
+
201
+ it 'returns VARCHAR(4000) if :db_adapter is :sqlserver' do
202
+ expect(datatable).to receive(:db_adapter) { :sqlserver }
203
+ expect(column.send(:type_cast)).to eq('VARCHAR(4000)')
204
+ end
205
+ end
206
+
207
+ describe 'when empty column' do
208
+ before { datatable.params[:columns]['0'][:data] = '' }
209
+
210
+ it 'raises error' do
211
+ expect { datatable.to_json }.to raise_error(AjaxDatatablesRails::Error::InvalidSearchColumn).with_message('Unknown column. Check that `data` field is filled on JS side with the column name')
212
+ end
213
+ end
214
+
215
+ describe 'when unknown column' do
216
+ before { datatable.params[:columns]['0'][:data] = 'foo' }
217
+
218
+ it 'raises error' do
219
+ expect { datatable.to_json }.to raise_error(AjaxDatatablesRails::Error::InvalidSearchColumn).with_message("Check that column 'foo' exists in view_columns")
220
+ end
221
+ end
154
222
  end
@@ -1,22 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe AjaxDatatablesRails::Datatable::Datatable do
5
+ RSpec.describe AjaxDatatablesRails::Datatable::Datatable do
4
6
 
5
- let(:view) { double('view', params: sample_params) }
6
- let(:datatable) { ComplexDatatable.new(view).datatable }
7
- let(:order_option) { {'0'=>{'column'=>'0', 'dir'=>'asc'}, '1'=>{'column'=>'1', 'dir'=>'desc'}} }
7
+ let(:datatable) { ComplexDatatable.new(sample_params).datatable }
8
+ let(:datatable_json) { ComplexDatatable.new(sample_params_json).datatable }
9
+ let(:order_option) { { '0' => { 'column' => '0', 'dir' => 'asc' }, '1' => { 'column' => '1', 'dir' => 'desc' } } }
10
+ let(:order_option_json) { [{ 'column' => '0', 'dir' => 'asc' }, { 'column' => '1', 'dir' => 'desc' }] }
8
11
 
9
- describe 'order methods' do
10
- it 'should be orderable' do
12
+ shared_examples 'order methods' do
13
+ it 'is orderable' do
11
14
  expect(datatable.orderable?).to eq(true)
12
15
  end
13
16
 
14
- it 'should not be orderable' do
17
+ it 'is not orderable' do
15
18
  datatable.options[:order] = nil
16
19
  expect(datatable.orderable?).to eq(false)
17
20
  end
18
21
 
19
- it 'should have 2 orderable columns' do
22
+ it 'has 2 orderable columns' do
20
23
  datatable.options[:order] = order_option
21
24
  expect(datatable.orders.count).to eq(2)
22
25
  end
@@ -36,13 +39,35 @@ describe AjaxDatatablesRails::Datatable::Datatable do
36
39
  end
37
40
  end
38
41
 
42
+ shared_examples 'columns methods' do
43
+ it 'has 4 columns' do
44
+ expect(datatable.columns.count).to eq(6)
45
+ end
46
+
47
+ it 'child class' do
48
+ expect(datatable.columns.first).to be_a(AjaxDatatablesRails::Datatable::Column)
49
+ end
50
+ end
51
+
52
+ describe 'with query params' do
53
+ it_behaves_like 'order methods'
54
+ it_behaves_like 'columns methods'
55
+ end
56
+
57
+ describe 'with json params' do
58
+ let(:order_option) { order_option_json }
59
+ let(:datatable) { datatable_json }
60
+ it_behaves_like 'order methods'
61
+ it_behaves_like 'columns methods'
62
+ end
63
+
39
64
  describe 'search methods' do
40
- it 'should be searchable' do
65
+ it 'is searchable' do
41
66
  datatable.options[:search][:value] = 'atom'
42
67
  expect(datatable.searchable?).to eq(true)
43
68
  end
44
69
 
45
- it 'should not be searchable' do
70
+ it 'is not searchable' do
46
71
  datatable.options[:search][:value] = nil
47
72
  expect(datatable.searchable?).to eq(false)
48
73
  end
@@ -52,36 +77,51 @@ describe AjaxDatatablesRails::Datatable::Datatable do
52
77
  end
53
78
  end
54
79
 
55
- describe 'columns methods' do
56
- it 'should have 4 columns' do
57
- expect(datatable.columns.count).to eq(6)
80
+ describe 'option methods' do
81
+ describe '#paginate?' do
82
+ it {
83
+ expect(datatable.paginate?).to be(true)
84
+ }
58
85
  end
59
86
 
60
- it 'child class' do
61
- expect(datatable.columns.first).to be_a(AjaxDatatablesRails::Datatable::Column)
62
- end
63
- end
87
+ describe '#per_page' do
88
+ context 'when params[:length] is missing' do
89
+ it 'defaults to 10' do
90
+ expect(datatable.per_page).to eq(10)
91
+ end
92
+ end
64
93
 
65
- describe 'option methods' do
66
- before :each do
67
- datatable.options[:start] = '50'
68
- datatable.options[:length] = '15'
69
- end
94
+ context 'when params[:length] is passed' do
95
+ let(:datatable) { ComplexDatatable.new({ length: '20' }).datatable }
70
96
 
71
- it 'paginate?' do
72
- expect(datatable.paginate?).to be(true)
97
+ it 'matches the value on view params[:length]' do
98
+ expect(datatable.per_page).to eq(20)
99
+ end
100
+ end
73
101
  end
74
102
 
75
- it 'offset' do
76
- expect(datatable.offset).to eq(50)
77
- end
103
+ describe '#offset' do
104
+ context 'when params[:start] is missing' do
105
+ it 'defaults to 0' do
106
+ expect(datatable.offset).to eq(0)
107
+ end
108
+ end
109
+
110
+ context 'when params[:start] is passed' do
111
+ let(:datatable) { ComplexDatatable.new({ start: '11' }).datatable }
78
112
 
79
- it 'page' do
80
- expect(datatable.page).to eq(4)
113
+ it 'matches the value on view params[:start]' do
114
+ expect(datatable.offset).to eq(11)
115
+ end
116
+ end
81
117
  end
82
118
 
83
- it 'per_page' do
84
- expect(datatable.per_page).to eq(15)
119
+ describe '#page' do
120
+ let(:datatable) { ComplexDatatable.new({ start: '11' }).datatable }
121
+
122
+ it 'calculates page number from params[:start] and #per_page' do
123
+ expect(datatable.page).to eq(2)
124
+ end
85
125
  end
86
126
  end
87
127
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe AjaxDatatablesRails::Datatable::SimpleOrder do
5
+ RSpec.describe AjaxDatatablesRails::Datatable::SimpleOrder do
4
6
 
5
- let(:view) { double('view', params: sample_params) }
6
- let(:datatable) { ComplexDatatable.new(view).datatable }
7
- let(:options) { ActiveSupport::HashWithIndifferentAccess.new({'column' => '1', 'dir' => 'desc'}) }
7
+ let(:parent) { ComplexDatatable.new(sample_params) }
8
+ let(:datatable) { parent.datatable }
9
+ let(:options) { ActiveSupport::HashWithIndifferentAccess.new({ 'column' => '1', 'dir' => 'desc' }) }
8
10
  let(:simple_order) { AjaxDatatablesRails::Datatable::SimpleOrder.new(datatable, options) }
9
11
 
10
12
  describe 'option methods' do
@@ -14,27 +16,47 @@ describe AjaxDatatablesRails::Datatable::SimpleOrder do
14
16
  end
15
17
 
16
18
  describe 'option methods with nulls last' do
17
- describe 'using global option' do
18
- before { AjaxDatatablesRails.config.nulls_last = true }
19
- after { AjaxDatatablesRails.config.nulls_last = false }
19
+ describe 'using class option' do
20
+ before { parent.nulls_last = true }
21
+ after { parent.nulls_last = false }
20
22
 
21
23
  it 'sql query' do
24
+ skip('unsupported database adapter') if ENV['DB_ADAPTER'] == 'oracle_enhanced'
25
+
22
26
  expect(simple_order.query('email')).to eq(
23
- 'CASE WHEN email IS NULL THEN 1 ELSE 0 END, email DESC'
27
+ "email DESC #{nulls_last_sql(parent)}"
24
28
  )
25
29
  end
26
30
  end
27
31
 
28
32
  describe 'using column option' do
29
- let(:sorted_datatable) { DatatableOrderNullsLast.new(view).datatable }
33
+ let(:parent) { DatatableOrderNullsLast.new(sample_params) }
34
+ let(:sorted_datatable) { parent.datatable }
30
35
  let(:nulls_last_order) { AjaxDatatablesRails::Datatable::SimpleOrder.new(sorted_datatable, options) }
31
36
 
32
- it 'sql query' do
33
- expect(nulls_last_order.query('email')).to eq(
34
- 'CASE WHEN email IS NULL THEN 1 ELSE 0 END, email DESC'
35
- )
37
+ context 'with postgres database adapter' do
38
+ before { parent.db_adapter = :pg }
39
+
40
+ it 'sql query' do
41
+ expect(nulls_last_order.query('email')).to eq('email DESC NULLS LAST')
42
+ end
43
+ end
44
+
45
+ context 'with sqlite database adapter' do
46
+ before { parent.db_adapter = :sqlite }
47
+
48
+ it 'sql query' do
49
+ expect(nulls_last_order.query('email')).to eq('email DESC IS NULL')
50
+ end
51
+ end
52
+
53
+ context 'with mysql database adapter' do
54
+ before { parent.db_adapter = :mysql }
55
+
56
+ it 'sql query' do
57
+ expect(nulls_last_order.query('email')).to eq('email DESC IS NULL')
58
+ end
36
59
  end
37
60
  end
38
61
  end
39
-
40
62
  end