diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 805300ac..9d1a58d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,20 +10,37 @@ on: - '**' schedule: - cron: '0 4 1 * *' + # Run workflow manually + workflow_dispatch: jobs: + rubocop: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.1' + + - name: Bundler + run: bundle install + + - name: Rubocop + run: bin/rubocop + rspec: runs-on: ubuntu-latest - env: - ORACLE_COOKIE: sqldev - ORACLE_FILE: oracle11g/xe/oracle-xe-11.2.0-1.0.x86_64.rpm.zip - ORACLE_HOME: /u01/app/oracle/product/11.2.0/xe - ORACLE_SID: XE + env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.rails }}_with_${{ matrix.adapter }}.gemfile services: postgres: - image: 'postgres:13' + image: 'postgres:16' ports: ['5432:5432'] env: POSTGRES_PASSWORD: postgres @@ -52,73 +69,60 @@ jobs: fail-fast: false matrix: ruby: + - '3.4' + - '3.3' - '3.2' - '3.1' - - '3.0' - - '2.7' - 'head' rails: - - rails_7.0.4 - - rails_6.1.7 - - rails_6.0.6 + - rails_8.0 + - rails_7.2 + - rails_7.1 adapter: - sqlite3 - postgresql - mysql2 - - oracle_enhanced + - postgis + # Disabled for now: + # Rails 7.0: trilogy_auth_recv: caching_sha2_password requires either TCP with TLS or a unix socket: TRILOGY_UNSUPPORTED + # Rails 7.1: unknown keyword: :uses_transaction + # Rails 7.2: NotImplementedError + # - trilogy + exclude: + # Rails 8.0 needs Ruby > 3.2 + - rails: 'rails_8.0' + ruby: '3.1' steps: - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} + uses: actions/checkout@v4 - name: Set DB Adapter env: - RAILS_VERSION: ${{ matrix.rails }} DB_ADAPTER: ${{ matrix.adapter }} - CUSTOM_ORACLE_FILE: ${{ secrets.CUSTOM_ORACLE_FILE }} # See: https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-README.md#mysql run: | - if [ "${DB_ADAPTER}" = "mysql2" ]; then + if [[ "${DB_ADAPTER}" == "mysql2" ]] || [[ "${DB_ADAPTER}" == "trilogy" ]]; then sudo systemctl start mysql.service mysql -u root -proot -e 'create database ajax_datatables_rails;' fi - if [ "${DB_ADAPTER}" = "oracle_enhanced" ]; then - ./spec/install_oracle.sh - # Fix error : libnnz11.so: cannot open shared object file: No such file or directory - sudo ln -s ${ORACLE_HOME}/lib/libnnz11.so /usr/lib/libnnz11.so - fi - - - name: Setup Ruby cache - uses: actions/cache@v3 + - name: Setup Ruby + uses: ruby/setup-ruby@v1 with: - path: vendor/bundle - key: ${{ runner.os }}-gems-${{ matrix.ruby }}-${{ matrix.rails }}-${{ matrix.adapter }}-${{ hashFiles('**/Gemfile.lock') }} - restore-keys: | - ${{ runner.os }}-gems-${{ matrix.ruby }}-${{ matrix.rails }}-${{ matrix.adapter }}- - - - name: Bundle + ruby-version: ${{ matrix.ruby }} + bundler-cache: true env: - RAILS_VERSION: ${{ matrix.rails }} DB_ADAPTER: ${{ matrix.adapter }} - BUNDLE_GEMFILE: gemfiles/${{ matrix.rails }}.gemfile - run: | - gem install bundler - bundle config path vendor/bundle - bundle install --jobs 4 --retry 3 - - name: RSpec & publish code coverage - uses: paambaati/codeclimate-action@v3.2.0 + - name: Run RSpec env: - RAILS_VERSION: ${{ matrix.rails }} DB_ADAPTER: ${{ matrix.adapter }} - BUNDLE_GEMFILE: gemfiles/${{ matrix.rails }}.gemfile - CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + run: bin/rspec + + - name: Publish code coverage + uses: qltysh/qlty-action/coverage@v1 with: - coverageCommand: bin/rake + token: ${{ secrets.QLTY_COVERAGE_TOKEN }} + files: coverage/coverage.json diff --git a/.github/workflows/ci_oracle.yml b/.github/workflows/ci_oracle.yml new file mode 100644 index 00000000..7df46ebf --- /dev/null +++ b/.github/workflows/ci_oracle.yml @@ -0,0 +1,104 @@ +--- +name: CI Oracle + +on: + push: + branches: + - '**' + pull_request: + branches: + - '**' + schedule: + - cron: '0 4 1 * *' + # Run workflow manually + workflow_dispatch: + +jobs: + rspec: + runs-on: ubuntu-latest + + env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps + BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.rails }}_with_${{ matrix.adapter }}.gemfile + ORACLE_HOME: /opt/oracle/instantclient_23_8 + LD_LIBRARY_PATH: /opt/oracle/instantclient_23_8 + TNS_ADMIN: ./ci/network/admin + DATABASE_SYS_PASSWORD: Oracle18 + DATABASE_NAME: FREEPDB1 + + services: + oracle: + image: gvenzl/oracle-free:latest + ports: + - 1521:1521 + env: + TZ: Europe/Paris + ORACLE_PASSWORD: Oracle18 + options: >- + --health-cmd healthcheck.sh + --health-interval 10s + --health-timeout 5s + --health-retries 10 + + strategy: + fail-fast: false + matrix: + ruby: + - '3.4' + - '3.3' + - '3.2' + - '3.1' + - 'head' + rails: + - rails_8.0 + - rails_7.2 + - rails_7.1 + adapter: + - oracle_enhanced + exclude: + - rails: 'rails_8.0' + ruby: '3.1' + adapter: 'oracle_enhanced' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create symbolic link for libaio library compatibility + run: | + sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 + + - name: Download Oracle instant client + run: | + wget -q https://download.oracle.com/otn_software/linux/instantclient/2380000/instantclient-basic-linux.x64-23.8.0.25.04.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2380000/instantclient-sdk-linux.x64-23.8.0.25.04.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2380000/instantclient-sqlplus-linux.x64-23.8.0.25.04.zip + + - name: Install Oracle instant client + run: | + sudo unzip instantclient-basic-linux.x64-23.8.0.25.04.zip -d /opt/oracle/ + sudo unzip -o instantclient-sdk-linux.x64-23.8.0.25.04.zip -d /opt/oracle/ + sudo unzip -o instantclient-sqlplus-linux.x64-23.8.0.25.04.zip -d /opt/oracle/ + echo "/opt/oracle/instantclient_23_8" >> $GITHUB_PATH + + - name: Create database user + run: | + ./ci/setup_accounts.sh + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + env: + DB_ADAPTER: ${{ matrix.adapter }} + + - name: Run RSpec + env: + DB_ADAPTER: ${{ matrix.adapter }} + run: bin/rspec + + - name: Publish code coverage + uses: qltysh/qlty-action/coverage@v1 + with: + token: ${{ secrets.QLTY_COVERAGE_TOKEN }} + files: coverage/coverage.json diff --git a/.gitignore b/.gitignore index 5c8920df..bb537c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ spec/dummy/db/*.sqlite3 spec/dummy/db/*.sqlite3-journal spec/dummy/log/*.log spec/dummy/tmp/ + +# Ignore MacOS files +.DS_Store diff --git a/.qlty/qlty.toml b/.qlty/qlty.toml new file mode 100644 index 00000000..75811a42 --- /dev/null +++ b/.qlty/qlty.toml @@ -0,0 +1,35 @@ +config_version = "0" + +[[source]] +name = "default" +default = true + +[[plugin]] +name = "actionlint" + +[[plugin]] +name = "checkov" +version = "3.2.49" + +[[plugin]] +name = "markdownlint" +version = "0.31.1" + +[[plugin]] +name = "osv-scanner" + +[[plugin]] +name = "prettier" +version = "2.8.4" + +[[plugin]] +name = "ripgrep" + +[[plugin]] +name = "trivy" + +[[plugin]] +name = "trufflehog" + +[[plugin]] +name = "yamllint" diff --git a/.rspec b/.rspec index 4e1e0d2f..372b5acf 100644 --- a/.rspec +++ b/.rspec @@ -1 +1 @@ ---color +--warnings diff --git a/.rubocop.yml b/.rubocop.yml index ba60a761..63074818 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,22 +1,49 @@ +--- +plugins: + - rubocop-factory_bot + - rubocop-performance + - rubocop-rake + - rubocop-rspec + AllCops: NewCops: enable - SuggestExtensions: false - TargetRubyVersion: 2.7 + TargetRubyVersion: 3.1 Exclude: - bin/* - - lib/generators/**/*.rb - gemfiles/* - - spec/**/* + - spec/dummy/**/* + +######### +# STYLE # +######### Style/Documentation: Enabled: false -Layout/HashAlignment: - Enabled: false +Style/TrailingCommaInArrayLiteral: + EnforcedStyleForMultiline: comma + +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: comma + +Style/BlockDelimiters: + AllowedPatterns: ['expect'] + +########## +# LAYOUT # +########## + +Layout/LineLength: + Max: 150 + Exclude: + - ajax-datatables-rails.gemspec Layout/EmptyLines: Enabled: false +Layout/EmptyLineBetweenDefs: + Enabled: false + Layout/EmptyLinesAroundClassBody: Enabled: false @@ -26,33 +53,33 @@ Layout/EmptyLinesAroundBlockBody: Layout/EmptyLinesAroundModuleBody: Enabled: false -Layout/EmptyLineBetweenDefs: - Enabled: false - -Metrics/CyclomaticComplexity: - Max: 7 +Layout/HashAlignment: + EnforcedColonStyle: table + EnforcedHashRocketStyle: table -Metrics/LineLength: - Enabled: false +########## +# NAMING # +########## -Metrics/BlockLength: - Max: 30 +Naming/FileName: + Exclude: + - lib/ajax-datatables-rails.rb -Metrics/MethodLength: - Max: 15 +######### +# RSPEC # +######### -Metrics/ClassLength: - Max: 130 +RSpec/MultipleExpectations: + Max: 7 -Naming/AccessorMethodName: - Enabled: false +RSpec/NestedGroups: + Max: 6 -Naming/FileName: - Exclude: - - lib/ajax-datatables-rails.rb +RSpec/ExampleLength: + Max: 9 -Style/TrailingCommaInArrayLiteral: - EnforcedStyleForMultiline: comma +RSpec/MultipleMemoizedHelpers: + Max: 6 -Style/TrailingCommaInHashLiteral: - EnforcedStyleForMultiline: comma +RSpec/NotToNot: + EnforcedStyle: to_not diff --git a/Appraisals b/Appraisals index 4d4315de..d39912b0 100644 --- a/Appraisals +++ b/Appraisals @@ -1,28 +1,118 @@ # frozen_string_literal: true -require 'yaml' - -rails_versions = YAML.safe_load(File.read('appraisal.yml')) - -rails_versions.each do |version, gems| - appraise "rails_#{version}" do - gem 'rails', version - gems.each do |name, opts| - if opts['install_if'] - install_if opts['install_if'] do - if opts['version'].empty? - gem name - else - gem name, opts['version'] - end - end - else - if opts['version'].empty? - gem name - else - gem name, opts['version'] - end - end - end - end +############### +# RAILS 7.1.0 # +############### + +appraise 'rails_7.1_with_postgresql' do + gem 'rails', '~> 7.1.0' + gem 'pg' +end + +appraise 'rails_7.1_with_sqlite3' do + gem 'rails', '~> 7.1.0' + gem 'sqlite3', '~> 1.5.0' + remove_gem 'pg' +end + +appraise 'rails_7.1_with_mysql2' do + gem 'rails', '~> 7.1.0' + gem 'mysql2' + remove_gem 'pg' +end + +appraise 'rails_7.1_with_trilogy' do + gem 'rails', '~> 7.1.0' + gem 'activerecord-trilogy-adapter' + remove_gem 'pg' +end + +appraise 'rails_7.1_with_oracle_enhanced' do + gem 'rails', '~> 7.1.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 7.1.0' + remove_gem 'pg' +end + +appraise 'rails_7.1_with_postgis' do + gem 'rails', '~> 7.1.0' + gem 'pg' + gem 'activerecord-postgis-adapter', '~> 9.0.0' +end + +############### +# RAILS 7.2.0 # +############### + +appraise 'rails_7.2_with_postgresql' do + gem 'rails', '~> 7.2.0' + gem 'pg' +end + +appraise 'rails_7.2_with_sqlite3' do + gem 'rails', '~> 7.2.0' + gem 'sqlite3', '~> 1.5.0' + remove_gem 'pg' +end + +appraise 'rails_7.2_with_mysql2' do + gem 'rails', '~> 7.2.0' + gem 'mysql2' + remove_gem 'pg' +end + +appraise 'rails_7.2_with_trilogy' do + gem 'rails', '~> 7.2.0' + gem 'activerecord-trilogy-adapter' + remove_gem 'pg' +end + +appraise 'rails_7.2_with_oracle_enhanced' do + gem 'rails', '~> 7.2.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 7.2.0' + remove_gem 'pg' +end + +appraise 'rails_7.2_with_postgis' do + gem 'rails', '~> 7.2.0' + gem 'pg' + gem 'activerecord-postgis-adapter', '~> 10.0.0' +end + +############### +# RAILS 8.0.0 # +############### + +appraise 'rails_8.0_with_postgresql' do + gem 'rails', '~> 8.0.0' + gem 'pg' +end + +appraise 'rails_8.0_with_sqlite3' do + gem 'rails', '~> 8.0.0' + gem 'sqlite3' + remove_gem 'pg' +end + +appraise 'rails_8.0_with_mysql2' do + gem 'rails', '~> 8.0.0' + gem 'mysql2' + remove_gem 'pg' +end + +appraise 'rails_8.0_with_trilogy' do + gem 'rails', '~> 8.0.0' + gem 'activerecord-trilogy-adapter' + remove_gem 'pg' +end + +appraise 'rails_8.0_with_oracle_enhanced' do + gem 'rails', '~> 8.0.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 8.0.0' + remove_gem 'pg' +end + +appraise 'rails_8.0_with_postgis' do + gem 'rails', '~> 8.0.0' + gem 'pg' + gem 'activerecord-postgis-adapter', '~> 11.0.0' end diff --git a/CHANGELOG.md b/CHANGELOG.md index cf677fbb..10407924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # CHANGELOG +## 1.6.0 (2025-??-??) + +* Remove dead code +* Implementing `searchable: false` tests +* Improve objects shape +* Fix Rubocop offenses +* Make gem smaller +* Drop support of Rails 6.0 +* Drop support of Rails 6.1 +* Drop support of Rails 7.0 +* Drop support of Ruby 2.7 +* Drop support of Ruby 3.0 +* Add support for Rails 7.2 +* Add support for Rails 8.0 +* Add support for Ruby 3.4 + +## 1.5.0 (2024-04-08) + +* Add support for grouped results (merge: [#419](https://github.com/jbox-web/ajax-datatables-rails/pull/419)) +* Fix server-side out of order ajax responses (merge: [#418](https://github.com/jbox-web/ajax-datatables-rails/pull/418)) +* Add support for postgis adapter (merge: [#417](https://github.com/jbox-web/ajax-datatables-rails/pull/417)) +* Add support for trilogy adapter (merge: [#423](https://github.com/jbox-web/ajax-datatables-rails/pull/423)) +* Drop support of Rails 5.2 +* Add support for Rails 7.1 +* Add support for Ruby 3.2 +* Add support for Ruby 3.3 + +This is the last version to support Rails 6.0.x and Ruby 2.7.x. + ## 1.4.0 (2022-12-18) * Improve tests @@ -7,7 +36,7 @@ * Drop support of Ruby 2.5 * Drop support of Ruby 2.6 * Add support of Ruby 3.1 -* Add support of Rails 7 +* Add support of Rails 7.0 * Fix: prevent establishing ActiveRecord connection on startup ## 1.3.1 (2021-02-09) diff --git a/Gemfile b/Gemfile index 063266df..cc821440 100644 --- a/Gemfile +++ b/Gemfile @@ -4,4 +4,26 @@ source 'https://rubygems.org/' gemspec -gem 'appraisal', git: 'https://github.com/n-rodriguez/appraisal.git', branch: 'wip/combustion' +# Dev libs +gem 'appraisal', git: 'https://github.com/thoughtbot/appraisal.git' +gem 'combustion' +gem 'database_cleaner' +gem 'factory_bot' +gem 'faker' +gem 'generator_spec' +gem 'puma' +gem 'rake' +gem 'rspec' +gem 'rspec-rebound' +gem 'simplecov' + +# Fallback to pg in dev/local environment +gem 'pg' + +# Dev tools / linter +gem 'guard-rspec', require: false +gem 'rubocop', require: false +gem 'rubocop-factory_bot', require: false +gem 'rubocop-performance', require: false +gem 'rubocop-rake', require: false +gem 'rubocop-rspec', require: false diff --git a/Guardfile b/Guardfile index 15175960..5a44087b 100644 --- a/Guardfile +++ b/Guardfile @@ -1,6 +1,6 @@ # frozen_string_literal: true -guard :rspec, cmd: 'bundle exec rspec' do +guard :rspec, cmd: 'bin/rspec' do require 'guard/rspec/dsl' dsl = Guard::RSpec::Dsl.new(self) diff --git a/README.md b/README.md index 6577bd97..62fd2b29 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,10 @@ It's tested against : -* Rails 6.0.6 / 6.1.7 / 7.0.4 -* Ruby 2.7 / 3.0 / 3.1 -* SQLite3 -* Postgresql 13 -* MySQL 8 -* Oracle XE 11.2 (thanks to [travis-oracle](https://github.com/cbandy/travis-oracle)) +* Rails: 7.1 / 7.2 / 8.0 +* Ruby: 3.1 / 3.2 / 3.3 / 3.4 +* Databases: MySQL 8 / SQLite3 / Postgresql 16 / Oracle XE 11.2 (thanks to [travis-oracle](https://github.com/cbandy/travis-oracle)) +* Adapters: sqlite / mysql2 / trilogy / postgres / postgis / oracle ## Description diff --git a/Rakefile b/Rakefile index 5ae06112..ad26ae7d 100644 --- a/Rakefile +++ b/Rakefile @@ -5,12 +5,3 @@ require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) task default: :spec - -task :console do - require 'pry' - require 'rails' - require 'ajax-datatables-rails' - puts 'Loaded AjaxDatatablesRails' - ARGV.clear - Pry.start -end diff --git a/ajax-datatables-rails.gemspec b/ajax-datatables-rails.gemspec index 09facdcf..69e22ea8 100644 --- a/ajax-datatables-rails.gemspec +++ b/ajax-datatables-rails.gemspec @@ -13,34 +13,17 @@ Gem::Specification.new do |s| s.description = "A wrapper around datatable's ajax methods that allow synchronization with server-side pagination in a rails app" s.license = 'MIT' s.metadata = { - 'homepage_uri' => 'https://github.com/jbox-web/ajax-datatables-rails', - 'changelog_uri' => 'https://github.com/jbox-web/ajax-datatables-rails/blob/master/CHANGELOG.md', - 'source_code_uri' => 'https://github.com/jbox-web/ajax-datatables-rails', - 'bug_tracker_uri' => 'https://github.com/jbox-web/ajax-datatables-rails/issues', + 'homepage_uri' => 'https://github.com/jbox-web/ajax-datatables-rails', + 'changelog_uri' => 'https://github.com/jbox-web/ajax-datatables-rails/blob/master/CHANGELOG.md', + 'source_code_uri' => 'https://github.com/jbox-web/ajax-datatables-rails', + 'bug_tracker_uri' => 'https://github.com/jbox-web/ajax-datatables-rails/issues', + 'rubygems_mfa_required' => 'true', } - s.required_ruby_version = '>= 2.7.0' + s.required_ruby_version = '>= 3.1.0' - s.files = `git ls-files`.split("\n") + s.files = Dir['README.md', 'CHANGELOG.md', 'LICENSE', 'lib/**/*.rb', 'lib/**/*.erb'] - s.add_runtime_dependency 'rails', '>= 6.0' - s.add_runtime_dependency 'zeitwerk' - - s.add_development_dependency 'activerecord-oracle_enhanced-adapter' - s.add_development_dependency 'appraisal' - s.add_development_dependency 'combustion', '~> 1.3' - s.add_development_dependency 'database_cleaner' - s.add_development_dependency 'factory_bot' - s.add_development_dependency 'faker' - s.add_development_dependency 'generator_spec' - s.add_development_dependency 'guard-rspec' - s.add_development_dependency 'pg' - s.add_development_dependency 'pry' - s.add_development_dependency 'puma' - s.add_development_dependency 'rake' - s.add_development_dependency 'rspec' - s.add_development_dependency 'rspec-retry' - s.add_development_dependency 'rubocop' - s.add_development_dependency 'simplecov' - s.add_development_dependency 'sqlite3', '~> 1.4.0' + s.add_dependency 'rails', '>= 7.1' + s.add_dependency 'zeitwerk' end diff --git a/appraisal.yml b/appraisal.yml deleted file mode 100644 index d0baf6e2..00000000 --- a/appraisal.yml +++ /dev/null @@ -1,42 +0,0 @@ ---- -6.0.6: - sqlite3: - version: ~> 1.4.0 - install_if: '-> { ENV["DB_ADAPTER"] == "sqlite3" }' - mysql2: - version: '' - install_if: '-> { ENV["DB_ADAPTER"] == "mysql2" }' - activerecord-oracle_enhanced-adapter: - version: ~> 6.0.0 - install_if: '-> { ENV["DB_ADAPTER"] == "oracle_enhanced" }' - ruby-oci8: - version: '' - install_if: '-> { ENV["DB_ADAPTER"] == "oracle_enhanced" }' - -6.1.7: - sqlite3: - version: ~> 1.4.0 - install_if: '-> { ENV["DB_ADAPTER"] == "sqlite3" }' - mysql2: - version: '' - install_if: '-> { ENV["DB_ADAPTER"] == "mysql2" }' - activerecord-oracle_enhanced-adapter: - version: ~> 6.1.0 - install_if: '-> { ENV["DB_ADAPTER"] == "oracle_enhanced" }' - ruby-oci8: - version: '' - install_if: '-> { ENV["DB_ADAPTER"] == "oracle_enhanced" }' - -7.0.4: - sqlite3: - version: ~> 1.4.0 - install_if: '-> { ENV["DB_ADAPTER"] == "sqlite3" }' - mysql2: - version: '' - install_if: '-> { ENV["DB_ADAPTER"] == "mysql2" }' - activerecord-oracle_enhanced-adapter: - version: ~> 7.0.0 - install_if: '-> { ENV["DB_ADAPTER"] == "oracle_enhanced" }' - ruby-oci8: - version: '' - install_if: '-> { ENV["DB_ADAPTER"] == "oracle_enhanced" }' diff --git a/bin/_guard-core b/bin/_guard-core index cd565c3a..9105b28b 100755 --- a/bin/_guard-core +++ b/bin/_guard-core @@ -8,14 +8,12 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) -bundle_binstub = File.expand_path("../bundle", __FILE__) +bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. diff --git a/bin/appraisal b/bin/appraisal index 0e7ba65d..5038ce52 100755 --- a/bin/appraisal +++ b/bin/appraisal @@ -8,14 +8,12 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) -bundle_binstub = File.expand_path("../bundle", __FILE__) +bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. diff --git a/bin/bundle b/bin/bundle index a71368e3..50da5fdf 100755 --- a/bin/bundle +++ b/bin/bundle @@ -27,7 +27,7 @@ m = Module.new do bundler_version = nil update_index = nil ARGV.each_with_index do |a, i| - if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN) bundler_version = a end next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ @@ -41,13 +41,13 @@ m = Module.new do gemfile = ENV["BUNDLE_GEMFILE"] return gemfile if gemfile && !gemfile.empty? - File.expand_path("../../Gemfile", __FILE__) + File.expand_path("../Gemfile", __dir__) end def lockfile lockfile = case File.basename(gemfile) - when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, ".locked") else "#{gemfile}.lock" end File.expand_path(lockfile) @@ -60,24 +60,19 @@ m = Module.new do Regexp.last_match(1) end - def bundler_version - @bundler_version ||= - env_var_version || cli_arg_version || - lockfile_version - end - def bundler_requirement - return "#{Gem::Requirement.default}.a" unless bundler_version - - bundler_gem_version = Gem::Version.new(bundler_version) - - requirement = bundler_gem_version.approximate_recommendation + @bundler_requirement ||= + env_var_version || + cli_arg_version || + bundler_requirement_for(lockfile_version) + end - return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + def bundler_requirement_for(version) + return "#{Gem::Requirement.default}.a" unless version - requirement += ".a" if bundler_gem_version.prerelease? + bundler_gem_version = Gem::Version.new(version) - requirement + bundler_gem_version.approximate_recommendation end def load_bundler! diff --git a/bin/guard b/bin/guard index bcb966f4..ff444e0c 100755 --- a/bin/guard +++ b/bin/guard @@ -8,14 +8,12 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) -bundle_binstub = File.expand_path("../bundle", __FILE__) +bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. diff --git a/bin/rackup b/bin/rackup index 7023745e..6408c791 100755 --- a/bin/rackup +++ b/bin/rackup @@ -13,7 +13,7 @@ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. @@ -24,4 +24,4 @@ end require "rubygems" require "bundler/setup" -load Gem.bin_path("rack", "rackup") +load Gem.bin_path("rackup", "rackup") diff --git a/bin/rake b/bin/rake index 9275675e..4eb7d7bf 100755 --- a/bin/rake +++ b/bin/rake @@ -8,14 +8,12 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) -bundle_binstub = File.expand_path("../bundle", __FILE__) +bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. diff --git a/bin/rspec b/bin/rspec index a6c78521..cb53ebe5 100755 --- a/bin/rspec +++ b/bin/rspec @@ -8,14 +8,12 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) -bundle_binstub = File.expand_path("../bundle", __FILE__) +bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. diff --git a/bin/rubocop b/bin/rubocop index d0c48829..369a05be 100755 --- a/bin/rubocop +++ b/bin/rubocop @@ -8,14 +8,12 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) -bundle_binstub = File.expand_path("../bundle", __FILE__) +bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. diff --git a/ci/network/admin/tnsnames.ora b/ci/network/admin/tnsnames.ora new file mode 100644 index 00000000..d1ba8183 --- /dev/null +++ b/ci/network/admin/tnsnames.ora @@ -0,0 +1,15 @@ +FREEPDB1 = + (DESCRIPTION = + (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521)) + (CONNECT_DATA = + (SERVICE_NAME = FREEPDB1) + ) + ) + +XE = + (DESCRIPTION = + (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521)) + (CONNECT_DATA = + (SERVICE_NAME = XE) + ) + ) diff --git a/ci/setup_accounts.sh b/ci/setup_accounts.sh new file mode 100755 index 00000000..3ed4d2ff --- /dev/null +++ b/ci/setup_accounts.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -ev + +sqlplus sys/${DATABASE_SYS_PASSWORD}@${DATABASE_NAME} as sysdba< { ENV["DB_ADAPTER"] == "sqlite3" } do - gem "sqlite3", "~> 1.4.0" -end - -install_if -> { ENV["DB_ADAPTER"] == "mysql2" } do - gem "mysql2" -end - -install_if -> { ENV["DB_ADAPTER"] == "oracle_enhanced" } do - gem "activerecord-oracle_enhanced-adapter", "~> 6.0.0" - gem "ruby-oci8" -end - -gemspec path: "../" diff --git a/gemfiles/rails_6.1.7.gemfile b/gemfiles/rails_6.1.7.gemfile deleted file mode 100644 index 19b7fbd6..00000000 --- a/gemfiles/rails_6.1.7.gemfile +++ /dev/null @@ -1,21 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org/" - -gem "appraisal", git: "https://github.com/n-rodriguez/appraisal.git", branch: "wip/combustion" -gem "rails", "6.1.7" - -install_if -> { ENV["DB_ADAPTER"] == "sqlite3" } do - gem "sqlite3", "~> 1.4.0" -end - -install_if -> { ENV["DB_ADAPTER"] == "mysql2" } do - gem "mysql2" -end - -install_if -> { ENV["DB_ADAPTER"] == "oracle_enhanced" } do - gem "activerecord-oracle_enhanced-adapter", "~> 6.1.0" - gem "ruby-oci8" -end - -gemspec path: "../" diff --git a/gemfiles/rails_7.0.4.gemfile b/gemfiles/rails_7.0.4.gemfile deleted file mode 100644 index 0ec19b30..00000000 --- a/gemfiles/rails_7.0.4.gemfile +++ /dev/null @@ -1,21 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org/" - -gem "appraisal", git: "https://github.com/n-rodriguez/appraisal.git", branch: "wip/combustion" -gem "rails", "7.0.4" - -install_if -> { ENV["DB_ADAPTER"] == "sqlite3" } do - gem "sqlite3", "~> 1.4.0" -end - -install_if -> { ENV["DB_ADAPTER"] == "mysql2" } do - gem "mysql2" -end - -install_if -> { ENV["DB_ADAPTER"] == "oracle_enhanced" } do - gem "activerecord-oracle_enhanced-adapter", "~> 7.0.0" - gem "ruby-oci8" -end - -gemspec path: "../" diff --git a/gemfiles/rails_7.1_with_mysql2.gemfile b/gemfiles/rails_7.1_with_mysql2.gemfile new file mode 100644 index 00000000..168f0c11 --- /dev/null +++ b/gemfiles/rails_7.1_with_mysql2.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.1.0" +gem "mysql2" + +gemspec path: "../" diff --git a/gemfiles/rails_7.1_with_oracle_enhanced.gemfile b/gemfiles/rails_7.1_with_oracle_enhanced.gemfile new file mode 100644 index 00000000..20e36feb --- /dev/null +++ b/gemfiles/rails_7.1_with_oracle_enhanced.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.1.0" +gem "activerecord-oracle_enhanced-adapter", "~> 7.1.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.1_with_postgis.gemfile b/gemfiles/rails_7.1_with_postgis.gemfile new file mode 100644 index 00000000..699d0c5e --- /dev/null +++ b/gemfiles/rails_7.1_with_postgis.gemfile @@ -0,0 +1,26 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "pg" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.1.0" +gem "activerecord-postgis-adapter", "~> 9.0.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.1_with_postgresql.gemfile b/gemfiles/rails_7.1_with_postgresql.gemfile new file mode 100644 index 00000000..6dbde4a8 --- /dev/null +++ b/gemfiles/rails_7.1_with_postgresql.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "pg" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.1.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.1_with_sqlite3.gemfile b/gemfiles/rails_7.1_with_sqlite3.gemfile new file mode 100644 index 00000000..7641ede3 --- /dev/null +++ b/gemfiles/rails_7.1_with_sqlite3.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.1.0" +gem "sqlite3", "~> 1.5.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.1_with_trilogy.gemfile b/gemfiles/rails_7.1_with_trilogy.gemfile new file mode 100644 index 00000000..a62a7c41 --- /dev/null +++ b/gemfiles/rails_7.1_with_trilogy.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.1.0" +gem "activerecord-trilogy-adapter" + +gemspec path: "../" diff --git a/gemfiles/rails_7.2_with_mysql2.gemfile b/gemfiles/rails_7.2_with_mysql2.gemfile new file mode 100644 index 00000000..6b4fa44d --- /dev/null +++ b/gemfiles/rails_7.2_with_mysql2.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.2.0" +gem "mysql2" + +gemspec path: "../" diff --git a/gemfiles/rails_7.2_with_oracle_enhanced.gemfile b/gemfiles/rails_7.2_with_oracle_enhanced.gemfile new file mode 100644 index 00000000..c498dab6 --- /dev/null +++ b/gemfiles/rails_7.2_with_oracle_enhanced.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.2.0" +gem "activerecord-oracle_enhanced-adapter", "~> 7.2.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.2_with_postgis.gemfile b/gemfiles/rails_7.2_with_postgis.gemfile new file mode 100644 index 00000000..6a62fe31 --- /dev/null +++ b/gemfiles/rails_7.2_with_postgis.gemfile @@ -0,0 +1,26 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "pg" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.2.0" +gem "activerecord-postgis-adapter", "~> 10.0.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.2_with_postgresql.gemfile b/gemfiles/rails_7.2_with_postgresql.gemfile new file mode 100644 index 00000000..6c118407 --- /dev/null +++ b/gemfiles/rails_7.2_with_postgresql.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "pg" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.2.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.2_with_sqlite3.gemfile b/gemfiles/rails_7.2_with_sqlite3.gemfile new file mode 100644 index 00000000..8ee69bab --- /dev/null +++ b/gemfiles/rails_7.2_with_sqlite3.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.2.0" +gem "sqlite3", "~> 1.5.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.2_with_trilogy.gemfile b/gemfiles/rails_7.2_with_trilogy.gemfile new file mode 100644 index 00000000..cb3631c2 --- /dev/null +++ b/gemfiles/rails_7.2_with_trilogy.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 7.2.0" +gem "activerecord-trilogy-adapter" + +gemspec path: "../" diff --git a/gemfiles/rails_8.0_with_mysql2.gemfile b/gemfiles/rails_8.0_with_mysql2.gemfile new file mode 100644 index 00000000..765f4597 --- /dev/null +++ b/gemfiles/rails_8.0_with_mysql2.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 8.0.0" +gem "mysql2" + +gemspec path: "../" diff --git a/gemfiles/rails_8.0_with_oracle_enhanced.gemfile b/gemfiles/rails_8.0_with_oracle_enhanced.gemfile new file mode 100644 index 00000000..e7e3681d --- /dev/null +++ b/gemfiles/rails_8.0_with_oracle_enhanced.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 8.0.0" +gem "activerecord-oracle_enhanced-adapter", "~> 8.0.0" + +gemspec path: "../" diff --git a/gemfiles/rails_8.0_with_postgis.gemfile b/gemfiles/rails_8.0_with_postgis.gemfile new file mode 100644 index 00000000..e0371b93 --- /dev/null +++ b/gemfiles/rails_8.0_with_postgis.gemfile @@ -0,0 +1,26 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "pg" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 8.0.0" +gem "activerecord-postgis-adapter", "~> 11.0.0" + +gemspec path: "../" diff --git a/gemfiles/rails_8.0_with_postgresql.gemfile b/gemfiles/rails_8.0_with_postgresql.gemfile new file mode 100644 index 00000000..37cf0343 --- /dev/null +++ b/gemfiles/rails_8.0_with_postgresql.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "pg" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 8.0.0" + +gemspec path: "../" diff --git a/gemfiles/rails_8.0_with_sqlite3.gemfile b/gemfiles/rails_8.0_with_sqlite3.gemfile new file mode 100644 index 00000000..cdc0a53b --- /dev/null +++ b/gemfiles/rails_8.0_with_sqlite3.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 8.0.0" +gem "sqlite3" + +gemspec path: "../" diff --git a/gemfiles/rails_8.0_with_trilogy.gemfile b/gemfiles/rails_8.0_with_trilogy.gemfile new file mode 100644 index 00000000..c114794e --- /dev/null +++ b/gemfiles/rails_8.0_with_trilogy.gemfile @@ -0,0 +1,25 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git" +gem "combustion" +gem "database_cleaner" +gem "factory_bot" +gem "faker" +gem "generator_spec" +gem "puma" +gem "rake" +gem "rspec" +gem "rspec-rebound" +gem "simplecov" +gem "guard-rspec", require: false +gem "rubocop", require: false +gem "rubocop-factory_bot", require: false +gem "rubocop-performance", require: false +gem "rubocop-rake", require: false +gem "rubocop-rspec", require: false +gem "rails", "~> 8.0.0" +gem "activerecord-trilogy-adapter" + +gemspec path: "../" diff --git a/lib/ajax-datatables-rails.rb b/lib/ajax-datatables-rails.rb index 05d6fff1..cb9f515f 100644 --- a/lib/ajax-datatables-rails.rb +++ b/lib/ajax-datatables-rails.rb @@ -1,14 +1,17 @@ # frozen_string_literal: true +# require external dependencies require 'zeitwerk' -loader = Zeitwerk::Loader.for_gem -generators = "#{__dir__}/generators" -loader.ignore(generators) -loader.inflector.inflect( - 'orm' => 'ORM', - 'ajax-datatables-rails' => 'AjaxDatatablesRails' -) -loader.setup + +# load zeitwerk +Zeitwerk::Loader.for_gem.tap do |loader| + loader.ignore("#{__dir__}/generators") + loader.inflector.inflect( + 'orm' => 'ORM', + 'ajax-datatables-rails' => 'AjaxDatatablesRails' + ) + loader.setup +end module AjaxDatatablesRails end diff --git a/lib/ajax-datatables-rails/base.rb b/lib/ajax-datatables-rails/base.rb index 208f1204..4d52feee 100644 --- a/lib/ajax-datatables-rails/base.rb +++ b/lib/ajax-datatables-rails/base.rb @@ -1,25 +1,11 @@ # frozen_string_literal: true module AjaxDatatablesRails - class Base + class Base # rubocop:disable Metrics/ClassLength class << self - def rails_52? - Rails.gem_version >= Gem::Version.new('5.2') && Rails.gem_version <= Gem::Version.new('6.0') - end - - def rails_60? - Rails.gem_version >= Gem::Version.new('6.0') && Rails.gem_version <= Gem::Version.new('6.1') - end - def default_db_adapter - if rails_52? - ::ActiveRecord::Base.configurations.dig(Rails.env, 'adapter').downcase.to_sym - elsif rails_60? - ::ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first.config['adapter'].downcase.to_sym - else - ::ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first.adapter.downcase.to_sym - end + ::ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first.adapter.downcase.to_sym end end @@ -34,19 +20,41 @@ def initialize(params, options = {}) @params = params @options = options @datatable = Datatable::Datatable.new(self) + + @view_columns = nil + @connected_columns = nil + @searchable_columns = nil + @search_columns = nil + @records = nil + @build_conditions = nil end # User defined methods def view_columns - raise(NotImplementedError, view_columns_error_text) + raise(NotImplementedError, <<~ERROR) + + You should implement this method in your class and return an array + of database columns based on the columns displayed in the HTML view. + These columns should be represented in the ModelName.column_name, + or aliased_join_table.column_name notation. + ERROR end - def get_raw_records - raise(NotImplementedError, raw_records_error_text) + def get_raw_records # rubocop:disable Naming/AccessorMethodName + raise(NotImplementedError, <<~ERROR) + + You should implement this method in your class and specify + how records are going to be retrieved from the database. + ERROR end def data - raise(NotImplementedError, data_error_text) + raise(NotImplementedError, <<~ERROR) + + You should implement this method in your class and return an array + of arrays, or an array of hashes, as defined in the jQuery.dataTables + plugin documentation. + ERROR end # ORM defined methods @@ -94,23 +102,15 @@ def column_data(column) # helper methods def connected_columns - @connected_columns ||= begin - view_columns.keys.map do |field_name| - datatable.column_by(:data, field_name.to_s) - end.compact - end + @connected_columns ||= view_columns.keys.filter_map { |field_name| datatable.column_by(:data, field_name.to_s) } end def searchable_columns - @searchable_columns ||= begin - connected_columns.select(&:searchable?) - end + @searchable_columns ||= connected_columns.select(&:searchable?) end def search_columns - @search_columns ||= begin - searchable_columns.select(&:searched?) - end + @search_columns ||= searchable_columns.select(&:searched?) end def sanitize_data(data) @@ -157,32 +157,5 @@ def draw_id params[:draw].present? ? { draw: params[:draw].to_i } : {} end - def raw_records_error_text - <<-ERROR - - You should implement this method in your class and specify - how records are going to be retrieved from the database. - ERROR - end - - def data_error_text - <<-ERROR - - You should implement this method in your class and return an array - of arrays, or an array of hashes, as defined in the jQuery.dataTables - plugin documentation. - ERROR - end - - def view_columns_error_text - <<-ERROR - - You should implement this method in your class and return an array - of database columns based on the columns displayed in the HTML view. - These columns should be represented in the ModelName.column_name, - or aliased_join_table.column_name notation. - ERROR - end - end end diff --git a/lib/ajax-datatables-rails/datatable/column.rb b/lib/ajax-datatables-rails/datatable/column.rb index 1c169d24..2179a4da 100644 --- a/lib/ajax-datatables-rails/datatable/column.rb +++ b/lib/ajax-datatables-rails/datatable/column.rb @@ -8,19 +8,26 @@ class Column include Order include DateFilter - attr_reader :datatable, :index, :options + attr_reader :datatable, :index, :options, :column_name attr_writer :search - def initialize(datatable, index, options) + def initialize(datatable, index, options) # rubocop:disable Metrics/MethodLength @datatable = datatable @index = index @options = options - @view_column = datatable.view_columns[column_name] - validate_settings! - end + @column_name = options[:data]&.to_sym + @view_column = datatable.view_columns[@column_name] + + @model = nil + @field = nil + @type_cast = nil + @casted_column = nil + @search = nil + @delimiter = nil + @range_start = nil + @range_end = nil - def column_name - @column_name ||= options[:data]&.to_sym + validate_settings! end def data @@ -68,6 +75,7 @@ def formatted_value DB_ADAPTER_TYPE_CAST = { mysql: TYPE_CAST_MYSQL, mysql2: TYPE_CAST_MYSQL, + trilogy: TYPE_CAST_MYSQL, sqlite: TYPE_CAST_SQLITE, sqlite3: TYPE_CAST_SQLITE, oracle: TYPE_CAST_ORACLE, @@ -91,11 +99,13 @@ def casted_column @casted_column ||= ::Arel::Nodes::NamedFunction.new('CAST', [table[field].as(type_cast)]) end + # rubocop:disable Layout/LineLength def validate_settings! - raise AjaxDatatablesRails::Error::InvalidSearchColumn, "Unknown column. Check that `data` field is filled on JS side with the column name" if column_name.empty? + raise AjaxDatatablesRails::Error::InvalidSearchColumn, 'Unknown column. Check that `data` field is filled on JS side with the column name' if column_name.empty? raise AjaxDatatablesRails::Error::InvalidSearchColumn, "Check that column '#{column_name}' exists in view_columns" unless valid_search_column?(column_name) raise AjaxDatatablesRails::Error::InvalidSearchCondition, cond unless valid_search_condition?(cond) end + # rubocop:enable Layout/LineLength def valid_search_column?(column_name) !datatable.view_columns[column_name].nil? diff --git a/lib/ajax-datatables-rails/datatable/datatable.rb b/lib/ajax-datatables-rails/datatable/datatable.rb index ceaf63c2..0d4e4d6f 100644 --- a/lib/ajax-datatables-rails/datatable/datatable.rb +++ b/lib/ajax-datatables-rails/datatable/datatable.rb @@ -8,6 +8,10 @@ class Datatable def initialize(datatable) @datatable = datatable @options = datatable.params + + @orders = nil + @search = nil + @columns = nil end # ----------------- ORDER METHODS -------------------- diff --git a/lib/ajax-datatables-rails/datatable/simple_order.rb b/lib/ajax-datatables-rails/datatable/simple_order.rb index 69366e83..b817a586 100644 --- a/lib/ajax-datatables-rails/datatable/simple_order.rb +++ b/lib/ajax-datatables-rails/datatable/simple_order.rb @@ -41,17 +41,29 @@ def sort_nulls_last? column.nulls_last? || @nulls_last == true end + PG_NULL_STYLE = 'NULLS LAST' + MYSQL_NULL_STYLE = 'IS NULL' + private_constant :PG_NULL_STYLE + private_constant :MYSQL_NULL_STYLE + + NULL_STYLE_MAP = { + pg: PG_NULL_STYLE, + postgresql: PG_NULL_STYLE, + postgres: PG_NULL_STYLE, + postgis: PG_NULL_STYLE, + oracle: PG_NULL_STYLE, + mysql: MYSQL_NULL_STYLE, + mysql2: MYSQL_NULL_STYLE, + trilogy: MYSQL_NULL_STYLE, + sqlite: MYSQL_NULL_STYLE, + sqlite3: MYSQL_NULL_STYLE, + }.freeze + private_constant :NULL_STYLE_MAP + def nulls_last_sql return unless sort_nulls_last? - case @adapter - when :pg, :postgresql, :postgres, :oracle - 'NULLS LAST' - when :mysql, :mysql2, :sqlite, :sqlite3 - 'IS NULL' - else - raise "unsupported database adapter: #{@adapter}" - end + NULL_STYLE_MAP[@adapter] || raise("unsupported database adapter: #{@adapter}") end end diff --git a/lib/ajax-datatables-rails/orm/active_record.rb b/lib/ajax-datatables-rails/orm/active_record.rb index fae27f3a..8da0895d 100644 --- a/lib/ajax-datatables-rails/orm/active_record.rb +++ b/lib/ajax-datatables-rails/orm/active_record.rb @@ -33,22 +33,18 @@ def build_conditions end end - # rubocop:disable Metrics/AbcSize def build_conditions_for_datatable - columns = searchable_columns.reject(&:searched?) - criteria = search_for.inject([]) do |crit, atom| - search = Datatable::SimpleSearch.new(value: atom, regex: datatable.search.regexp?) - crit << columns.map do |simple_column| - simple_column.search = search + columns = searchable_columns.reject(&:searched?) + search_for.inject([]) do |crit, atom| + crit << columns.filter_map do |simple_column| + simple_column.search = Datatable::SimpleSearch.new(value: atom, regex: datatable.search.regexp?) simple_column.search_query - end.compact.reduce(:or) + end.reduce(:or) end.compact.reduce(:and) - criteria end - # rubocop:enable Metrics/AbcSize def build_conditions_for_selected_columns - search_columns.map(&:search_query).compact.reduce(:and) + search_columns.filter_map(&:search_query).reduce(:and) end def search_for diff --git a/lib/ajax-datatables-rails/version.rb b/lib/ajax-datatables-rails/version.rb index 3e926b16..3e9a1320 100644 --- a/lib/ajax-datatables-rails/version.rb +++ b/lib/ajax-datatables-rails/version.rb @@ -8,7 +8,7 @@ def self.gem_version module VERSION MAJOR = 1 - MINOR = 4 + MINOR = 5 TINY = 0 PRE = nil diff --git a/lib/generators/rails/datatable_generator.rb b/lib/generators/rails/datatable_generator.rb index 5ef5afdb..8e582bcd 100644 --- a/lib/generators/rails/datatable_generator.rb +++ b/lib/generators/rails/datatable_generator.rb @@ -10,7 +10,7 @@ class DatatableGenerator < ::Rails::Generators::Base argument :name, type: :string def generate_datatable - template 'datatable.rb', File.join('app', 'datatables', "#{datatable_path}.rb") + template 'datatable.rb.erb', File.join('app', 'datatables', "#{datatable_path}.rb") end def datatable_name diff --git a/lib/generators/rails/templates/datatable.rb b/lib/generators/rails/templates/datatable.rb.erb similarity index 100% rename from lib/generators/rails/templates/datatable.rb rename to lib/generators/rails/templates/datatable.rb.erb diff --git a/spec/ajax-datatables-rails/base_spec.rb b/spec/ajax_datatables_rails/base_spec.rb similarity index 80% rename from spec/ajax-datatables-rails/base_spec.rb rename to spec/ajax_datatables_rails/base_spec.rb index 17d3738b..28915792 100644 --- a/spec/ajax-datatables-rails/base_spec.rb +++ b/spec/ajax_datatables_rails/base_spec.rb @@ -20,11 +20,17 @@ context 'when method is not defined by the user' do it 'raises an error' do datatable = described_class.new(sample_params) - expect { datatable.view_columns }.to raise_error NotImplementedError + expect { datatable.view_columns }.to raise_error(NotImplementedError).with_message(<<~ERROR) + + You should implement this method in your class and return an array + of database columns based on the columns displayed in the HTML view. + These columns should be represented in the ModelName.column_name, + or aliased_join_table.column_name notation. + ERROR end end - context 'child class implements view_columns' do + context 'when child class implements view_columns' do it 'expects a hash based defining columns' do datatable = ComplexDatatable.new(sample_params) expect(datatable.view_columns).to be_a(Hash) @@ -36,7 +42,11 @@ context 'when method is not defined by the user' do it 'raises an error' do datatable = described_class.new(sample_params) - expect { datatable.get_raw_records }.to raise_error NotImplementedError + expect { datatable.get_raw_records }.to raise_error(NotImplementedError).with_message(<<~ERROR) + + You should implement this method in your class and specify + how records are going to be retrieved from the database. + ERROR end end end @@ -45,7 +55,12 @@ context 'when method is not defined by the user' do it 'raises an error' do datatable = described_class.new(sample_params) - expect { datatable.data }.to raise_error NotImplementedError + expect { datatable.data }.to raise_error(NotImplementedError).with_message(<<~ERROR) + + You should implement this method in your class and return an array + of arrays, or an array of hashes, as defined in the jQuery.dataTables + plugin documentation. + ERROR end end @@ -93,7 +108,7 @@ describe 'ORM API' do context 'when ORM is not implemented' do - let(:datatable) { AjaxDatatablesRails::Base.new(sample_params) } + let(:datatable) { described_class.new(sample_params) } describe '#fetch_records' do it 'raises an error if it does not include an ORM module' do @@ -124,16 +139,16 @@ describe 'it allows method override' do let(:datatable) do datatable = Class.new(ComplexDatatable) do - def filter_records(records) - raise NotImplementedError.new('FOO') + def filter_records(_records) + raise NotImplementedError, 'FOO' end - def sort_records(records) - raise NotImplementedError.new('FOO') + def sort_records(_records) + raise NotImplementedError, 'FOO' end - def paginate_records(records) - raise NotImplementedError.new('FOO') + def paginate_records(_records) + raise NotImplementedError, 'FOO' end end datatable.new(sample_params) @@ -141,12 +156,13 @@ def paginate_records(records) describe '#fetch_records' do it 'calls #get_raw_records' do - expect(datatable).to receive(:get_raw_records) { User.all } + allow(datatable).to receive(:get_raw_records) { User.all } datatable.fetch_records + expect(datatable).to have_received(:get_raw_records) end it 'returns a collection of records' do - expect(datatable).to receive(:get_raw_records) { User.all } + allow(datatable).to receive(:get_raw_records) { User.all } expect(datatable.fetch_records).to be_a(ActiveRecord::Relation) end end @@ -189,7 +205,7 @@ def paginate_records(records) context 'with additional_data' do it 'returns a hash' do create_list(:user, 5) - expect(datatable).to receive(:additional_data) { { foo: 'bar' } } + allow(datatable).to receive(:additional_data).and_return({ foo: 'bar' }) data = datatable.as_json expect(data[:recordsTotal]).to eq 5 expect(data[:recordsFiltered]).to eq 5 @@ -213,9 +229,10 @@ def paginate_records(records) end describe '#column_data' do - let(:datatable) { ComplexDatatable.new(sample_params) } before { datatable.params[:columns]['0'][:search][:value] = 'doe' } + let(:datatable) { ComplexDatatable.new(sample_params) } + it 'returns column data from params' do expect(datatable.column_data(:username)).to eq('doe') expect(datatable.column_data('username')).to eq('doe') diff --git a/spec/ajax-datatables-rails/datatable/column_spec.rb b/spec/ajax_datatables_rails/datatable/column_spec.rb similarity index 70% rename from spec/ajax-datatables-rails/datatable/column_spec.rb rename to spec/ajax_datatables_rails/datatable/column_spec.rb index 6239d891..21dc66f0 100644 --- a/spec/ajax-datatables-rails/datatable/column_spec.rb +++ b/spec/ajax_datatables_rails/datatable/column_spec.rb @@ -13,19 +13,19 @@ before { datatable.params[:columns]['0'][:search][:value] = 'searchvalue' } it 'is orderable' do - expect(column.orderable?).to eq(true) + expect(column.orderable?).to be(true) end it 'sorts nulls last' do - expect(column.nulls_last?).to eq(false) + expect(column.nulls_last?).to be(false) end it 'is searchable' do - expect(column.searchable?).to eq(true) + expect(column.searchable?).to be(true) end it 'is searched' do - expect(column.searched?).to eq(true) + expect(column.searched?).to be(true) end it 'has connected to id column' do @@ -53,7 +53,7 @@ context 'with other ORM' do it 'returns the corresponding model' do - expect(User).to receive(:respond_to?).with(:arel_table).and_return(false) + allow(User).to receive(:respond_to?).with(:arel_table).and_return(false) expect(column.table).to eq User end end @@ -87,7 +87,7 @@ end it 'does not regex' do - expect(column.search.regexp?).to eq false + expect(column.search.regexp?).to be false end end @@ -97,12 +97,6 @@ end end - describe '#source' do - it 'is :like by default' do - expect(column.source).to eq('User.username') - end - end - describe '#search_query' do it 'bulds search query' do expect(column.search_query.to_sql).to include('%searchvalue%') @@ -128,6 +122,14 @@ end end + describe 'unsearchable column' do + let(:column) { datatable.datatable.columns.find { |c| c.data == 'email_hash' } } + + it 'is not searchable' do + expect(column.searchable?).to be(false) + end + end + describe '#formatter' do let(:datatable) { DatatableWithFormater.new(sample_params) } let(:column) { datatable.datatable.columns.find { |c| c.data == 'last_name' } } @@ -142,11 +144,12 @@ let(:column) { datatable.datatable.columns.find { |c| c.data == 'username' } } it 'is a proc' do - config = column.instance_variable_get('@view_column') + config = column.instance_variable_get(:@view_column) filter = config[:cond] expect(filter).to be_a(Proc) - expect(filter).to receive(:call).with(column, column.formatted_value) + allow(filter).to receive(:call).with(column, column.formatted_value) column.filter + expect(filter).to have_received(:call).with(column, column.formatted_value) end end @@ -154,52 +157,62 @@ let(:column) { datatable.datatable.columns.first } it 'returns VARCHAR if :db_adapter is :pg' do - expect(datatable).to receive(:db_adapter) { :pg } + allow(datatable).to receive(:db_adapter).and_return(:pg) expect(column.send(:type_cast)).to eq('VARCHAR') end it 'returns VARCHAR if :db_adapter is :postgre' do - expect(datatable).to receive(:db_adapter) { :postgre } + allow(datatable).to receive(:db_adapter).and_return(:postgre) expect(column.send(:type_cast)).to eq('VARCHAR') end it 'returns VARCHAR if :db_adapter is :postgresql' do - expect(datatable).to receive(:db_adapter) { :postgresql } + allow(datatable).to receive(:db_adapter).and_return(:postgresql) + expect(column.send(:type_cast)).to eq('VARCHAR') + end + + it 'returns VARCHAR if :db_adapter is :postgis' do + allow(datatable).to receive(:db_adapter).and_return(:postgis) expect(column.send(:type_cast)).to eq('VARCHAR') end it 'returns VARCHAR2(4000) if :db_adapter is :oracle' do - expect(datatable).to receive(:db_adapter) { :oracle } + allow(datatable).to receive(:db_adapter).and_return(:oracle) expect(column.send(:type_cast)).to eq('VARCHAR2(4000)') end it 'returns VARCHAR2(4000) if :db_adapter is :oracleenhanced' do - expect(datatable).to receive(:db_adapter) { :oracleenhanced } + allow(datatable).to receive(:db_adapter).and_return(:oracleenhanced) expect(column.send(:type_cast)).to eq('VARCHAR2(4000)') end it 'returns CHAR if :db_adapter is :mysql2' do - expect(datatable).to receive(:db_adapter) { :mysql2 } + allow(datatable).to receive(:db_adapter).and_return(:mysql2) + expect(column.send(:type_cast)).to eq('CHAR') + end + + it 'returns CHAR if :db_adapter is :trilogy' do + allow(datatable).to receive(:db_adapter).and_return(:trilogy) expect(column.send(:type_cast)).to eq('CHAR') end it 'returns CHAR if :db_adapter is :mysql' do - expect(datatable).to receive(:db_adapter) { :mysql } + allow(datatable).to receive(:db_adapter).and_return(:mysql) expect(column.send(:type_cast)).to eq('CHAR') end it 'returns TEXT if :db_adapter is :sqlite' do - expect(datatable).to receive(:db_adapter) { :sqlite } + allow(datatable).to receive(:db_adapter).and_return(:sqlite) expect(column.send(:type_cast)).to eq('TEXT') end it 'returns TEXT if :db_adapter is :sqlite3' do - expect(datatable).to receive(:db_adapter) { :sqlite3 } + allow(datatable).to receive(:db_adapter).and_return(:sqlite3) expect(column.send(:type_cast)).to eq('TEXT') end it 'returns VARCHAR(4000) if :db_adapter is :sqlserver' do - expect(datatable).to receive(:db_adapter) { :sqlserver } + allow(datatable).to receive(:db_adapter).and_return(:sqlserver) expect(column.send(:type_cast)).to eq('VARCHAR(4000)') end end @@ -207,16 +220,20 @@ describe 'when empty column' do before { datatable.params[:columns]['0'][:data] = '' } + let(:message) { 'Unknown column. Check that `data` field is filled on JS side with the column name' } + it 'raises error' do - 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') + expect { datatable.to_json }.to raise_error(AjaxDatatablesRails::Error::InvalidSearchColumn).with_message(message) end end describe 'when unknown column' do before { datatable.params[:columns]['0'][:data] = 'foo' } + let(:message) { "Check that column 'foo' exists in view_columns" } + it 'raises error' do - expect { datatable.to_json }.to raise_error(AjaxDatatablesRails::Error::InvalidSearchColumn).with_message("Check that column 'foo' exists in view_columns") + expect { datatable.to_json }.to raise_error(AjaxDatatablesRails::Error::InvalidSearchColumn).with_message(message) end end end diff --git a/spec/ajax-datatables-rails/datatable/datatable_spec.rb b/spec/ajax_datatables_rails/datatable/datatable_spec.rb similarity index 92% rename from spec/ajax-datatables-rails/datatable/datatable_spec.rb rename to spec/ajax_datatables_rails/datatable/datatable_spec.rb index 6d266288..fa12005d 100644 --- a/spec/ajax-datatables-rails/datatable/datatable_spec.rb +++ b/spec/ajax_datatables_rails/datatable/datatable_spec.rb @@ -11,12 +11,12 @@ shared_examples 'order methods' do it 'is orderable' do - expect(datatable.orderable?).to eq(true) + expect(datatable.orderable?).to be(true) end it 'is not orderable' do datatable.options[:order] = nil - expect(datatable.orderable?).to eq(false) + expect(datatable.orderable?).to be(false) end it 'has 2 orderable columns' do @@ -40,8 +40,8 @@ end shared_examples 'columns methods' do - it 'has 7 columns' do - expect(datatable.columns.count).to eq(7) + it 'has 8 columns' do + expect(datatable.columns.count).to eq(8) end it 'child class' do @@ -57,6 +57,7 @@ describe 'with json params' do let(:order_option) { order_option_json } let(:datatable) { datatable_json } + it_behaves_like 'order methods' it_behaves_like 'columns methods' end @@ -64,12 +65,12 @@ describe 'search methods' do it 'is searchable' do datatable.options[:search][:value] = 'atom' - expect(datatable.searchable?).to eq(true) + expect(datatable.searchable?).to be(true) end it 'is not searchable' do datatable.options[:search][:value] = nil - expect(datatable.searchable?).to eq(false) + expect(datatable.searchable?).to be(false) end it 'child class' do diff --git a/spec/ajax-datatables-rails/datatable/simple_order_spec.rb b/spec/ajax_datatables_rails/datatable/simple_order_spec.rb similarity index 81% rename from spec/ajax-datatables-rails/datatable/simple_order_spec.rb rename to spec/ajax_datatables_rails/datatable/simple_order_spec.rb index c28bfe84..36d2260f 100644 --- a/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +++ b/spec/ajax_datatables_rails/datatable/simple_order_spec.rb @@ -7,7 +7,7 @@ let(:parent) { ComplexDatatable.new(sample_params) } let(:datatable) { parent.datatable } let(:options) { ActiveSupport::HashWithIndifferentAccess.new({ 'column' => '1', 'dir' => 'desc' }) } - let(:simple_order) { AjaxDatatablesRails::Datatable::SimpleOrder.new(datatable, options) } + let(:simple_order) { described_class.new(datatable, options) } describe 'option methods' do it 'sql query' do @@ -32,7 +32,7 @@ describe 'using column option' do let(:parent) { DatatableOrderNullsLast.new(sample_params) } let(:sorted_datatable) { parent.datatable } - let(:nulls_last_order) { AjaxDatatablesRails::Datatable::SimpleOrder.new(sorted_datatable, options) } + let(:nulls_last_order) { described_class.new(sorted_datatable, options) } context 'with postgres database adapter' do before { parent.db_adapter = :pg } @@ -42,6 +42,14 @@ end end + context 'with postgis database adapter' do + before { parent.db_adapter = :postgis } + + it 'sql query' do + expect(nulls_last_order.query('email')).to eq('email DESC NULLS LAST') + end + end + context 'with sqlite database adapter' do before { parent.db_adapter = :sqlite } diff --git a/spec/ajax-datatables-rails/datatable/simple_search_spec.rb b/spec/ajax_datatables_rails/datatable/simple_search_spec.rb similarity index 83% rename from spec/ajax-datatables-rails/datatable/simple_search_spec.rb rename to spec/ajax_datatables_rails/datatable/simple_search_spec.rb index fc814802..a13bed72 100644 --- a/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +++ b/spec/ajax_datatables_rails/datatable/simple_search_spec.rb @@ -5,7 +5,7 @@ RSpec.describe AjaxDatatablesRails::Datatable::SimpleSearch do let(:options) { ActiveSupport::HashWithIndifferentAccess.new({ 'value' => 'search value', 'regex' => 'true' }) } - let(:simple_search) { AjaxDatatablesRails::Datatable::SimpleSearch.new(options) } + let(:simple_search) { described_class.new(options) } describe 'option methods' do it 'regexp?' do diff --git a/spec/ajax-datatables-rails/orm/active_record_count_records_spec.rb b/spec/ajax_datatables_rails/orm/active_record_count_records_spec.rb similarity index 85% rename from spec/ajax-datatables-rails/orm/active_record_count_records_spec.rb rename to spec/ajax_datatables_rails/orm/active_record_count_records_spec.rb index 4c5c2be3..70c4de4c 100644 --- a/spec/ajax-datatables-rails/orm/active_record_count_records_spec.rb +++ b/spec/ajax_datatables_rails/orm/active_record_count_records_spec.rb @@ -8,13 +8,13 @@ let(:records) { User.all } describe '#records_total_count' do - context 'ungrouped results' do + context 'when ungrouped results' do it 'returns the count' do expect(datatable.send(:records_total_count)).to eq records.count end end - context 'grouped results' do + context 'when grouped results' do let(:datatable) { GroupedDatatable.new(sample_params) } it 'returns the count' do @@ -23,15 +23,14 @@ end end - describe '#records_filtered_count' do - context 'ungrouped results' do + context 'when ungrouped results' do it 'returns the count' do expect(datatable.send(:records_filtered_count)).to eq records.count end end - context 'grouped results' do + context 'when grouped results' do let(:datatable) { GroupedDatatable.new(sample_params) } it 'returns the count' do diff --git a/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb b/spec/ajax_datatables_rails/orm/active_record_filter_records_spec.rb similarity index 87% rename from spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb rename to spec/ajax_datatables_rails/orm/active_record_filter_records_spec.rb index 1dd108a3..4bcbd541 100644 --- a/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +++ b/spec/ajax_datatables_rails/orm/active_record_filter_records_spec.rb @@ -12,16 +12,28 @@ expect { datatable.filter_records }.to raise_error(ArgumentError) end - it 'performs a simple search first' do - datatable.params[:search] = { value: 'msmith' } - expect(datatable).to receive(:build_conditions_for_datatable) - datatable.filter_records(records) + context 'with simple search' do + before do + datatable.params[:search] = { value: 'msmith' } + end + + it 'performs a simple search first' do + allow(datatable).to receive(:build_conditions_for_datatable) + datatable.filter_records(records) + expect(datatable).to have_received(:build_conditions_for_datatable) + end + + it 'does not search unsearchable fields' do + criteria = datatable.filter_records(records) + expect(criteria.to_sql).to_not include('email_hash') + end end it 'performs a composite search second' do datatable.params[:search] = { value: '' } - expect(datatable).to receive(:build_conditions_for_selected_columns) + allow(datatable).to receive(:build_conditions_for_selected_columns) datatable.filter_records(records) + expect(datatable).to have_received(:build_conditions_for_selected_columns) end end @@ -42,8 +54,8 @@ query = datatable.build_conditions results = records.where(query).map(&:username) expect(results).to include('msmith') - expect(results).not_to include('johndoe') - expect(results).not_to include('hsmith') + expect(results).to_not include('johndoe') + expect(results).to_not include('hsmith') end end end @@ -60,7 +72,7 @@ expect(result).to be_a(Arel::Nodes::Grouping) end - context 'no search query' do + context 'when no search query' do it 'returns empty query' do datatable.params[:search] = { value: '' } expect(datatable.build_conditions_for_datatable).to be_blank @@ -69,7 +81,7 @@ context 'when none of columns are connected' do before do - allow(datatable).to receive(:searchable_columns) { [] } + allow(datatable).to receive(:searchable_columns).and_return([]) end context 'when search value is a string' do @@ -84,7 +96,7 @@ it 'returns filtered results' do query = datatable.build_conditions_for_datatable results = records.where(query).map(&:username) - expect(results).to eq ['johndoe', 'msmith'] + expect(results).to eq %w[johndoe msmith] end end @@ -100,7 +112,7 @@ it 'returns filtered results' do query = datatable.build_conditions_for_datatable results = records.where(query).map(&:username) - expect(results).to eq ['johndoe', 'msmith'] + expect(results).to eq %w[johndoe msmith] end end end @@ -115,7 +127,7 @@ query = datatable.build_conditions_for_datatable results = records.where(query).map(&:username) expect(results).to include('johndoe') - expect(results).not_to include('msmith') + expect(results).to_not include('msmith') end end @@ -128,7 +140,7 @@ query = datatable.build_conditions_for_datatable results = records.where(query).map(&:username) expect(results).to eq ['johndoe'] - expect(results).not_to include('msmith') + expect(results).to_not include('msmith') end end @@ -141,7 +153,7 @@ end it 'does not raise error' do - allow_any_instance_of(AjaxDatatablesRails::Datatable::Column).to receive(:valid_search_condition?).and_return(true) + allow_any_instance_of(AjaxDatatablesRails::Datatable::Column).to receive(:valid_search_condition?).and_return(true) # rubocop:disable RSpec/AnyInstance expect { datatable.data.size @@ -157,7 +169,7 @@ create(:user, username: 'msmith', email: 'mary.smith@example.com') end - context 'columns include search query' do + context 'when columns include search query' do before do datatable.params[:columns]['0'][:search][:value] = 'doe' datatable.params[:columns]['1'][:search][:value] = 'example' @@ -186,14 +198,24 @@ result = datatable.build_conditions_for_selected_columns expect(result).to respond_to(:to_sql) expect(result.to_sql).to eq( - "CAST(\"USERS\".\"USERNAME\" AS VARCHAR2(4000)) LIKE '%doe%' AND CAST(\"USERS\".\"EMAIL\" AS VARCHAR2(4000)) LIKE '%example%'" + "UPPER(CAST(\"USERS\".\"USERNAME\" AS VARCHAR2(4000))) LIKE UPPER('%doe%') AND UPPER(CAST(\"USERS\".\"EMAIL\" AS VARCHAR2(4000))) LIKE UPPER('%example%')" # rubocop:disable Layout/LineLength ) end end end if RunningSpec.mysql? - context 'when db_adapter is mysql2' do + context 'when db_adapter is mysql2' do # rubocop:disable RSpec/RepeatedExampleGroupBody + it 'can call #to_sql on returned object' do + result = datatable.build_conditions_for_selected_columns + expect(result).to respond_to(:to_sql) + expect(result.to_sql).to eq( + "CAST(`users`.`username` AS CHAR) LIKE '%doe%' AND CAST(`users`.`email` AS CHAR) LIKE '%example%'" + ) + end + end + + context 'when db_adapter is trilogy' do # rubocop:disable RSpec/RepeatedExampleGroupBody it 'can call #to_sql on returned object' do result = datatable.build_conditions_for_selected_columns expect(result).to respond_to(:to_sql) @@ -206,8 +228,9 @@ end it 'calls #build_conditions_for_selected_columns' do - expect(datatable).to receive(:build_conditions_for_selected_columns) + allow(datatable).to receive(:build_conditions_for_selected_columns) datatable.build_conditions + expect(datatable).to have_received(:build_conditions_for_selected_columns) end context 'with search values in columns' do @@ -219,13 +242,13 @@ query = datatable.build_conditions_for_selected_columns results = records.where(query).map(&:username) expect(results).to include('johndoe') - expect(results).not_to include('msmith') + expect(results).to_not include('msmith') end end end describe 'filter conditions' do - context 'date condition' do + context 'with date condition' do describe 'it can filter records with condition :date_range' do let(:datatable) { DatatableCondDate.new(sample_params) } @@ -236,7 +259,7 @@ context 'when range is empty' do it 'does not filter records' do - datatable.params[:columns]['6'][:search][:value] = '-' + datatable.params[:columns]['7'][:search][:value] = '-' expect(datatable.data.size).to eq 2 item = datatable.data.first expect(item[:last_name]).to eq 'Doe' @@ -245,21 +268,21 @@ context 'when start date is filled' do it 'filters records created after this date' do - datatable.params[:columns]['6'][:search][:value] = '31/12/1999-' + datatable.params[:columns]['7'][:search][:value] = '31/12/1999-' expect(datatable.data.size).to eq 2 end end context 'when end date is filled' do it 'filters records created before this date' do - datatable.params[:columns]['6'][:search][:value] = '-31/12/1999' + datatable.params[:columns]['7'][:search][:value] = '-31/12/1999' expect(datatable.data.size).to eq 0 end end context 'when both date are filled' do it 'filters records created between the range' do - datatable.params[:columns]['6'][:search][:value] = '01/12/1999-15/01/2000' + datatable.params[:columns]['7'][:search][:value] = '01/12/1999-15/01/2000' expect(datatable.data.size).to eq 1 end end @@ -268,7 +291,7 @@ context 'when range is empty' do it 'filters records' do datatable.params[:columns]['0'][:search][:value] = 'doe' - datatable.params[:columns]['6'][:search][:value] = '-' + datatable.params[:columns]['7'][:search][:value] = '-' expect(datatable.data.size).to eq 1 item = datatable.data.first expect(item[:last_name]).to eq 'Doe' @@ -278,7 +301,7 @@ context 'when start date is filled' do it 'filters records' do datatable.params[:columns]['0'][:search][:value] = 'doe' - datatable.params[:columns]['6'][:search][:value] = '01/12/1999-' + datatable.params[:columns]['7'][:search][:value] = '01/12/1999-' expect(datatable.data.size).to eq 1 item = datatable.data.first expect(item[:last_name]).to eq 'Doe' @@ -288,7 +311,7 @@ context 'when end date is filled' do it 'filters records' do datatable.params[:columns]['0'][:search][:value] = 'doe' - datatable.params[:columns]['6'][:search][:value] = '-15/01/2000' + datatable.params[:columns]['7'][:search][:value] = '-15/01/2000' expect(datatable.data.size).to eq 1 item = datatable.data.first expect(item[:last_name]).to eq 'Doe' @@ -298,7 +321,7 @@ context 'when both date are filled' do it 'filters records' do datatable.params[:columns]['0'][:search][:value] = 'doe' - datatable.params[:columns]['6'][:search][:value] = '01/12/1999-15/01/2000' + datatable.params[:columns]['7'][:search][:value] = '01/12/1999-15/01/2000' expect(datatable.data.size).to eq 1 item = datatable.data.first expect(item[:last_name]).to eq 'Doe' @@ -308,7 +331,7 @@ end end - context 'numeric condition' do + context 'with numeric condition' do before do create(:user, first_name: 'john', post_id: 1) create(:user, first_name: 'mary', post_id: 2) @@ -427,7 +450,7 @@ end end - context 'proc condition' do + context 'with proc condition' do describe 'it can filter records with lambda/proc condition' do let(:datatable) { DatatableCondProc.new(sample_params) } @@ -446,7 +469,7 @@ end end - context 'string condition' do + context 'with string condition' do describe 'it can filter records with condition :start_with' do let(:datatable) { DatatableCondStartWith.new(sample_params) } @@ -584,7 +607,7 @@ end end - context 'unknown condition' do + context 'with unknown condition' do let(:datatable) { DatatableCondUnknown.new(sample_params) } before do @@ -598,7 +621,7 @@ end end - context 'custom column' do + context 'with custom column' do describe 'it can filter records with custom column' do let(:datatable) { DatatableCustomColumn.new(sample_params) } diff --git a/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb b/spec/ajax_datatables_rails/orm/active_record_paginate_records_spec.rb similarity index 83% rename from spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb rename to spec/ajax_datatables_rails/orm/active_record_paginate_records_spec.rb index e715b2fe..a33c834d 100644 --- a/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +++ b/spec/ajax_datatables_rails/orm/active_record_paginate_records_spec.rb @@ -17,7 +17,7 @@ expect { datatable.paginate_records }.to raise_error(ArgumentError) end - it 'paginates records properly' do + it 'paginates records properly' do # rubocop:disable RSpec/ExampleLength if RunningSpec.oracle? if Rails.version.in? %w[4.2.11] expect(datatable.paginate_records(records).to_sql).to include( @@ -54,13 +54,15 @@ end it 'depends on the value of #offset' do - expect(datatable.datatable).to receive(:offset) + allow(datatable.datatable).to receive(:offset) datatable.paginate_records(records) + expect(datatable.datatable).to have_received(:offset) end it 'depends on the value of #per_page' do - expect(datatable.datatable).to receive(:per_page).at_least(:once) { 10 } + allow(datatable.datatable).to receive(:per_page).at_least(:once).and_return(10) datatable.paginate_records(records) + expect(datatable.datatable).to have_received(:per_page).at_least(:once) end end diff --git a/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb b/spec/ajax_datatables_rails/orm/active_record_sort_records_spec.rb similarity index 100% rename from spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb rename to spec/ajax_datatables_rails/orm/active_record_sort_records_spec.rb diff --git a/spec/dummy/config/database.yml b/spec/dummy/config/database.yml index 949cea8e..a9de41f6 100644 --- a/spec/dummy/config/database.yml +++ b/spec/dummy/config/database.yml @@ -4,21 +4,21 @@ test: database: ajax_datatables_rails encoding: utf8 -<% if adapter == 'postgresql' %> +<% if adapter == 'postgresql' || adapter == 'postgis' %> host: '127.0.0.1' port: 5432 username: 'postgres' password: 'postgres' -<% elsif adapter == 'mysql2' %> +<% elsif adapter == 'mysql2' || adapter == 'trilogy' %> host: '127.0.0.1' port: 3306 username: 'root' password: 'root' <% elsif adapter == 'oracle_enhanced' %> - host: '127.0.0.1/xe' - username: <%= ENV.fetch('http://github.com/USER') %> - password: <%= ENV.fetch('http://github.com/USER') %> - database: 'xe' + host: '127.0.0.1' + username: 'oracle_enhanced' + password: 'oracle_enhanced' + database: 'FREEPDB1' <% elsif adapter == 'sqlite3' %> # database: ':memory:' database: db/ajax_datatables_rails.sqlite3 diff --git a/spec/install_oracle.sh b/spec/install_oracle.sh deleted file mode 100755 index 07537f79..00000000 --- a/spec/install_oracle.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -wget 'https://github.com/cbandy/travis-oracle/archive/v2.0.3.tar.gz' -mkdir -p ~/.travis/oracle -tar xz --strip-components 1 -C ~/.travis/oracle -f v2.0.3.tar.gz - -if [ -n ${CUSTOM_ORACLE_FILE} ]; then - wget -q ${CUSTOM_ORACLE_FILE} -O ~/.travis/oracle/oracle-xe-11.2.0-1.0.x86_64.rpm.zip -else - ~/.travis/oracle/download.sh -fi - -~/.travis/oracle/install.sh - -# in dev env: sqlplus system/password@localhost/XE -"${ORACLE_HOME}/bin/sqlplus" -L -S / AS SYSDBA <(o) { o.upcase } }) + super.deep_merge(last_name: { formatter: lambda(&:upcase) }) end end diff --git a/spec/support/datatables/datatable_custom_column.rb b/spec/support/datatables/datatable_custom_column.rb index 4740adea..2d8db393 100644 --- a/spec/support/datatables/datatable_custom_column.rb +++ b/spec/support/datatables/datatable_custom_column.rb @@ -5,7 +5,7 @@ def view_columns super.deep_merge(full_name: { cond: filter_full_name }) end - def get_raw_records + def get_raw_records # rubocop:disable Naming/AccessorMethodName User.select("*, CONCAT(first_name, ' ', last_name) as full_name") end diff --git a/spec/support/datatables/grouped_datatable_array.rb b/spec/support/datatables/grouped_datatable_array.rb index e4547adf..e23e0126 100644 --- a/spec/support/datatables/grouped_datatable_array.rb +++ b/spec/support/datatables/grouped_datatable_array.rb @@ -2,7 +2,7 @@ class GroupedDatatable < ComplexDatatable - def get_raw_records + def get_raw_records # rubocop:disable Naming/AccessorMethodName User.all.group(:id) end end diff --git a/spec/support/helpers/params.rb b/spec/support/helpers/params.rb index b127b779..0323ab51 100644 --- a/spec/support/helpers/params.rb +++ b/spec/support/helpers/params.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# rubocop:disable Metrics/MethodLength +# rubocop:disable Metrics/MethodLength, Layout/HashAlignment def sample_params ActionController::Parameters.new( { @@ -43,6 +43,12 @@ def sample_params } }, '6' => { + 'data' => 'email_hash', 'name' => '', 'searchable' => 'false', 'orderable' => 'true', + 'search' => { + 'value' => '', 'regex' => 'false' + } + }, + '7' => { 'data' => 'created_at', 'name' => '', 'searchable' => 'true', 'orderable' => 'true', 'search' => { 'value' => '', 'regex' => 'false' @@ -52,13 +58,16 @@ def sample_params 'order' => { '0' => { 'column' => '0', 'dir' => 'asc' }, }, - 'start' => '0', 'length' => '10', 'search' => { + 'start' => '0', + 'length' => '10', + 'search' => { 'value' => '', 'regex' => 'false' }, - '_' => '1423364387185' + '_' => '1423364387185', } ) end +# rubocop:enable Metrics/MethodLength, Layout/HashAlignment def sample_params_json hash_params = sample_params.to_unsafe_h @@ -66,13 +75,12 @@ def sample_params_json hash_params['order'] = hash_params['order'].values ActionController::Parameters.new(hash_params) end -# rubocop:enable Metrics/MethodLength def nulls_last_sql(datatable) case datatable.db_adapter - when :pg, :postgresql, :postgres, :oracle + when :pg, :postgresql, :postgres, :oracle, :postgis 'NULLS LAST' - when :mysql, :mysql2, :sqlite, :sqlite3 + when :mysql, :mysql2, :trilogy, :sqlite, :sqlite3 'IS NULL' else raise 'unsupported database adapter' diff --git a/spec/support/models/user.rb b/spec/support/models/user.rb index 7ad18b20..34d527e2 100644 --- a/spec/support/models/user.rb +++ b/spec/support/models/user.rb @@ -1,7 +1,15 @@ # frozen_string_literal: true +require 'digest' + class User < ActiveRecord::Base def full_name "#{first_name} #{last_name}" end + + def email_hash + return nil if email.nil? + + Digest::SHA256.hexdigest email + end end