ajax-datatables-rails 0.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +8 -0
  3. data/.github/workflows/ci.yml +128 -0
  4. data/.gitignore +23 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +58 -0
  7. data/Appraisals +28 -0
  8. data/CHANGELOG.md +102 -7
  9. data/Gemfile +4 -1
  10. data/Guardfile +16 -0
  11. data/LICENSE +17 -18
  12. data/README.md +595 -404
  13. data/Rakefile +4 -2
  14. data/ajax-datatables-rails.gemspec +41 -25
  15. data/appraisal.yml +56 -0
  16. data/bin/_guard-core +29 -0
  17. data/bin/appraisal +29 -0
  18. data/bin/bundle +114 -0
  19. data/bin/guard +29 -0
  20. data/bin/rackup +27 -0
  21. data/bin/rake +29 -0
  22. data/bin/rspec +29 -0
  23. data/bin/rubocop +29 -0
  24. data/config.ru +7 -0
  25. data/doc/migrate.md +97 -0
  26. data/doc/webpack.md +55 -0
  27. data/gemfiles/rails_5.2.8.gemfile +21 -0
  28. data/gemfiles/rails_6.0.6.gemfile +21 -0
  29. data/gemfiles/rails_6.1.7.gemfile +21 -0
  30. data/gemfiles/rails_7.0.4.gemfile +21 -0
  31. data/lib/ajax-datatables-rails/active_record.rb +7 -0
  32. data/lib/ajax-datatables-rails/base.rb +114 -149
  33. data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +68 -0
  34. data/lib/ajax-datatables-rails/datatable/column/order.rb +29 -0
  35. data/lib/ajax-datatables-rails/datatable/column/search.rb +125 -0
  36. data/lib/ajax-datatables-rails/datatable/column.rb +123 -0
  37. data/lib/ajax-datatables-rails/datatable/datatable.rb +91 -0
  38. data/lib/ajax-datatables-rails/datatable/simple_order.rb +59 -0
  39. data/lib/ajax-datatables-rails/datatable/simple_search.rb +23 -0
  40. data/lib/ajax-datatables-rails/datatable.rb +6 -0
  41. data/lib/ajax-datatables-rails/error.rb +9 -0
  42. data/lib/ajax-datatables-rails/orm/active_record.rb +60 -0
  43. data/lib/ajax-datatables-rails/orm.rb +6 -0
  44. data/lib/ajax-datatables-rails/version.rb +15 -1
  45. data/lib/ajax-datatables-rails.rb +11 -7
  46. data/lib/generators/rails/datatable_generator.rb +11 -22
  47. data/lib/generators/rails/templates/datatable.rb +13 -15
  48. data/spec/ajax-datatables-rails/base_spec.rb +223 -0
  49. data/spec/ajax-datatables-rails/datatable/column_spec.rb +222 -0
  50. data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +127 -0
  51. data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +62 -0
  52. data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +19 -0
  53. data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +639 -0
  54. data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +67 -0
  55. data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +80 -0
  56. data/spec/dummy/app/assets/config/manifest.js +0 -0
  57. data/spec/dummy/config/database.yml +25 -0
  58. data/spec/dummy/config/routes.rb +5 -0
  59. data/spec/dummy/config/storage.yml +3 -0
  60. data/spec/dummy/db/schema.rb +13 -0
  61. data/spec/dummy/log/.gitignore +1 -0
  62. data/spec/dummy/public/favicon.ico +0 -0
  63. data/spec/factories/user.rb +11 -0
  64. data/spec/install_oracle.sh +18 -0
  65. data/spec/spec_helper.rb +85 -6
  66. data/spec/support/datatables/complex_datatable.rb +33 -0
  67. data/spec/support/datatables/complex_datatable_array.rb +16 -0
  68. data/spec/support/datatables/datatable_cond_date.rb +7 -0
  69. data/spec/support/datatables/datatable_cond_numeric.rb +53 -0
  70. data/spec/support/datatables/datatable_cond_proc.rb +13 -0
  71. data/spec/support/datatables/datatable_cond_string.rb +43 -0
  72. data/spec/support/datatables/datatable_cond_unknown.rb +7 -0
  73. data/spec/support/datatables/datatable_custom_column.rb +17 -0
  74. data/spec/support/datatables/datatable_order_nulls_last.rb +7 -0
  75. data/spec/support/helpers/params.rb +80 -0
  76. data/spec/support/models/user.rb +7 -0
  77. metadata +249 -48
  78. data/lib/ajax-datatables-rails/config.rb +0 -25
  79. data/lib/ajax-datatables-rails/extensions/kaminari.rb +0 -12
  80. data/lib/ajax-datatables-rails/extensions/simple_paginator.rb +0 -12
  81. data/lib/ajax-datatables-rails/extensions/will_paginate.rb +0 -12
  82. data/lib/ajax-datatables-rails/models.rb +0 -6
  83. data/lib/generators/datatable/config_generator.rb +0 -17
  84. data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -7
  85. data/spec/ajax-datatables-rails/ajax_datatables_rails_spec.rb +0 -351
  86. data/spec/ajax-datatables-rails/kaminari_spec.rb +0 -35
  87. data/spec/ajax-datatables-rails/models_spec.rb +0 -10
  88. data/spec/ajax-datatables-rails/simple_paginator_spec.rb +0 -32
  89. data/spec/ajax-datatables-rails/will_paginate_spec.rb +0 -28
  90. data/spec/schema.rb +0 -35
  91. data/spec/test_models.rb +0 -21
@@ -0,0 +1,639 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe AjaxDatatablesRails::ORM::ActiveRecord do
6
+
7
+ let(:datatable) { ComplexDatatable.new(sample_params) }
8
+ let(:records) { User.all }
9
+
10
+ describe '#filter_records' do
11
+ it 'requires a records collection as argument' do
12
+ expect { datatable.filter_records }.to raise_error(ArgumentError)
13
+ end
14
+
15
+ it 'performs a simple search first' do
16
+ datatable.params[:search] = { value: 'msmith' }
17
+ expect(datatable).to receive(:build_conditions_for_datatable)
18
+ datatable.filter_records(records)
19
+ end
20
+
21
+ it 'performs a composite search second' do
22
+ datatable.params[:search] = { value: '' }
23
+ expect(datatable).to receive(:build_conditions_for_selected_columns)
24
+ datatable.filter_records(records)
25
+ end
26
+ end
27
+
28
+ describe '#build_conditions' do
29
+ before do
30
+ create(:user, username: 'johndoe', email: 'johndoe@example.com')
31
+ create(:user, username: 'msmith', email: 'mary.smith@example.com')
32
+ create(:user, username: 'hsmith', email: 'henry.smith@example.net')
33
+ end
34
+
35
+ context 'with column and global search' do
36
+ before do
37
+ datatable.params[:search] = { value: 'example.com', regex: 'false' }
38
+ datatable.params[:columns]['0'][:search][:value] = 'smith'
39
+ end
40
+
41
+ it 'return a filtered set of records' do
42
+ query = datatable.build_conditions
43
+ results = records.where(query).map(&:username)
44
+ expect(results).to include('msmith')
45
+ expect(results).not_to include('johndoe')
46
+ expect(results).not_to include('hsmith')
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#build_conditions_for_datatable' do
52
+ before do
53
+ create(:user, username: 'johndoe', email: 'johndoe@example.com')
54
+ create(:user, username: 'msmith', email: 'mary.smith@example.com')
55
+ end
56
+
57
+ it 'returns an Arel object' do
58
+ datatable.params[:search] = { value: 'msmith' }
59
+ result = datatable.build_conditions_for_datatable
60
+ expect(result).to be_a(Arel::Nodes::Grouping)
61
+ end
62
+
63
+ context 'no search query' do
64
+ it 'returns empty query' do
65
+ datatable.params[:search] = { value: '' }
66
+ expect(datatable.build_conditions_for_datatable).to be_blank
67
+ end
68
+ end
69
+
70
+ context 'when none of columns are connected' do
71
+ before do
72
+ allow(datatable).to receive(:searchable_columns) { [] }
73
+ end
74
+
75
+ context 'when search value is a string' do
76
+ before do
77
+ datatable.params[:search] = { value: 'msmith' }
78
+ end
79
+
80
+ it 'returns empty query result' do
81
+ expect(datatable.build_conditions_for_datatable).to be_blank
82
+ end
83
+
84
+ it 'returns filtered results' do
85
+ query = datatable.build_conditions_for_datatable
86
+ results = records.where(query).map(&:username)
87
+ expect(results).to eq ['johndoe', 'msmith']
88
+ end
89
+ end
90
+
91
+ context 'when search value is space-separated string' do
92
+ before do
93
+ datatable.params[:search] = { value: 'foo bar' }
94
+ end
95
+
96
+ it 'returns empty query result' do
97
+ expect(datatable.build_conditions_for_datatable).to be_blank
98
+ end
99
+
100
+ it 'returns filtered results' do
101
+ query = datatable.build_conditions_for_datatable
102
+ results = records.where(query).map(&:username)
103
+ expect(results).to eq ['johndoe', 'msmith']
104
+ end
105
+ end
106
+ end
107
+
108
+ context 'with search query' do
109
+ context 'when search value is a string' do
110
+ before do
111
+ datatable.params[:search] = { value: 'john', regex: 'false' }
112
+ end
113
+
114
+ it 'returns a filtering query' do
115
+ query = datatable.build_conditions_for_datatable
116
+ results = records.where(query).map(&:username)
117
+ expect(results).to include('johndoe')
118
+ expect(results).not_to include('msmith')
119
+ end
120
+ end
121
+
122
+ context 'when search value is space-separated string' do
123
+ before do
124
+ datatable.params[:search] = { value: 'john doe', regex: 'false' }
125
+ end
126
+
127
+ it 'returns a filtering query' do
128
+ query = datatable.build_conditions_for_datatable
129
+ results = records.where(query).map(&:username)
130
+ expect(results).to eq ['johndoe']
131
+ expect(results).not_to include('msmith')
132
+ end
133
+ end
134
+
135
+ # TODO: improve (or delete?) this test
136
+ context 'when column.search_query returns nil' do
137
+ let(:datatable) { DatatableCondUnknown.new(sample_params) }
138
+
139
+ before do
140
+ datatable.params[:search] = { value: 'john doe', regex: 'false' }
141
+ end
142
+
143
+ it 'does not raise error' do
144
+ allow_any_instance_of(AjaxDatatablesRails::Datatable::Column).to receive(:valid_search_condition?).and_return(true)
145
+
146
+ expect {
147
+ datatable.data.size
148
+ }.to_not raise_error
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ describe '#build_conditions_for_selected_columns' do
155
+ before do
156
+ create(:user, username: 'johndoe', email: 'johndoe@example.com')
157
+ create(:user, username: 'msmith', email: 'mary.smith@example.com')
158
+ end
159
+
160
+ context 'columns include search query' do
161
+ before do
162
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
163
+ datatable.params[:columns]['1'][:search][:value] = 'example'
164
+ end
165
+
166
+ it 'returns an Arel object' do
167
+ result = datatable.build_conditions_for_selected_columns
168
+ expect(result).to be_a(Arel::Nodes::And)
169
+ end
170
+
171
+ if RunningSpec.postgresql?
172
+ context 'when db_adapter is postgresql' do
173
+ it 'can call #to_sql on returned object' do
174
+ result = datatable.build_conditions_for_selected_columns
175
+ expect(result).to respond_to(:to_sql)
176
+ expect(result.to_sql).to eq(
177
+ "CAST(\"users\".\"username\" AS VARCHAR) ILIKE '%doe%' AND CAST(\"users\".\"email\" AS VARCHAR) ILIKE '%example%'"
178
+ )
179
+ end
180
+ end
181
+ end
182
+
183
+ if RunningSpec.oracle?
184
+ context 'when db_adapter is oracle' do
185
+ it 'can call #to_sql on returned object' do
186
+ result = datatable.build_conditions_for_selected_columns
187
+ expect(result).to respond_to(:to_sql)
188
+ expect(result.to_sql).to eq(
189
+ "CAST(\"USERS\".\"USERNAME\" AS VARCHAR2(4000)) LIKE '%doe%' AND CAST(\"USERS\".\"EMAIL\" AS VARCHAR2(4000)) LIKE '%example%'"
190
+ )
191
+ end
192
+ end
193
+ end
194
+
195
+ if RunningSpec.mysql?
196
+ context 'when db_adapter is mysql2' do
197
+ it 'can call #to_sql on returned object' do
198
+ result = datatable.build_conditions_for_selected_columns
199
+ expect(result).to respond_to(:to_sql)
200
+ expect(result.to_sql).to eq(
201
+ "CAST(`users`.`username` AS CHAR) LIKE '%doe%' AND CAST(`users`.`email` AS CHAR) LIKE '%example%'"
202
+ )
203
+ end
204
+ end
205
+ end
206
+ end
207
+
208
+ it 'calls #build_conditions_for_selected_columns' do
209
+ expect(datatable).to receive(:build_conditions_for_selected_columns)
210
+ datatable.build_conditions
211
+ end
212
+
213
+ context 'with search values in columns' do
214
+ before do
215
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
216
+ end
217
+
218
+ it 'returns a filtered set of records' do
219
+ query = datatable.build_conditions_for_selected_columns
220
+ results = records.where(query).map(&:username)
221
+ expect(results).to include('johndoe')
222
+ expect(results).not_to include('msmith')
223
+ end
224
+ end
225
+ end
226
+
227
+ describe 'filter conditions' do
228
+ context 'date condition' do
229
+ describe 'it can filter records with condition :date_range' do
230
+ let(:datatable) { DatatableCondDate.new(sample_params) }
231
+
232
+ before do
233
+ create(:user, username: 'johndoe', email: 'johndoe@example.com', last_name: 'Doe', created_at: '01/01/2000')
234
+ create(:user, username: 'msmith', email: 'mary.smith@example.com', last_name: 'Smith', created_at: '01/02/2000')
235
+ end
236
+
237
+ context 'when range is empty' do
238
+ it 'does not filter records' do
239
+ datatable.params[:columns]['6'][:search][:value] = '-'
240
+ expect(datatable.data.size).to eq 2
241
+ item = datatable.data.first
242
+ expect(item[:last_name]).to eq 'Doe'
243
+ end
244
+ end
245
+
246
+ context 'when start date is filled' do
247
+ it 'filters records created after this date' do
248
+ datatable.params[:columns]['6'][:search][:value] = '31/12/1999-'
249
+ expect(datatable.data.size).to eq 2
250
+ end
251
+ end
252
+
253
+ context 'when end date is filled' do
254
+ it 'filters records created before this date' do
255
+ datatable.params[:columns]['6'][:search][:value] = '-31/12/1999'
256
+ expect(datatable.data.size).to eq 0
257
+ end
258
+ end
259
+
260
+ context 'when both date are filled' do
261
+ it 'filters records created between the range' do
262
+ datatable.params[:columns]['6'][:search][:value] = '01/12/1999-15/01/2000'
263
+ expect(datatable.data.size).to eq 1
264
+ end
265
+ end
266
+
267
+ context 'when another filter is active' do
268
+ context 'when range is empty' do
269
+ it 'filters records' do
270
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
271
+ datatable.params[:columns]['6'][:search][:value] = '-'
272
+ expect(datatable.data.size).to eq 1
273
+ item = datatable.data.first
274
+ expect(item[:last_name]).to eq 'Doe'
275
+ end
276
+ end
277
+
278
+ context 'when start date is filled' do
279
+ it 'filters records' do
280
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
281
+ datatable.params[:columns]['6'][:search][:value] = '01/12/1999-'
282
+ expect(datatable.data.size).to eq 1
283
+ item = datatable.data.first
284
+ expect(item[:last_name]).to eq 'Doe'
285
+ end
286
+ end
287
+
288
+ context 'when end date is filled' do
289
+ it 'filters records' do
290
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
291
+ datatable.params[:columns]['6'][:search][:value] = '-15/01/2000'
292
+ expect(datatable.data.size).to eq 1
293
+ item = datatable.data.first
294
+ expect(item[:last_name]).to eq 'Doe'
295
+ end
296
+ end
297
+
298
+ context 'when both date are filled' do
299
+ it 'filters records' do
300
+ datatable.params[:columns]['0'][:search][:value] = 'doe'
301
+ datatable.params[:columns]['6'][:search][:value] = '01/12/1999-15/01/2000'
302
+ expect(datatable.data.size).to eq 1
303
+ item = datatable.data.first
304
+ expect(item[:last_name]).to eq 'Doe'
305
+ end
306
+ end
307
+ end
308
+ end
309
+ end
310
+
311
+ context 'numeric condition' do
312
+ before do
313
+ create(:user, first_name: 'john', post_id: 1)
314
+ create(:user, first_name: 'mary', post_id: 2)
315
+ end
316
+
317
+ describe 'it can filter records with condition :eq' do
318
+ let(:datatable) { DatatableCondEq.new(sample_params) }
319
+
320
+ it 'filters records matching' do
321
+ datatable.params[:columns]['5'][:search][:value] = 1
322
+ expect(datatable.data.size).to eq 1
323
+ item = datatable.data.first
324
+ expect(item[:first_name]).to eq 'john'
325
+ end
326
+ end
327
+
328
+ describe 'it can filter records with condition :not_eq' do
329
+ let(:datatable) { DatatableCondNotEq.new(sample_params) }
330
+
331
+ it 'filters records matching' do
332
+ datatable.params[:columns]['5'][:search][:value] = 1
333
+ expect(datatable.data.size).to eq 1
334
+ item = datatable.data.first
335
+ expect(item[:first_name]).to eq 'mary'
336
+ end
337
+ end
338
+
339
+ describe 'it can filter records with condition :lt' do
340
+ let(:datatable) { DatatableCondLt.new(sample_params) }
341
+
342
+ it 'filters records matching' do
343
+ datatable.params[:columns]['5'][:search][:value] = 2
344
+ expect(datatable.data.size).to eq 1
345
+ item = datatable.data.first
346
+ expect(item[:first_name]).to eq 'john'
347
+ end
348
+ end
349
+
350
+ describe 'it can filter records with condition :gt' do
351
+ let(:datatable) { DatatableCondGt.new(sample_params) }
352
+
353
+ it 'filters records matching' do
354
+ datatable.params[:columns]['5'][:search][:value] = 1
355
+ expect(datatable.data.size).to eq 1
356
+ item = datatable.data.first
357
+ expect(item[:first_name]).to eq 'mary'
358
+ end
359
+ end
360
+
361
+ describe 'it can filter records with condition :lteq' do
362
+ let(:datatable) { DatatableCondLteq.new(sample_params) }
363
+
364
+ it 'filters records matching' do
365
+ datatable.params[:columns]['5'][:search][:value] = 2
366
+ expect(datatable.data.size).to eq 2
367
+ end
368
+ end
369
+
370
+ describe 'it can filter records with condition :gteq' do
371
+ let(:datatable) { DatatableCondGteq.new(sample_params) }
372
+
373
+ it 'filters records matching' do
374
+ datatable.params[:columns]['5'][:search][:value] = 1
375
+ expect(datatable.data.size).to eq 2
376
+ end
377
+ end
378
+
379
+ describe 'it can filter records with condition :in' do
380
+ let(:datatable) { DatatableCondIn.new(sample_params) }
381
+
382
+ it 'filters records matching' do
383
+ datatable.params[:columns]['5'][:search][:value] = [1]
384
+ expect(datatable.data.size).to eq 1
385
+ item = datatable.data.first
386
+ expect(item[:first_name]).to eq 'john'
387
+ end
388
+ end
389
+
390
+ describe 'it can filter records with condition :in with regex' do
391
+ let(:datatable) { DatatableCondInWithRegex.new(sample_params) }
392
+
393
+ it 'filters records matching' do
394
+ datatable.params[:columns]['5'][:search][:value] = '1|2'
395
+ datatable.params[:order]['0'] = { column: '5', dir: 'asc' }
396
+ expect(datatable.data.size).to eq 2
397
+ item = datatable.data.first
398
+ expect(item[:first_name]).to eq 'john'
399
+ end
400
+ end
401
+
402
+ describe 'Integer overflows' do
403
+ let(:datatable) { DatatableCondEq.new(sample_params) }
404
+ let(:largest_postgresql_integer_value) { 2_147_483_647 }
405
+ let(:smallest_postgresql_integer_value) { -2_147_483_648 }
406
+
407
+ before do
408
+ create(:user, first_name: 'john', post_id: 1)
409
+ create(:user, first_name: 'mary', post_id: 2)
410
+ create(:user, first_name: 'phil', post_id: largest_postgresql_integer_value)
411
+ end
412
+
413
+ it 'returns an empty result if input value is too large' do
414
+ datatable.params[:columns]['5'][:search][:value] = largest_postgresql_integer_value + 1
415
+ expect(datatable.data.size).to eq 0
416
+ end
417
+
418
+ it 'returns an empty result if input value is too small' do
419
+ datatable.params[:columns]['5'][:search][:value] = smallest_postgresql_integer_value - 1
420
+ expect(datatable.data.size).to eq 0
421
+ end
422
+
423
+ it 'returns the matching user' do
424
+ datatable.params[:columns]['5'][:search][:value] = largest_postgresql_integer_value
425
+ expect(datatable.data.size).to eq 1
426
+ end
427
+ end
428
+ end
429
+
430
+ context 'proc condition' do
431
+ describe 'it can filter records with lambda/proc condition' do
432
+ let(:datatable) { DatatableCondProc.new(sample_params) }
433
+
434
+ before do
435
+ create(:user, username: 'johndoe', email: 'johndoe@example.com')
436
+ create(:user, username: 'johndie', email: 'johndie@example.com')
437
+ create(:user, username: 'msmith', email: 'mary.smith@example.com')
438
+ end
439
+
440
+ it 'filters records matching' do
441
+ datatable.params[:columns]['0'][:search][:value] = 'john'
442
+ expect(datatable.data.size).to eq 2
443
+ item = datatable.data.first
444
+ expect(item[:username]).to eq 'johndie'
445
+ end
446
+ end
447
+ end
448
+
449
+ context 'string condition' do
450
+ describe 'it can filter records with condition :start_with' do
451
+ let(:datatable) { DatatableCondStartWith.new(sample_params) }
452
+
453
+ before do
454
+ create(:user, first_name: 'John')
455
+ create(:user, first_name: 'Mary')
456
+ end
457
+
458
+ it 'filters records matching' do
459
+ datatable.params[:columns]['2'][:search][:value] = 'Jo'
460
+ expect(datatable.data.size).to eq 1
461
+ item = datatable.data.first
462
+ expect(item[:first_name]).to eq 'John'
463
+ end
464
+ end
465
+
466
+ describe 'it can filter records with condition :end_with' do
467
+ let(:datatable) { DatatableCondEndWith.new(sample_params) }
468
+
469
+ before do
470
+ create(:user, last_name: 'JOHN')
471
+ create(:user, last_name: 'MARY')
472
+ end
473
+
474
+ if RunningSpec.oracle?
475
+ context 'when db_adapter is oracleenhanced' do
476
+ it 'filters records matching' do
477
+ datatable.params[:columns]['3'][:search][:value] = 'RY'
478
+ expect(datatable.data.size).to eq 1
479
+ item = datatable.data.first
480
+ expect(item[:last_name]).to eq 'MARY'
481
+ end
482
+ end
483
+ else
484
+ it 'filters records matching' do
485
+ datatable.params[:columns]['3'][:search][:value] = 'ry'
486
+ expect(datatable.data.size).to eq 1
487
+ item = datatable.data.first
488
+ expect(item[:last_name]).to eq 'MARY'
489
+ end
490
+ end
491
+ end
492
+
493
+ describe 'it can filter records with condition :like' do
494
+ let(:datatable) { DatatableCondLike.new(sample_params) }
495
+
496
+ before do
497
+ create(:user, email: 'john@foo.com')
498
+ create(:user, email: 'mary@bar.com')
499
+ end
500
+
501
+ it 'filters records matching' do
502
+ datatable.params[:columns]['1'][:search][:value] = 'foo'
503
+ expect(datatable.data.size).to eq 1
504
+ item = datatable.data.first
505
+ expect(item[:email]).to eq 'john@foo.com'
506
+ end
507
+ end
508
+
509
+ describe 'it can filter records with condition :string_eq' do
510
+ let(:datatable) { DatatableCondStringEq.new(sample_params) }
511
+
512
+ before do
513
+ create(:user, email: 'john@foo.com')
514
+ create(:user, email: 'mary@bar.com')
515
+ end
516
+
517
+ it 'filters records matching' do
518
+ datatable.params[:columns]['1'][:search][:value] = 'john@foo.com'
519
+ expect(datatable.data.size).to eq 1
520
+ item = datatable.data.first
521
+ expect(item[:email]).to eq 'john@foo.com'
522
+ end
523
+ end
524
+
525
+ describe 'it can filter records with condition :string_in' do
526
+ let(:datatable) { DatatableCondStringIn.new(sample_params) }
527
+
528
+ before do
529
+ create(:user, email: 'john@foo.com')
530
+ create(:user, email: 'mary@bar.com')
531
+ create(:user, email: 'henry@baz.com')
532
+ end
533
+
534
+ it 'filters records matching' do
535
+ datatable.params[:columns]['1'][:search][:value] = 'john@foo.com'
536
+ expect(datatable.data.size).to eq 1
537
+ item = datatable.data.first
538
+ expect(item[:email]).to eq 'john@foo.com'
539
+ end
540
+
541
+ it 'filters records matching with multiple' do
542
+ datatable.params[:columns]['1'][:search][:value] = 'john@foo.com|henry@baz.com'
543
+ expect(datatable.data.size).to eq 2
544
+ items = datatable.data.sort_by { |h| h[:email] }
545
+ item_first = items.first
546
+ item_last = items.last
547
+ expect(item_first[:email]).to eq 'henry@baz.com'
548
+ expect(item_last[:email]).to eq 'john@foo.com'
549
+ end
550
+
551
+ it 'filters records matching with multiple contains not found' do
552
+ datatable.params[:columns]['1'][:search][:value] = 'john@foo.com|henry_not@baz.com'
553
+ expect(datatable.data.size).to eq 1
554
+ item = datatable.data.first
555
+ expect(item[:email]).to eq 'john@foo.com'
556
+ end
557
+ end
558
+
559
+ describe 'it can filter records with condition :null_value' do
560
+ let(:datatable) { DatatableCondNullValue.new(sample_params) }
561
+
562
+ before do
563
+ create(:user, first_name: 'john', email: 'foo@bar.com')
564
+ create(:user, first_name: 'mary', email: nil)
565
+ end
566
+
567
+ context 'when condition is NULL' do
568
+ it 'filters records matching' do
569
+ datatable.params[:columns]['1'][:search][:value] = 'NULL'
570
+ expect(datatable.data.size).to eq 1
571
+ item = datatable.data.first
572
+ expect(item[:first_name]).to eq 'mary'
573
+ end
574
+ end
575
+
576
+ context 'when condition is !NULL' do
577
+ it 'filters records matching' do
578
+ datatable.params[:columns]['1'][:search][:value] = '!NULL'
579
+ expect(datatable.data.size).to eq 1
580
+ item = datatable.data.first
581
+ expect(item[:first_name]).to eq 'john'
582
+ end
583
+ end
584
+ end
585
+ end
586
+
587
+ context 'unknown condition' do
588
+ let(:datatable) { DatatableCondUnknown.new(sample_params) }
589
+
590
+ before do
591
+ datatable.params[:search] = { value: 'john doe', regex: 'false' }
592
+ end
593
+
594
+ it 'raises error' do
595
+ expect {
596
+ datatable.data.size
597
+ }.to raise_error(AjaxDatatablesRails::Error::InvalidSearchCondition).with_message('foo')
598
+ end
599
+ end
600
+
601
+ context 'custom column' do
602
+ describe 'it can filter records with custom column' do
603
+ let(:datatable) { DatatableCustomColumn.new(sample_params) }
604
+
605
+ before do
606
+ create(:user, username: 'msmith', email: 'mary.smith@example.com', first_name: 'Mary', last_name: 'Smith')
607
+ create(:user, username: 'jsmith', email: 'john.smith@example.com', first_name: 'John', last_name: 'Smith')
608
+ create(:user, username: 'johndoe', email: 'johndoe@example.com', first_name: 'John', last_name: 'Doe')
609
+ end
610
+
611
+ it 'filters records' do
612
+ skip('unsupported database adapter') if RunningSpec.oracle? || RunningSpec.sqlite?
613
+
614
+ datatable.params[:columns]['4'][:search][:value] = 'John'
615
+ datatable.params[:order]['0'][:column] = '4'
616
+ expect(datatable.data.size).to eq 2
617
+ item = datatable.data.first
618
+ expect(item[:full_name]).to eq 'John Doe'
619
+ end
620
+ end
621
+ end
622
+ end
623
+
624
+ describe 'formatter option' do
625
+ let(:datatable) { DatatableWithFormater.new(sample_params) }
626
+
627
+ before do
628
+ create(:user, username: 'johndoe', email: 'johndoe@example.com', last_name: 'DOE')
629
+ create(:user, username: 'msmith', email: 'mary.smith@example.com', last_name: 'SMITH')
630
+ datatable.params[:columns]['3'][:search][:value] = 'doe'
631
+ end
632
+
633
+ it 'can transform search value before asking the database' do
634
+ expect(datatable.data.size).to eq 1
635
+ item = datatable.data.first
636
+ expect(item[:last_name]).to eq 'DOE'
637
+ end
638
+ end
639
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe AjaxDatatablesRails::ORM::ActiveRecord do
6
+
7
+ let(:datatable) { ComplexDatatable.new(sample_params) }
8
+ let(:records) { User.all }
9
+
10
+ before do
11
+ create(:user, username: 'johndoe', email: 'johndoe@example.com')
12
+ create(:user, username: 'msmith', email: 'mary.smith@example.com')
13
+ end
14
+
15
+ describe '#paginate_records' do
16
+ it 'requires a records collection argument' do
17
+ expect { datatable.paginate_records }.to raise_error(ArgumentError)
18
+ end
19
+
20
+ it 'paginates records properly' do
21
+ if RunningSpec.oracle?
22
+ if Rails.version.in? %w[4.2.11]
23
+ expect(datatable.paginate_records(records).to_sql).to include(
24
+ 'rownum <= 10'
25
+ )
26
+ else
27
+ expect(datatable.paginate_records(records).to_sql).to include(
28
+ 'rownum <= (0 + 10)'
29
+ )
30
+ end
31
+ else
32
+ expect(datatable.paginate_records(records).to_sql).to include(
33
+ 'LIMIT 10 OFFSET 0'
34
+ )
35
+ end
36
+
37
+ datatable.params[:start] = '26'
38
+ datatable.params[:length] = '25'
39
+ if RunningSpec.oracle?
40
+ if Rails.version.in? %w[4.2.11]
41
+ expect(datatable.paginate_records(records).to_sql).to include(
42
+ 'rownum <= 51'
43
+ )
44
+ else
45
+ expect(datatable.paginate_records(records).to_sql).to include(
46
+ 'rownum <= (26 + 25)'
47
+ )
48
+ end
49
+ else
50
+ expect(datatable.paginate_records(records).to_sql).to include(
51
+ 'LIMIT 25 OFFSET 26'
52
+ )
53
+ end
54
+ end
55
+
56
+ it 'depends on the value of #offset' do
57
+ expect(datatable.datatable).to receive(:offset)
58
+ datatable.paginate_records(records)
59
+ end
60
+
61
+ it 'depends on the value of #per_page' do
62
+ expect(datatable.datatable).to receive(:per_page).at_least(:once) { 10 }
63
+ datatable.paginate_records(records)
64
+ end
65
+ end
66
+
67
+ end