ajax-datatables-rails 0.3.1 → 0.4.0

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +26 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +1157 -0
  6. data/.travis.yml +68 -0
  7. data/Appraisals +34 -0
  8. data/Gemfile +5 -1
  9. data/LICENSE +17 -18
  10. data/README.md +239 -239
  11. data/Rakefile +1 -1
  12. data/ajax-datatables-rails.gemspec +31 -24
  13. data/gemfiles/rails_4.0.13.gemfile +14 -0
  14. data/gemfiles/rails_4.1.15.gemfile +14 -0
  15. data/gemfiles/rails_4.2.8.gemfile +13 -0
  16. data/gemfiles/rails_5.0.3.gemfile +13 -0
  17. data/gemfiles/rails_5.1.1.gemfile +13 -0
  18. data/lib/ajax-datatables-rails.rb +9 -8
  19. data/lib/ajax-datatables-rails/base.rb +80 -156
  20. data/lib/ajax-datatables-rails/config.rb +8 -5
  21. data/lib/ajax-datatables-rails/datatable/column.rb +169 -0
  22. data/lib/ajax-datatables-rails/datatable/column_date_filter.rb +41 -0
  23. data/lib/ajax-datatables-rails/datatable/datatable.rb +79 -0
  24. data/lib/ajax-datatables-rails/datatable/simple_order.rb +31 -0
  25. data/lib/ajax-datatables-rails/datatable/simple_search.rb +18 -0
  26. data/lib/ajax-datatables-rails/orm/active_record.rb +52 -0
  27. data/lib/ajax-datatables-rails/version.rb +1 -1
  28. data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +3 -3
  29. data/lib/generators/rails/datatable_generator.rb +7 -19
  30. data/lib/generators/rails/templates/datatable.rb +26 -14
  31. data/spec/ajax-datatables-rails/base_spec.rb +190 -0
  32. data/spec/ajax-datatables-rails/configuration_spec.rb +43 -0
  33. data/spec/ajax-datatables-rails/datatable/column_spec.rb +109 -0
  34. data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +87 -0
  35. data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +13 -0
  36. data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +17 -0
  37. data/spec/ajax-datatables-rails/extended_spec.rb +20 -0
  38. data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +439 -0
  39. data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +66 -0
  40. data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +34 -0
  41. data/spec/ajax-datatables-rails/orm/active_record_spec.rb +25 -0
  42. data/spec/factories/user.rb +9 -0
  43. data/spec/install_oracle.sh +12 -0
  44. data/spec/spec_helper.rb +75 -3
  45. data/spec/support/schema.rb +14 -0
  46. data/spec/support/test_helpers.rb +174 -0
  47. data/spec/support/test_models.rb +2 -0
  48. metadata +169 -37
  49. data/lib/ajax-datatables-rails/extensions/kaminari.rb +0 -12
  50. data/lib/ajax-datatables-rails/extensions/simple_paginator.rb +0 -12
  51. data/lib/ajax-datatables-rails/extensions/will_paginate.rb +0 -12
  52. data/lib/ajax-datatables-rails/models.rb +0 -6
  53. data/spec/ajax-datatables-rails/ajax_datatables_rails_spec.rb +0 -351
  54. data/spec/ajax-datatables-rails/kaminari_spec.rb +0 -35
  55. data/spec/ajax-datatables-rails/models_spec.rb +0 -10
  56. data/spec/ajax-datatables-rails/simple_paginator_spec.rb +0 -32
  57. data/spec/ajax-datatables-rails/will_paginate_spec.rb +0 -28
  58. data/spec/schema.rb +0 -35
  59. data/spec/test_models.rb +0 -21
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe AjaxDatatablesRails::Datatable::SimpleOrder do
4
+
5
+ let(:options) { ActiveSupport::HashWithIndifferentAccess.new({'column'=>'1', 'dir'=>'desc'}) }
6
+ let(:simple_order) { AjaxDatatablesRails::Datatable::SimpleOrder.new(nil, options) }
7
+
8
+ describe 'option methods' do
9
+ it 'sql query' do
10
+ expect(simple_order.query('firstname')).to eq('firstname DESC')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe AjaxDatatablesRails::Datatable::SimpleSearch do
4
+
5
+ let(:options) { ActiveSupport::HashWithIndifferentAccess.new({'value'=>'search value', 'regex'=>'true'}) }
6
+ let(:simple_search) { AjaxDatatablesRails::Datatable::SimpleSearch.new(options) }
7
+
8
+ describe 'option methods' do
9
+ it 'regexp?' do
10
+ expect(simple_search.regexp?).to be(true)
11
+ end
12
+
13
+ it 'value' do
14
+ expect(simple_search.value).to eq('search value')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe AjaxDatatablesRails::Base do
4
+ let(:view) { double('view', params: sample_params) }
5
+ let(:datatable) { ReallyComplexDatatable.new(view) }
6
+
7
+ describe 'it can transform search value before asking the database' do
8
+ before(:each) do
9
+ create(:user, username: 'johndoe', email: 'johndoe@example.com', last_name: 'DOE')
10
+ create(:user, username: 'msmith', email: 'mary.smith@example.com', last_name: 'SMITH')
11
+ datatable.params[:columns]['3'][:search][:value] = 'doe'
12
+ end
13
+
14
+ it 'should filter records' do
15
+ expect(datatable.data.size).to eq 1
16
+ item = datatable.data.first
17
+ expect(item[:last_name]).to eq 'DOE'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,439 @@
1
+ require 'spec_helper'
2
+
3
+ describe AjaxDatatablesRails::ORM::ActiveRecord do
4
+
5
+ let(:view) { double('view', params: sample_params) }
6
+ let(:datatable) { ComplexDatatable.new(view) }
7
+ let(:records) { User.all }
8
+
9
+ describe '#filter_records' do
10
+ it 'requires a records collection as argument' do
11
+ expect { datatable.send(:filter_records) }.to raise_error(ArgumentError)
12
+ end
13
+
14
+ it 'performs a simple search first' do
15
+ datatable.params[:search] = { value: 'msmith' }
16
+ expect(datatable).to receive(:build_conditions_for_datatable)
17
+ datatable.send(:filter_records, records)
18
+ end
19
+
20
+ it 'performs a composite search second' do
21
+ datatable.params[:search] = { value: '' }
22
+ expect(datatable).to receive(:build_conditions_for_selected_columns)
23
+ datatable.send(:filter_records, records)
24
+ end
25
+ end
26
+
27
+ describe '#build_conditions_for_datatable' do
28
+ before(:each) do
29
+ create(:user, username: 'johndoe', email: 'johndoe@example.com')
30
+ create(:user, username: 'msmith', email: 'mary.smith@example.com')
31
+ end
32
+
33
+ it 'returns an Arel object' do
34
+ datatable.params[:search] = { value: 'msmith' }
35
+ result = datatable.send(:build_conditions_for_datatable)
36
+ expect(result).to be_a(Arel::Nodes::Grouping)
37
+ end
38
+
39
+ context 'no search query' do
40
+ it 'returns empty query' do
41
+ datatable.params[:search] = { value: '' }
42
+ expect(datatable.send(:build_conditions_for_datatable)).to be_blank
43
+ end
44
+ end
45
+
46
+ context 'none of columns are connected' do
47
+ before(:each) do
48
+ allow(datatable).to receive(:searchable_columns) { [] }
49
+ end
50
+
51
+ it 'returns empty query result' do
52
+ datatable.params[:search] = { value: 'msmith' }
53
+ expect(datatable.send(:build_conditions_for_datatable)).to be_blank
54
+ end
55
+ end
56
+
57
+ context 'with search query' do
58
+ before(:each) do
59
+ datatable.params[:search] = { value: "john", regex: "false" }
60
+ end
61
+
62
+ it 'returns a filtering query' do
63
+ query = datatable.send(:build_conditions_for_datatable)
64
+ results = records.where(query).map(&:username)
65
+ expect(results).to include('johndoe')
66
+ expect(results).not_to include('msmith')
67
+ end
68
+ end
69
+ end
70
+
71
+ describe '#build_conditions_for_selected_columns' do
72
+ before(:each) do
73
+ create(:user, username: 'johndoe', email: 'johndoe@example.com')
74
+ create(:user, username: 'msmith', email: 'mary.smith@example.com')
75
+ end
76
+
77
+ context 'columns include search query' do
78
+ before do
79
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
80
+ datatable.params[:columns]['1'][:search][:value] = 'example'
81
+ end
82
+
83
+ it 'returns an Arel object' do
84
+ result = datatable.send(:build_conditions_for_selected_columns)
85
+ expect(result).to be_a(Arel::Nodes::And)
86
+ end
87
+
88
+ if AjaxDatatablesRails.config.db_adapter == :postgresql
89
+ context 'when db_adapter is postgresql' do
90
+ it 'can call #to_sql on returned object' do
91
+ result = datatable.send(:build_conditions_for_selected_columns)
92
+ expect(result).to respond_to(:to_sql)
93
+ expect(result.to_sql).to eq(
94
+ "CAST(\"users\".\"username\" AS VARCHAR) ILIKE '%doe%' AND CAST(\"users\".\"email\" AS VARCHAR) ILIKE '%example%'"
95
+ )
96
+ end
97
+ end
98
+ end
99
+
100
+ if AjaxDatatablesRails.config.db_adapter.in? %i[oracle oracleenhanced]
101
+ context 'when db_adapter is oracle' do
102
+ it 'can call #to_sql on returned object' do
103
+ result = datatable.send(:build_conditions_for_selected_columns)
104
+ expect(result).to respond_to(:to_sql)
105
+ expect(result.to_sql).to eq(
106
+ "CAST(\"USERS\".\"USERNAME\" AS VARCHAR2(4000)) LIKE '%doe%' AND CAST(\"USERS\".\"EMAIL\" AS VARCHAR2(4000)) LIKE '%example%'"
107
+ )
108
+ end
109
+ end
110
+ end
111
+
112
+ if AjaxDatatablesRails.config.db_adapter.in? %i[mysql2 sqlite3]
113
+ context 'when db_adapter is mysql2' do
114
+ it 'can call #to_sql on returned object' do
115
+ result = datatable.send(:build_conditions_for_selected_columns)
116
+ expect(result).to respond_to(:to_sql)
117
+ expect(result.to_sql).to eq(
118
+ "CAST(`users`.`username` AS CHAR) LIKE '%doe%' AND CAST(`users`.`email` AS CHAR) LIKE '%example%'"
119
+ )
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ it 'calls #build_conditions_for_selected_columns' do
126
+ expect(datatable).to receive(:build_conditions_for_selected_columns)
127
+ datatable.send(:build_conditions)
128
+ end
129
+
130
+ context 'with search values in columns' do
131
+ before(:each) do
132
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
133
+ end
134
+
135
+ it 'returns a filtered set of records' do
136
+ query = datatable.send(:build_conditions_for_selected_columns)
137
+ results = records.where(query).map(&:username)
138
+ expect(results).to include('johndoe')
139
+ expect(results).not_to include('msmith')
140
+ end
141
+ end
142
+ end
143
+
144
+ describe '#typecast helper method' do
145
+ let(:view) { double('view', params: sample_params) }
146
+ let(:column) { ComplexDatatable.new(view).datatable.columns.first }
147
+
148
+ it 'returns VARCHAR if :db_adapter is :pg' do
149
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :pg }
150
+ expect(column.send(:typecast)).to eq('VARCHAR')
151
+ end
152
+
153
+ it 'returns VARCHAR if :db_adapter is :postgre' do
154
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :postgre }
155
+ expect(column.send(:typecast)).to eq('VARCHAR')
156
+ end
157
+
158
+ it 'returns VARCHAR if :db_adapter is :postgresql' do
159
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :postgresql }
160
+ expect(column.send(:typecast)).to eq('VARCHAR')
161
+ end
162
+
163
+ it 'returns VARCHAR if :db_adapter is :oracle' do
164
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :oracle }
165
+ expect(column.send(:typecast)).to eq('VARCHAR2(4000)')
166
+ end
167
+
168
+ it 'returns VARCHAR if :db_adapter is :oracleenhanced' do
169
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :oracleenhanced }
170
+ expect(column.send(:typecast)).to eq('VARCHAR2(4000)')
171
+ end
172
+
173
+ it 'returns CHAR if :db_adapter is :mysql2' do
174
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :mysql2 }
175
+ expect(column.send(:typecast)).to eq('CHAR')
176
+ end
177
+
178
+ it 'returns CHAR if :db_adapter is :mysql' do
179
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :mysql }
180
+ expect(column.send(:typecast)).to eq('CHAR')
181
+ end
182
+
183
+ it 'returns TEXT if :db_adapter is :sqlite' do
184
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :sqlite }
185
+ expect(column.send(:typecast)).to eq('TEXT')
186
+ end
187
+
188
+ it 'returns TEXT if :db_adapter is :sqlite3' do
189
+ allow_any_instance_of(AjaxDatatablesRails::Configuration).to receive(:db_adapter) { :sqlite3 }
190
+ expect(column.send(:typecast)).to eq('TEXT')
191
+ end
192
+ end
193
+
194
+ describe 'filter conditions' do
195
+ let(:datatable) { ReallyComplexDatatable.new(view) }
196
+
197
+ unless AjaxDatatablesRails.old_rails?
198
+ describe 'it can filter records with condition :date_range' do
199
+ before(:each) do
200
+ create(:user, username: 'johndoe', email: 'johndoe@example.com', last_name: 'Doe', created_at: '01/01/2000')
201
+ create(:user, username: 'msmith', email: 'mary.smith@example.com', last_name: 'Smith', created_at: '01/02/2000')
202
+ end
203
+
204
+ context 'when range is empty' do
205
+ it 'should not filter records' do
206
+ datatable.params[:columns]['5'][:search][:value] = '-'
207
+ expect(datatable.data.size).to eq 2
208
+ item = datatable.data.first
209
+ expect(item[:last_name]).to eq 'Doe'
210
+ end
211
+ end
212
+
213
+ context 'when start date is filled' do
214
+ it 'should filter records created after this date' do
215
+ datatable.params[:columns]['5'][:search][:value] = '31/12/1999-'
216
+ expect(datatable.data.size).to eq 2
217
+ end
218
+ end
219
+
220
+ context 'when end date is filled' do
221
+ it 'should filter records created before this date' do
222
+ datatable.params[:columns]['5'][:search][:value] = '-31/12/1999'
223
+ expect(datatable.data.size).to eq 0
224
+ end
225
+ end
226
+
227
+ context 'when both date are filled' do
228
+ it 'should filter records created between the range' do
229
+ datatable.params[:columns]['5'][:search][:value] = '01/12/1999-15/01/2000'
230
+ expect(datatable.data.size).to eq 1
231
+ end
232
+ end
233
+
234
+ context 'when another filter is active' do
235
+ context 'when range is empty' do
236
+ it 'should filter records' do
237
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
238
+ datatable.params[:columns]['5'][:search][:value] = '-'
239
+ expect(datatable.data.size).to eq 1
240
+ item = datatable.data.first
241
+ expect(item[:last_name]).to eq 'Doe'
242
+ end
243
+ end
244
+
245
+ context 'when start date is filled' do
246
+ it 'should filter records' do
247
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
248
+ datatable.params[:columns]['5'][:search][:value] = '01/12/1999-'
249
+ expect(datatable.data.size).to eq 1
250
+ item = datatable.data.first
251
+ expect(item[:last_name]).to eq 'Doe'
252
+ end
253
+ end
254
+
255
+ context 'when end date is filled' do
256
+ it 'should filter records' do
257
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
258
+ datatable.params[:columns]['5'][:search][:value] = '-15/01/2000'
259
+ expect(datatable.data.size).to eq 1
260
+ item = datatable.data.first
261
+ expect(item[:last_name]).to eq 'Doe'
262
+ end
263
+ end
264
+
265
+ context 'when both date are filled' do
266
+ it 'should filter records' do
267
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
268
+ datatable.params[:columns]['5'][:search][:value] = '01/12/1999-15/01/2000'
269
+ expect(datatable.data.size).to eq 1
270
+ item = datatable.data.first
271
+ expect(item[:last_name]).to eq 'Doe'
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end
277
+
278
+ describe 'it can filter records with condition :start_with' do
279
+ before(:each) do
280
+ create(:user, first_name: 'John')
281
+ create(:user, first_name: 'Mary')
282
+ end
283
+
284
+ it 'should filter records matching' do
285
+ datatable.params[:columns]['2'][:search][:value] = 'Jo'
286
+ expect(datatable.data.size).to eq 1
287
+ item = datatable.data.first
288
+ expect(item[:first_name]).to eq 'John'
289
+ end
290
+ end
291
+
292
+ describe 'it can filter records with condition :end_with' do
293
+ before(:each) do
294
+ create(:user, last_name: 'JOHN')
295
+ create(:user, last_name: 'MARY')
296
+ end
297
+
298
+ it 'should filter records matching' do
299
+ datatable.params[:columns]['3'][:search][:value] = 'ry'
300
+ expect(datatable.data.size).to eq 1
301
+ item = datatable.data.first
302
+ expect(item[:last_name]).to eq 'MARY'
303
+ end
304
+ end
305
+
306
+ describe 'it can filter records with condition :null_value' do
307
+ before(:each) do
308
+ create(:user, first_name: 'john', email: 'foo@bar.com')
309
+ create(:user, first_name: 'mary', email: nil)
310
+ end
311
+
312
+ context 'when condition is NULL' do
313
+ it 'should filter records matching' do
314
+ datatable.params[:columns]['1'][:search][:value] = 'NULL'
315
+ expect(datatable.data.size).to eq 1
316
+ item = datatable.data.first
317
+ expect(item[:first_name]).to eq 'mary'
318
+ end
319
+ end
320
+
321
+ context 'when condition is !NULL' do
322
+ it 'should filter records matching' do
323
+ datatable.params[:columns]['1'][:search][:value] = '!NULL'
324
+ expect(datatable.data.size).to eq 1
325
+ item = datatable.data.first
326
+ expect(item[:first_name]).to eq 'john'
327
+ end
328
+ end
329
+ end
330
+
331
+ describe 'it can filter records with condition :eq' do
332
+ let(:datatable) { ReallyComplexDatatableEq.new(view) }
333
+
334
+ before(:each) do
335
+ create(:user, first_name: 'john', post_id: 1)
336
+ create(:user, first_name: 'mary', post_id: 2)
337
+ end
338
+
339
+ it 'should filter records matching' do
340
+ datatable.params[:columns]['4'][:search][:value] = 1
341
+ expect(datatable.data.size).to eq 1
342
+ item = datatable.data.first
343
+ expect(item[:first_name]).to eq 'john'
344
+ end
345
+ end
346
+
347
+ describe 'it can filter records with condition :not_eq' do
348
+ let(:datatable) { ReallyComplexDatatableNotEq.new(view) }
349
+
350
+ before(:each) do
351
+ create(:user, first_name: 'john', post_id: 1)
352
+ create(:user, first_name: 'mary', post_id: 2)
353
+ end
354
+
355
+ it 'should filter records matching' do
356
+ datatable.params[:columns]['4'][:search][:value] = 1
357
+ expect(datatable.data.size).to eq 1
358
+ item = datatable.data.first
359
+ expect(item[:first_name]).to eq 'mary'
360
+ end
361
+ end
362
+
363
+ describe 'it can filter records with condition :lt' do
364
+ let(:datatable) { ReallyComplexDatatableLt.new(view) }
365
+
366
+ before(:each) do
367
+ create(:user, first_name: 'john', post_id: 1)
368
+ create(:user, first_name: 'mary', post_id: 2)
369
+ end
370
+
371
+ it 'should filter records matching' do
372
+ datatable.params[:columns]['4'][:search][:value] = 2
373
+ expect(datatable.data.size).to eq 1
374
+ item = datatable.data.first
375
+ expect(item[:first_name]).to eq 'john'
376
+ end
377
+ end
378
+
379
+ describe 'it can filter records with condition :gt' do
380
+ let(:datatable) { ReallyComplexDatatableGt.new(view) }
381
+
382
+ before(:each) do
383
+ create(:user, first_name: 'john', post_id: 1)
384
+ create(:user, first_name: 'mary', post_id: 2)
385
+ end
386
+
387
+ it 'should filter records matching' do
388
+ datatable.params[:columns]['4'][:search][:value] = 1
389
+ expect(datatable.data.size).to eq 1
390
+ item = datatable.data.first
391
+ expect(item[:first_name]).to eq 'mary'
392
+ end
393
+ end
394
+
395
+ describe 'it can filter records with condition :lteq' do
396
+ let(:datatable) { ReallyComplexDatatableLteq.new(view) }
397
+
398
+ before(:each) do
399
+ create(:user, first_name: 'john', post_id: 1)
400
+ create(:user, first_name: 'mary', post_id: 2)
401
+ end
402
+
403
+ it 'should filter records matching' do
404
+ datatable.params[:columns]['4'][:search][:value] = 2
405
+ expect(datatable.data.size).to eq 2
406
+ end
407
+ end
408
+
409
+ describe 'it can filter records with condition :gteq' do
410
+ let(:datatable) { ReallyComplexDatatableGteq.new(view) }
411
+
412
+ before(:each) do
413
+ create(:user, first_name: 'john', post_id: 1)
414
+ create(:user, first_name: 'mary', post_id: 2)
415
+ end
416
+
417
+ it 'should filter records matching' do
418
+ datatable.params[:columns]['4'][:search][:value] = 1
419
+ expect(datatable.data.size).to eq 2
420
+ end
421
+ end
422
+
423
+ describe 'it can filter records with condition :in' do
424
+ let(:datatable) { ReallyComplexDatatableIn.new(view) }
425
+
426
+ before(:each) do
427
+ create(:user, first_name: 'john', post_id: 1)
428
+ create(:user, first_name: 'mary', post_id: 2)
429
+ end
430
+
431
+ it 'should filter records matching' do
432
+ datatable.params[:columns]['4'][:search][:value] = [1]
433
+ expect(datatable.data.size).to eq 1
434
+ item = datatable.data.first
435
+ expect(item[:first_name]).to eq 'john'
436
+ end
437
+ end
438
+ end
439
+ end