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,80 @@
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(:nulls_last_datatable) { DatatableOrderNullsLast.new(sample_params) }
9
+ let(:records) { User.all }
10
+
11
+ before do
12
+ create(:user, username: 'johndoe', email: 'johndoe@example.com')
13
+ create(:user, username: 'msmith', email: 'mary.smith@example.com')
14
+ end
15
+
16
+ describe '#sort_records' do
17
+ it 'returns a records collection sorted by :order params' do
18
+ # set to order Users by email in descending order
19
+ datatable.params[:order]['0'] = { column: '1', dir: 'desc' }
20
+ expect(datatable.sort_records(records).map(&:email)).to match(
21
+ ['mary.smith@example.com', 'johndoe@example.com']
22
+ )
23
+ end
24
+
25
+ it 'can handle multiple sorting columns' do
26
+ # set to order by Users username in ascending order, and
27
+ # by Users email in descending order
28
+ datatable.params[:order]['0'] = { column: '0', dir: 'asc' }
29
+ datatable.params[:order]['1'] = { column: '1', dir: 'desc' }
30
+ expect(datatable.sort_records(records).to_sql).to include(
31
+ 'ORDER BY users.username ASC, users.email DESC'
32
+ )
33
+ end
34
+
35
+ it 'does not sort a column which is not orderable' do
36
+ datatable.params[:order]['0'] = { column: '0', dir: 'asc' }
37
+ datatable.params[:order]['1'] = { column: '4', dir: 'desc' }
38
+
39
+ expect(datatable.sort_records(records).to_sql).to include(
40
+ 'ORDER BY users.username ASC'
41
+ )
42
+
43
+ expect(datatable.sort_records(records).to_sql).to_not include(
44
+ 'users.post_id DESC'
45
+ )
46
+ end
47
+ end
48
+
49
+ describe '#sort_records with nulls last using global config' do
50
+ before { datatable.nulls_last = true }
51
+ after { datatable.nulls_last = false }
52
+
53
+ it 'can handle multiple sorting columns' do
54
+ skip('unsupported database adapter') if RunningSpec.oracle?
55
+
56
+ # set to order by Users username in ascending order, and
57
+ # by Users email in descending order
58
+ datatable.params[:order]['0'] = { column: '0', dir: 'asc' }
59
+ datatable.params[:order]['1'] = { column: '1', dir: 'desc' }
60
+ expect(datatable.sort_records(records).to_sql).to include(
61
+ "ORDER BY users.username ASC #{nulls_last_sql(datatable)}, users.email DESC #{nulls_last_sql(datatable)}"
62
+ )
63
+ end
64
+ end
65
+
66
+ describe '#sort_records with nulls last using column config' do
67
+ it 'can handle multiple sorting columns' do
68
+ skip('unsupported database adapter') if RunningSpec.oracle?
69
+
70
+ # set to order by Users username in ascending order, and
71
+ # by Users email in descending order
72
+ nulls_last_datatable.params[:order]['0'] = { column: '0', dir: 'asc' }
73
+ nulls_last_datatable.params[:order]['1'] = { column: '1', dir: 'desc' }
74
+ expect(nulls_last_datatable.sort_records(records).to_sql).to include(
75
+ "ORDER BY users.username ASC, users.email DESC #{nulls_last_sql(datatable)}"
76
+ )
77
+ end
78
+ end
79
+
80
+ end
File without changes
@@ -0,0 +1,25 @@
1
+ <% adapter = ENV.fetch('DB_ADAPTER', 'postgresql') %>
2
+ test:
3
+ adapter: <%= adapter %>
4
+ database: ajax_datatables_rails
5
+ encoding: utf8
6
+
7
+ <% if adapter == 'postgresql' %>
8
+ host: '127.0.0.1'
9
+ port: 5432
10
+ username: 'postgres'
11
+ password: 'postgres'
12
+ <% elsif adapter == 'mysql2' %>
13
+ host: '127.0.0.1'
14
+ port: 3306
15
+ username: 'root'
16
+ password: 'root'
17
+ <% elsif adapter == 'oracle_enhanced' %>
18
+ host: '127.0.0.1/xe'
19
+ username: <%= ENV.fetch('USER') %>
20
+ password: <%= ENV.fetch('USER') %>
21
+ database: 'xe'
22
+ <% elsif adapter == 'sqlite3' %>
23
+ # database: ':memory:'
24
+ database: db/ajax_datatables_rails.sqlite3
25
+ <% end %>
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.routes.draw do
4
+ # Add your own routes here, or remove this file if you don't have need for it.
5
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ service: Disk
3
+ root: /tmp/ajax-datatables-rails/tmp/storage
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveRecord::Schema.define do
4
+ create_table :users, force: true do |t|
5
+ t.string :username
6
+ t.string :email
7
+ t.string :first_name
8
+ t.string :last_name
9
+ t.integer :post_id
10
+
11
+ t.timestamps null: false
12
+ end
13
+ end
@@ -0,0 +1 @@
1
+ *.log
File without changes
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :user do |f|
5
+ f.username { Faker::Internet.user_name }
6
+ f.email { Faker::Internet.email }
7
+ f.first_name { Faker::Name.first_name }
8
+ f.last_name { Faker::Name.last_name }
9
+ f.post_id { (1..100).to_a.sample }
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ wget 'https://github.com/cbandy/travis-oracle/archive/v2.0.3.tar.gz'
4
+ mkdir -p ~/.travis/oracle
5
+ tar xz --strip-components 1 -C ~/.travis/oracle -f v2.0.3.tar.gz
6
+
7
+ if [ -n ${CUSTOM_ORACLE_FILE} ]; then
8
+ wget -q ${CUSTOM_ORACLE_FILE} -O ~/.travis/oracle/oracle-xe-11.2.0-1.0.x86_64.rpm.zip
9
+ else
10
+ ~/.travis/oracle/download.sh
11
+ fi
12
+
13
+ ~/.travis/oracle/install.sh
14
+
15
+ # in dev env: sqlplus system/password@localhost/XE
16
+ "${ORACLE_HOME}/bin/sqlplus" -L -S / AS SYSDBA <<SQL
17
+ ALTER USER ${USER} IDENTIFIED BY ${USER};
18
+ SQL
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'combustion'
4
+
5
+ Combustion.path = 'spec/dummy'
6
+ Combustion.initialize! :active_record, :action_controller
7
+
8
+ require 'simplecov'
9
+ require 'rspec'
10
+ require 'rspec/retry'
11
+ require 'database_cleaner'
12
+ require 'factory_bot'
13
+ require 'faker'
1
14
  require 'pry'
2
- require 'rails'
3
- require 'active_record'
4
- require 'ajax-datatables-rails'
5
15
 
6
- ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
16
+ # Start Simplecov
17
+ SimpleCov.start do
18
+ add_filter 'spec/'
19
+ end
20
+
21
+ # Configure RSpec
22
+ RSpec.configure do |config|
23
+ config.include FactoryBot::Syntax::Methods
24
+
25
+ config.before(:suite) do
26
+ FactoryBot.find_definitions
27
+ end
28
+
29
+ config.color = true
30
+ config.fail_fast = false
31
+
32
+ config.order = :random
33
+ Kernel.srand config.seed
34
+
35
+ config.expect_with :rspec do |c|
36
+ c.syntax = :expect
37
+ end
38
+
39
+ config.before(:suite) do
40
+ DatabaseCleaner.clean_with(:truncation)
41
+ end
42
+
43
+ config.before do
44
+ DatabaseCleaner.strategy = :transaction
45
+ end
46
+
47
+ config.before do
48
+ DatabaseCleaner.start
49
+ end
50
+
51
+ config.after do
52
+ DatabaseCleaner.clean
53
+ end
54
+
55
+ # disable monkey patching
56
+ # see: https://relishapp.com/rspec/rspec-core/v/3-8/docs/configuration/zero-monkey-patching-mode
57
+ config.disable_monkey_patching!
58
+
59
+ if ENV.key?('GITHUB_ACTIONS')
60
+ config.around do |ex|
61
+ ex.run_with_retry retry: 3
62
+ end
63
+ end
64
+ end
65
+
66
+ class RunningSpec
67
+ def self.sqlite?
68
+ ENV['DB_ADAPTER'] == 'sqlite3'
69
+ end
70
+
71
+ def self.oracle?
72
+ ENV['DB_ADAPTER'] == 'oracle_enhanced'
73
+ end
74
+
75
+ def self.mysql?
76
+ ENV['DB_ADAPTER'] == 'mysql2'
77
+ end
78
+
79
+ def self.postgresql?
80
+ ENV['DB_ADAPTER'] == 'postgresql'
81
+ end
82
+ end
83
+
84
+ # Require our gem
85
+ require 'ajax-datatables-rails'
7
86
 
8
- load File.dirname(__FILE__) + '/schema.rb'
9
- require File.dirname(__FILE__) + '/test_models.rb'
87
+ # Load test helpers
88
+ Dir[File.dirname(__FILE__) + '/support/**/*.rb'].sort.each { |f| require f }
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ComplexDatatable < AjaxDatatablesRails::ActiveRecord
4
+ def view_columns
5
+ @view_columns ||= {
6
+ username: { source: 'User.username' },
7
+ email: { source: 'User.email' },
8
+ first_name: { source: 'User.first_name' },
9
+ last_name: { source: 'User.last_name' },
10
+ full_name: { source: 'full_name' },
11
+ post_id: { source: 'User.post_id', orderable: false },
12
+ created_at: { source: 'User.created_at' },
13
+ }
14
+ end
15
+
16
+ def data
17
+ records.map do |record|
18
+ {
19
+ username: record.username,
20
+ email: record.email,
21
+ first_name: record.first_name,
22
+ last_name: record.last_name,
23
+ full_name: record.full_name,
24
+ post_id: record.post_id,
25
+ created_at: record.created_at,
26
+ }
27
+ end
28
+ end
29
+
30
+ def get_raw_records
31
+ User.all
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ComplexDatatableArray < ComplexDatatable
4
+ def data
5
+ records.map do |record|
6
+ [
7
+ record.username,
8
+ record.email,
9
+ record.first_name,
10
+ record.last_name,
11
+ record.post_id,
12
+ record.created_at,
13
+ ]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DatatableCondDate < ComplexDatatable
4
+ def view_columns
5
+ super.deep_merge(created_at: { cond: :date_range })
6
+ end
7
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DatatableCondEq < ComplexDatatable
4
+ def view_columns
5
+ super.deep_merge(post_id: { cond: :eq })
6
+ end
7
+ end
8
+
9
+ class DatatableCondNotEq < ComplexDatatable
10
+ def view_columns
11
+ super.deep_merge(post_id: { cond: :not_eq })
12
+ end
13
+ end
14
+
15
+ class DatatableCondLt < ComplexDatatable
16
+ def view_columns
17
+ super.deep_merge(post_id: { cond: :lt })
18
+ end
19
+ end
20
+
21
+ class DatatableCondGt < ComplexDatatable
22
+ def view_columns
23
+ super.deep_merge(post_id: { cond: :gt })
24
+ end
25
+ end
26
+
27
+ class DatatableCondLteq < ComplexDatatable
28
+ def view_columns
29
+ super.deep_merge(post_id: { cond: :lteq })
30
+ end
31
+ end
32
+
33
+ class DatatableCondGteq < ComplexDatatable
34
+ def view_columns
35
+ super.deep_merge(post_id: { cond: :gteq })
36
+ end
37
+ end
38
+
39
+ class DatatableCondIn < ComplexDatatable
40
+ def view_columns
41
+ super.deep_merge(post_id: { cond: :in })
42
+ end
43
+ end
44
+
45
+ class DatatableCondInWithRegex < DatatableCondIn
46
+ def view_columns
47
+ super.deep_merge(post_id: { cond: :in, use_regex: false, orderable: true, formatter: ->(str) { cast_regex_value(str) } })
48
+ end
49
+
50
+ def cast_regex_value(value)
51
+ value.split('|').map(&:to_i)
52
+ end
53
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DatatableCondProc < ComplexDatatable
4
+ def view_columns
5
+ super.deep_merge(username: { cond: custom_filter })
6
+ end
7
+
8
+ private
9
+
10
+ def custom_filter
11
+ ->(column, value) { ::Arel::Nodes::SqlLiteral.new(column.field.to_s).matches("#{value}%") }
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DatatableCondStartWith < ComplexDatatable
4
+ def view_columns
5
+ super.deep_merge(first_name: { cond: :start_with })
6
+ end
7
+ end
8
+
9
+ class DatatableCondEndWith < ComplexDatatable
10
+ def view_columns
11
+ super.deep_merge(last_name: { cond: :end_with })
12
+ end
13
+ end
14
+
15
+ class DatatableCondLike < ComplexDatatable
16
+ def view_columns
17
+ super.deep_merge(email: { cond: :like })
18
+ end
19
+ end
20
+
21
+ class DatatableCondStringEq < ComplexDatatable
22
+ def view_columns
23
+ super.deep_merge(email: { cond: :string_eq })
24
+ end
25
+ end
26
+
27
+ class DatatableCondStringIn < ComplexDatatable
28
+ def view_columns
29
+ super.deep_merge(email: { cond: :string_in, formatter: ->(o) { o.split('|') } })
30
+ end
31
+ end
32
+
33
+ class DatatableCondNullValue < ComplexDatatable
34
+ def view_columns
35
+ super.deep_merge(email: { cond: :null_value })
36
+ end
37
+ end
38
+
39
+ class DatatableWithFormater < ComplexDatatable
40
+ def view_columns
41
+ super.deep_merge(last_name: { formatter: ->(o) { o.upcase } })
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DatatableCondUnknown < ComplexDatatable
4
+ def view_columns
5
+ super.deep_merge(username: { cond: :foo })
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DatatableCustomColumn < ComplexDatatable
4
+ def view_columns
5
+ super.deep_merge(full_name: { cond: filter_full_name })
6
+ end
7
+
8
+ def get_raw_records
9
+ User.select("*, CONCAT(first_name, ' ', last_name) as full_name")
10
+ end
11
+
12
+ private
13
+
14
+ def filter_full_name
15
+ ->(_column, value) { ::Arel::Nodes::SqlLiteral.new("CONCAT(first_name, ' ', last_name)").matches("#{value}%") }
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DatatableOrderNullsLast < ComplexDatatable
4
+ def view_columns
5
+ super.deep_merge(email: { nulls_last: true })
6
+ end
7
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/MethodLength
4
+ def sample_params
5
+ ActionController::Parameters.new(
6
+ {
7
+ 'draw' => '1',
8
+ 'columns' => {
9
+ '0' => {
10
+ 'data' => 'username', 'name' => '', 'searchable' => 'true', 'orderable' => 'true',
11
+ 'search' => {
12
+ 'value' => '', 'regex' => 'false'
13
+ }
14
+ },
15
+ '1' => {
16
+ 'data' => 'email', 'name' => '', 'searchable' => 'true', 'orderable' => 'true',
17
+ 'search' => {
18
+ 'value' => '', 'regex' => 'false'
19
+ }
20
+ },
21
+ '2' => {
22
+ 'data' => 'first_name', 'name' => '', 'searchable' => 'true', 'orderable' => 'false',
23
+ 'search' => {
24
+ 'value' => '', 'regex' => 'false'
25
+ }
26
+ },
27
+ '3' => {
28
+ 'data' => 'last_name', 'name' => '', 'searchable' => 'true', 'orderable' => 'true',
29
+ 'search' => {
30
+ 'value' => '', 'regex' => 'false'
31
+ }
32
+ },
33
+ '4' => {
34
+ 'data' => 'full_name', 'name' => '', 'searchable' => 'true', 'orderable' => 'true',
35
+ 'search' => {
36
+ 'value' => '', 'regex' => 'false'
37
+ }
38
+ },
39
+ '5' => {
40
+ 'data' => 'post_id', 'name' => '', 'searchable' => 'true', 'orderable' => 'true',
41
+ 'search' => {
42
+ 'value' => '', 'regex' => 'false'
43
+ }
44
+ },
45
+ '6' => {
46
+ 'data' => 'created_at', 'name' => '', 'searchable' => 'true', 'orderable' => 'true',
47
+ 'search' => {
48
+ 'value' => '', 'regex' => 'false'
49
+ }
50
+ },
51
+ },
52
+ 'order' => {
53
+ '0' => { 'column' => '0', 'dir' => 'asc' },
54
+ },
55
+ 'start' => '0', 'length' => '10', 'search' => {
56
+ 'value' => '', 'regex' => 'false'
57
+ },
58
+ '_' => '1423364387185'
59
+ }
60
+ )
61
+ end
62
+
63
+ def sample_params_json
64
+ hash_params = sample_params.to_unsafe_h
65
+ hash_params['columns'] = hash_params['columns'].values
66
+ hash_params['order'] = hash_params['order'].values
67
+ ActionController::Parameters.new(hash_params)
68
+ end
69
+ # rubocop:enable Metrics/MethodLength
70
+
71
+ def nulls_last_sql(datatable)
72
+ case datatable.db_adapter
73
+ when :pg, :postgresql, :postgres, :oracle
74
+ 'NULLS LAST'
75
+ when :mysql, :mysql2, :sqlite, :sqlite3
76
+ 'IS NULL'
77
+ else
78
+ raise 'unsupported database adapter'
79
+ end
80
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class User < ActiveRecord::Base
4
+ def full_name
5
+ "#{first_name} #{last_name}"
6
+ end
7
+ end