order_as_specified 1.6 → 1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 119668cc688124610b87036f0f929c0fbcc35ef4acea5e1c2a1cdc48c1101241
4
- data.tar.gz: a17df8766bfe178cac883311d8ba4b165b4e43a9c4afd1d8e4b8af0e099d5010
3
+ metadata.gz: d928c44adb61e277076bd76af0ac1568b132a0f9ab49050d1b047fee59305714
4
+ data.tar.gz: bcbf4c9b1f4061ae9798535dff306c27c7b845bd827a9cd9f2e0ee7ee195c427
5
5
  SHA512:
6
- metadata.gz: 1a53e19dc18fb420fbf88f1fb535b46a0a5c5b13a84158c237a350243f8cfefa5f78ae048087bcc939ea7ecab12e4b7aec5c62bae7960d921a83704f9a53a45e
7
- data.tar.gz: 0ca1d4697d3634f442edb58173cf4d7f6199571ae1a69415cb6cb2d8b93079ff588023e5549f99ca998979cfeff93ee3ea1f2f0810afd90c8501df829d41e104
6
+ metadata.gz: 58d477da354092f0f3c7e9a034c14a76b04ac80599d46850ce064dd84ce0d172cbef0efd9ac6a3a7c467ba7472250299698aad1aa6311f7f679a4cc44d231483
7
+ data.tar.gz: bcf2ab1b90641f027ea0b9200bc442d77902448764a4f473552d2f6d4ec46c30023ce7bf893ddd678787212858ee2a85a738c0d10008d85fd7911fc3a37f2b17
@@ -0,0 +1,46 @@
1
+ # This is a dependabot configuration file. When this file is seen on github, a
2
+ # dependabot configuration is created for the project. We can use this to
3
+ # control various aspects of the automated dependency checking, such as the
4
+ # frequency and the target_branch.
5
+ #
6
+ # Reference: https://dependabot.com/docs/config-file/
7
+ version: 1
8
+ update_configs:
9
+ # This configures dependency updates for one package manager. In some
10
+ # projects, such as warehouse, where we have Ruby and Python, there can be
11
+ # separate package_manager entries.
12
+ - package_manager: "ruby:bundler"
13
+ directory: "/"
14
+ update_schedule: "weekly"
15
+
16
+ default_labels:
17
+ - "dependencies"
18
+ - "Needs QA"
19
+
20
+ # Dependabot will use a repository's default branch. This will override
21
+ # that.
22
+ # target_branch: "master"
23
+
24
+ allowed_updates:
25
+ - match:
26
+ dependency_type: "direct"
27
+
28
+ automerged_updates:
29
+ # This allows all dependencies that are used for development, e.g., rspec,
30
+ # rspec-mock, vcr, etc, to be automatically updated. This is generally
31
+ # okay because the dependencies are not used in production.
32
+ - match:
33
+ dependency_type: "development"
34
+ update_type: "all"
35
+
36
+ # # This is an example entry to enable automerging of a specific dependency
37
+ # # when the update is only for minor or patch semantic versions.
38
+ # #
39
+ # # The dependency_name can also be a wildcard.
40
+ # #
41
+ # # This is left commented, but whitelisting a dependency for automatic
42
+ # # merging is as simple as creating a new entry that looks like the below.
43
+ # - match:
44
+ # dependency_type: "all"
45
+ # dependency_name: "aws-sdk-s3"
46
+ # update_type: "semver:minor"
@@ -0,0 +1,26 @@
1
+ # This workflow auto-approves pull-requests when the github actor is a
2
+ # dependabot user and it is opening a new pull request.
3
+ #
4
+ # The problem that this workflow solves is that we have branch protection on
5
+ # our repositories that prevent PRs from merging unless there is an
6
+ # approval present. The problem is that this will block PRs that dependabot
7
+ # may want to merge automatically. Auto-approving dependabot PRs will allow
8
+ # the automatic merge to complete. We control what gets automerged through
9
+ # the dependabot configuration.
10
+ #
11
+ # This is a known issue: https://github.com/dependabot/feedback/issues/852
12
+ name: Auto-approve dependabot pull requests
13
+ on:
14
+ pull_request:
15
+ types: [opened]
16
+
17
+ jobs:
18
+ dependabot-triage:
19
+ runs-on: ubuntu-latest
20
+ if: (github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]')
21
+
22
+ steps:
23
+ - name: Auto-approve for dependabot
24
+ uses: hmarr/auto-approve-action@v2.0.0
25
+ with:
26
+ github-token: "${{ secrets.GITHUB_TOKEN }}"
@@ -0,0 +1,35 @@
1
+ # This workflow removes a "Needs QA" label from a PR when the actor is the
2
+ # dependabot user merging a PR.
3
+ #
4
+ # We need this mechanism to allow for automerging whitelisted dependencies while
5
+ # also allowing for blocking a merge to master for deployment (in the way that
6
+ # our other PRs work). When the automerge script runs in henchman, it looks
7
+ # for `Needs QA` on github pull requests, and if the label is present,
8
+ # blocks the commit from merging.
9
+ name: Remove 'Needs QA' label for auto-merged PRs.
10
+ on:
11
+ pull_request:
12
+ types: [closed]
13
+
14
+ jobs:
15
+ remove-label:
16
+ runs-on: ubuntu-latest
17
+ if: >
18
+ (github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]')
19
+ && github.event.pull_request.merged
20
+
21
+ steps:
22
+ # Our triage workflow adds 'Needs QA' to the PR in order to block it from
23
+ # merging to production. This removes that label when dependabot is doing
24
+ # the merging.
25
+ - name: Remove QA Label
26
+ uses: actions/github-script@0.4.0
27
+ with:
28
+ github-token: ${{ secrets.GITHUB_TOKEN }}
29
+ script: |
30
+ github.issues.removeLabel({
31
+ issue_number: context.issue.number,
32
+ owner: context.repo.owner,
33
+ repo: context.repo.repo,
34
+ name: 'Needs QA'
35
+ })
@@ -0,0 +1,61 @@
1
+ # based on https://github.com/ruby/setup-ruby/blob/master/README.md
2
+ name: Tests
3
+ on: [push, pull_request]
4
+ jobs:
5
+ ci:
6
+ name: CI
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ os: [ ubuntu-latest ]
11
+ ruby: [ 2.5, 2.6, 2.7 ]
12
+ runs-on: ${{ matrix.os }}
13
+ services:
14
+ postgres:
15
+ image: postgres:latest
16
+ env:
17
+ POSTGRES_USER: postgres
18
+ POSTGRES_PASSWORD: postgres
19
+ POSTGRES_DB: order_as_specified_test
20
+ options: >-
21
+ --health-cmd pg_isready
22
+ --health-interval 10s
23
+ --health-timeout 5s
24
+ --health-retries 5
25
+ ports:
26
+ - 5432:5432
27
+ mysql:
28
+ image: mysql:latest
29
+ env:
30
+ MYSQL_USER: mysql
31
+ MYSQL_PASSWORD: mysql
32
+ MYSQL_ROOT_PASSWORD: mysql
33
+ MYSQL_DATABASE: order_as_specified_test
34
+ ports:
35
+ - 3306:3306
36
+ options: >-
37
+ --health-cmd "mysqladmin ping"
38
+ --health-interval 10s
39
+ --health-timeout 5s
40
+ --health-retries 5
41
+ env:
42
+ CI: true
43
+ steps:
44
+ - uses: actions/checkout@v2
45
+ - uses: ruby/setup-ruby@v1
46
+ with:
47
+ ruby-version: ${{ matrix.ruby }}
48
+ - uses: actions/cache@v1
49
+ with:
50
+ path: vendor/bundle
51
+ key: bundle-use-ruby-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/Gemfile.lock') }}
52
+ restore-keys: |
53
+ bundle-use-ruby-${{ matrix.os }}-${{ matrix.ruby }}-
54
+ - run: sudo apt-get install libsqlite3-dev
55
+ - name: bundle install
56
+ run: |
57
+ ruby -v
58
+ bundle config path vendor/bundle
59
+ bundle install --jobs 4 --retry 3
60
+ - run: bundle exec rubocop
61
+ - run: bundle exec rspec
data/.gitignore CHANGED
@@ -13,4 +13,3 @@
13
13
  *.a
14
14
  mkmf.log
15
15
  *.gem
16
- .rubocop-https---raw-githubusercontent-com-panorama-ed-code-conventions-master-rubocop-yml
data/.rubocop.yml CHANGED
@@ -1,5 +1,2 @@
1
- inherit_from:
2
- - https://raw.githubusercontent.com/panorama-ed/code-conventions/master/rubocop.yml
3
-
4
- AllCops:
5
- TargetRubyVersion: 2.4 # Keep this in sync with .travis.yml
1
+ inherit_gem:
2
+ panolint: rubocop.yml
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Unreleased (`master`)
2
2
 
3
+ # 1.7
4
+
5
+ This release adds support for `nil` values in the ordering list. Thanks to
6
+ [yfulmes](https://github.com/yfulmes) for requesting this feature!
7
+
3
8
  # 1.6
4
9
 
5
10
  We are dropping official support for Ruby 2.3 and below, though they may
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at engineering@panoramaed.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- # Specify your gem's dependencies in order_as_specified.gemspec
5
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
6
+
7
+ # Specify your gem's dependencies in unique_attributes.gemspec
6
8
  gemspec
7
9
 
8
- if ENV["TRAVIS"] == "true" && ENV["ACTIVERECORD_VERSION"]
9
- gem "activerecord", ENV["ACTIVERECORD_VERSION"]
10
+ group :development do
11
+ gem "panolint", github: "panorama-ed/panolint", branch: "main"
10
12
  end
data/README.md CHANGED
@@ -142,6 +142,20 @@ TestObject.order_as_specified(language: ["fr", "es"])
142
142
  ]>
143
143
  ```
144
144
 
145
+ The order can also include `nil` attributes:
146
+
147
+ ```ruby
148
+ TestObject.order_as_specified(language: ["es", nil, "fr"])
149
+ => #<ActiveRecord::Relation [
150
+ #<TestObject id: 3, language: "es">,
151
+ #<TestObject id: 1, language: nil>,
152
+ #<TestObject id: 4, language: nil>,
153
+ #<TestObject id: 2, language: "fr">
154
+ ]>
155
+ ```
156
+
157
+ ### `distinct_on`
158
+
145
159
  In databases that support it (such as PostgreSQL), you can also use an option to
146
160
  add a `DISTINCT ON` to your query when you would otherwise have duplicates:
147
161
 
@@ -154,10 +168,20 @@ TestObject.order_as_specified(distinct_on: true, language: ["fr", "en"])
154
168
  ]>
155
169
  ```
156
170
 
157
- Note that if a `nil` value is passed in the ordering an error is raised, because
158
- databases do not have good or consistent support for ordering with `NULL` values
159
- in an arbitrary order, so we don't permit this behavior instead of allowing an
160
- unexpected result.
171
+ ### `case_insensitive`
172
+
173
+ If you want objects to come back in an order that is case-insensitive, you can
174
+ pass the `case_insensitive: true` value to the `order_as_specified` call, as in:
175
+
176
+ ```ruby
177
+ TestObject.order_as_specified(case_insensitive: true, language: ["fr", "en"])
178
+ => #<ActiveRecord::Relation [
179
+ #<TestObject language: "fr">
180
+ #<TestObject language: "FR">
181
+ #<TestObject language: "EN">
182
+ #<TestObject language: "en">
183
+ ]>
184
+ ```
161
185
 
162
186
  ## Limitations
163
187
 
data/RELEASING.md CHANGED
@@ -6,9 +6,9 @@
6
6
  1. On the new branch, update the VERSION constant in `lib/order_as_specified/version.rb`.
7
7
  1. Update the Changelog.
8
8
  1. Commit the change: `git add -A && git commit -m 'Bump to vX.X'`.
9
- 1. Add a tag: `git tag -am "vX.X" vX.X`.
10
- 1. Push the branch and tag: `git push --follow-tags`
11
9
  1. Make a PR.
12
10
  1. Merge the PR.
11
+ 1. Add a tag: `git tag -am "vX.X" vX.X`.
12
+ 1. Push the tag: `git push --tags`
13
13
  1. Push to rubygems: `gem build order_as_specified.gemspec && gem push *.gem && rm *.gem`
14
14
  1. Celebrate!
@@ -12,33 +12,39 @@ module OrderAsSpecified
12
12
  # @return [ActiveRecord::Relation] the objects, ordered as specified
13
13
  def order_as_specified(hash)
14
14
  distinct_on = hash.delete(:distinct_on)
15
+ case_insensitive = hash.delete(:case_insensitive)
16
+
15
17
  params = extract_params(hash)
16
18
  return all if params[:values].empty?
17
19
 
18
- table = connection.quote_table_name(params[:table])
19
- attribute = connection.quote_column_name(params[:attribute])
20
+ table = Arel::Table.new(params[:table])
21
+ node = Arel::Nodes::Case.new
20
22
 
21
- conditions = params[:values].map do |value|
22
- raise OrderAsSpecified::Error, "Cannot order by `nil`" if value.nil?
23
+ params[:values].each_with_index do |value, index|
24
+ attribute = table[params[:attribute]]
25
+ condition =
26
+ if value.is_a?(Range)
27
+ if value.first >= value.last
28
+ raise OrderAsSpecified::Error, "Range needs to be increasing"
29
+ end
23
30
 
24
- if value.is_a? Range
25
- range_clause("#{table}.#{attribute}", value)
26
- else
27
- # Sanitize each value to reduce the risk of SQL injection.
28
- "#{table}.#{attribute}=#{quote(value)}"
29
- end
30
- end
31
+ attribute.between(value)
32
+ elsif case_insensitive
33
+ attribute.matches(value)
34
+ else
35
+ attribute.eq(value)
36
+ end
31
37
 
32
- when_queries = conditions.map.with_index do |cond, index|
33
- "WHEN #{cond} THEN #{index}"
38
+ node.when(condition).then(index)
34
39
  end
35
- case_query = "CASE #{when_queries.join(' ')} ELSE #{conditions.size} END"
36
- scope = order(Arel.sql("#{case_query} ASC"))
40
+
41
+ node.else(node.conditions.size)
42
+ scope = order(Arel::Nodes::Ascending.new(table.grouping(node)))
37
43
 
38
44
  if distinct_on
39
- scope = scope.select(
40
- Arel.sql("DISTINCT ON (#{case_query}) #{table}.*")
41
- )
45
+ distinct = Arel::Nodes::DistinctOn.new(node)
46
+ table_alias = connection.quote_table_name(table.name)
47
+ scope = scope.select(Arel.sql("#{distinct.to_sql} #{table_alias}.*"))
42
48
  end
43
49
 
44
50
  scope
@@ -69,20 +75,4 @@ module OrderAsSpecified
69
75
  }
70
76
  end
71
77
  end
72
-
73
- def range_clause(col, range)
74
- if range.first >= range.last
75
- raise OrderAsSpecified::Error, "Range needs to be increasing"
76
- end
77
-
78
- op = range.exclude_end? ? "<" : "<="
79
- "#{col} >= #{quote(range.first)} AND #{col} #{op} #{quote(range.last)}"
80
- end
81
-
82
- def quote(value)
83
- # We have to explicitly quote for now because SQL sanitization for ORDER BY
84
- # queries isn't in less current versions of Rails.
85
- # See: https://github.com/rails/rails/pull/13008
86
- ActiveRecord::Base.connection.quote(value)
87
- end
88
78
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OrderAsSpecified
4
- VERSION = "1.6"
4
+ VERSION = "1.7"
5
5
  end
@@ -23,10 +23,13 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency "activerecord", ">= 5.0.0"
24
24
 
25
25
  spec.add_development_dependency "bundler"
26
- spec.add_development_dependency "codecov"
27
26
  spec.add_development_dependency "mysql2"
28
27
  spec.add_development_dependency "pg"
29
28
  spec.add_development_dependency "rspec"
30
29
  spec.add_development_dependency "rspec-rails"
31
- spec.add_development_dependency "sqlite3", "~> 1.3.13"
30
+
31
+ # Older versions of Rails locked in the SQLite3 version, so we have to
32
+ # explicitly specify the version here
33
+ sqlite3 = ENV["ACTIVERECORD_VERSION"] == "~> 5.0.0" ? "~> 1.3.13" : "~> 1.4"
34
+ spec.add_development_dependency "sqlite3", sqlite3
32
35
  end
@@ -5,11 +5,15 @@ sqlite3_test:
5
5
 
6
6
  postgresql_test:
7
7
  adapter: postgresql
8
+ host: localhost
8
9
  database: order_as_specified_test
9
10
  username: postgres
11
+ password: postgres
10
12
 
11
13
  mysql_test:
12
14
  adapter: mysql2
13
- database: order_as_specified_test
14
- username: travis
15
+ host: 127.0.0.1
15
16
  encoding: utf8
17
+ database: order_as_specified_test
18
+ username: mysql
19
+ password: mysql
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- VersionedMigration = ActiveRecord::Migration[ActiveRecord::Migration.current_version] # rubocop:disable Metrics/LineLength
3
+ VersionedMigration = ActiveRecord::Migration[ActiveRecord::Migration.current_version] # rubocop:disable Layout/LineLength
4
4
 
5
5
  class TestSetupMigration < VersionedMigration
6
6
  def up
data/spec/mysql_spec.rb CHANGED
@@ -5,12 +5,12 @@ require "shared/order_as_specified_examples"
5
5
  require "config/test_setup_migration"
6
6
 
7
7
  RSpec.describe "MySQL" do
8
- before :all do
8
+ before :all do # rubocop:disable RSpec/BeforeAfterAll
9
9
  ActiveRecord::Base.establish_connection(:mysql_test)
10
10
  TestSetupMigration.migrate(:up)
11
11
  end
12
12
 
13
- after(:all) { ActiveRecord::Base.remove_connection }
13
+ after(:all) { ActiveRecord::Base.remove_connection } # rubocop:disable RSpec/BeforeAfterAll
14
14
 
15
15
  include_examples ".order_as_specified"
16
16
  end
@@ -5,12 +5,12 @@ require "shared/order_as_specified_examples"
5
5
  require "config/test_setup_migration"
6
6
 
7
7
  RSpec.describe "PostgreSQL" do
8
- before :all do
8
+ before :all do # rubocop:disable RSpec/BeforeAfterAll
9
9
  ActiveRecord::Base.establish_connection(:postgresql_test)
10
10
  TestSetupMigration.migrate(:up)
11
11
  end
12
12
 
13
- after(:all) { ActiveRecord::Base.remove_connection }
13
+ after(:all) { ActiveRecord::Base.remove_connection } # rubocop:disable RSpec/BeforeAfterAll
14
14
 
15
15
  include_examples ".order_as_specified"
16
16
 
@@ -31,7 +31,7 @@ RSpec.describe "PostgreSQL" do
31
31
  expect(subject.length).to eq 3
32
32
  end
33
33
 
34
- context "input safety" do
34
+ describe "input safety" do
35
35
  before(:each) { TestClass.create(field: "foo") }
36
36
 
37
37
  it "sanitizes column values" do
@@ -61,8 +61,9 @@ RSpec.describe "PostgreSQL" do
61
61
  distinct_on: true,
62
62
  table => { column => ["foo"] }
63
63
  ).to_sql
64
- pattern = "DISTINCT ON (CASE WHEN #{quoted_table}.#{quoted_column}"
65
- expect(sql).to include(pattern)
64
+
65
+ pattern = /DISTINCT ON \(\s*CASE WHEN #{quoted_table}.#{quoted_column}/
66
+ expect(sql).to match(pattern)
66
67
  end
67
68
  end
68
69
  end
@@ -58,8 +58,8 @@ RSpec.shared_examples ".order_as_specified" do
58
58
  end.shuffle
59
59
  end
60
60
 
61
- it "raises an error" do
62
- expect { subject }.to raise_error(OrderAsSpecified::Error)
61
+ it "returns results in the given order" do
62
+ expect(subject.map(&:id)).to eq shuffled_object_ids
63
63
  end
64
64
  end
65
65
  end
@@ -101,7 +101,7 @@ RSpec.shared_examples ".order_as_specified" do
101
101
  ]
102
102
  end
103
103
 
104
- context "exclusive ranges" do
104
+ context "when ranges are exclusive" do
105
105
  let(:numbers) { [0, 1, 2, 3, 4, 0.9, 1.5] }
106
106
 
107
107
  let(:ranges) { [(1...2), (0...1), (2...5)] }
@@ -119,7 +119,7 @@ RSpec.shared_examples ".order_as_specified" do
119
119
  end
120
120
  end
121
121
 
122
- context "reverse ranges" do
122
+ context "when ranges are in reverse order" do
123
123
  let(:ranges) { [(5..0)] }
124
124
 
125
125
  it "raises an error" do
@@ -163,7 +163,7 @@ RSpec.shared_examples ".order_as_specified" do
163
163
  end
164
164
  end
165
165
 
166
- context "input safety" do
166
+ describe "input safety" do
167
167
  before(:each) do
168
168
  2.times { |i| TestClass.create(field: "foo#{i}") }
169
169
  end
@@ -192,16 +192,39 @@ RSpec.shared_examples ".order_as_specified" do
192
192
  quoted_column = AssociationTestClass.connection.quote_column_name(column)
193
193
 
194
194
  sql = TestClass.order_as_specified(table => { column => ["foo"] }).to_sql
195
- pattern = "ORDER BY CASE WHEN #{quoted_table}.#{quoted_column}"
195
+ pattern = "ORDER BY (CASE WHEN #{quoted_table}.#{quoted_column}"
196
196
  expect(sql).to include(pattern)
197
197
  end
198
198
  end
199
199
 
200
- context "invalid hash input" do
200
+ context "when hash input is invalid" do
201
201
  subject { TestClass.order_as_specified({}) }
202
202
 
203
203
  it "raises an error" do
204
204
  expect { subject }.to raise_error(OrderAsSpecified::Error)
205
205
  end
206
206
  end
207
+
208
+ context "when case insensitive option is used" do
209
+ subject do
210
+ TestClass.
211
+ order_as_specified(field: %w[abc def], case_insensitive: true).
212
+ pluck(TestClass.arel_table[:field].lower)
213
+ end
214
+
215
+ before :each do
216
+ TestClass.create!(
217
+ [
218
+ { field: "dEf" },
219
+ { field: "aBc" },
220
+ { field: "ABC" },
221
+ { field: "DEF" }
222
+ ]
223
+ )
224
+ end
225
+
226
+ it "orders in a case insensitive manner" do
227
+ expect(subject).to eq(%w[abc abc def def])
228
+ end
229
+ end
207
230
  end
data/spec/spec_helper.rb CHANGED
@@ -1,15 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- if ENV["TRAVIS"] == "true" && ENV["CODE_COVERAGE"] == "true"
4
- require "simplecov"
5
- require "codecov"
6
- SimpleCov.formatter = SimpleCov::Formatter::Codecov
7
- SimpleCov.start do
8
- # Omit the spec directory from being counted in code coverage calculations.
9
- add_filter "/spec/"
10
- end
11
- end
12
-
13
3
  require "active_record"
14
4
 
15
5
  require "order_as_specified"
data/spec/sqlite3_spec.rb CHANGED
@@ -5,12 +5,12 @@ require "shared/order_as_specified_examples"
5
5
  require "config/test_setup_migration"
6
6
 
7
7
  RSpec.describe "SQLite3" do
8
- before :all do
8
+ before :all do # rubocop:disable RSpec/BeforeAfterAll
9
9
  ActiveRecord::Base.establish_connection(:sqlite3_test)
10
10
  TestSetupMigration.migrate(:up)
11
11
  end
12
12
 
13
- after(:all) { ActiveRecord::Base.remove_connection }
13
+ after(:all) { ActiveRecord::Base.remove_connection } # rubocop:disable RSpec/BeforeAfterAll
14
14
 
15
15
  include_examples ".order_as_specified"
16
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: order_as_specified
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.6'
4
+ version: '1.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Evelyn
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-11 00:00:00.000000000 Z
11
+ date: 2021-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: codecov
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: mysql2
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +100,14 @@ dependencies:
114
100
  requirements:
115
101
  - - "~>"
116
102
  - !ruby/object:Gem::Version
117
- version: 1.3.13
103
+ version: '1.4'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
107
  requirements:
122
108
  - - "~>"
123
109
  - !ruby/object:Gem::Version
124
- version: 1.3.13
110
+ version: '1.4'
125
111
  description: Obtain ActiveRecord results with a custom ordering with no need to store
126
112
  anything in the database.
127
113
  email:
@@ -130,10 +116,14 @@ executables: []
130
116
  extensions: []
131
117
  extra_rdoc_files: []
132
118
  files:
119
+ - ".dependabot/config.yml"
120
+ - ".github/workflows/auto-approve-dependabot.yml"
121
+ - ".github/workflows/remove-needs-qa.yml"
122
+ - ".github/workflows/tests.yml"
133
123
  - ".gitignore"
134
124
  - ".rubocop.yml"
135
- - ".travis.yml"
136
125
  - CHANGELOG.md
126
+ - CODE_OF_CONDUCT.md
137
127
  - Gemfile
138
128
  - LICENSE.txt
139
129
  - README.md
@@ -157,7 +147,7 @@ homepage: https://github.com/panorama-ed/order_as_specified
157
147
  licenses:
158
148
  - MIT
159
149
  metadata: {}
160
- post_install_message:
150
+ post_install_message:
161
151
  rdoc_options: []
162
152
  require_paths:
163
153
  - lib
@@ -172,9 +162,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
162
  - !ruby/object:Gem::Version
173
163
  version: '0'
174
164
  requirements: []
175
- rubyforge_project:
176
- rubygems_version: 2.7.6
177
- signing_key:
165
+ rubyforge_project:
166
+ rubygems_version: 2.7.6.2
167
+ signing_key:
178
168
  specification_version: 4
179
169
  summary: Add arbitrary ordering to ActiveRecord queries.
180
170
  test_files:
data/.travis.yml DELETED
@@ -1,41 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.6
4
- - 2.5
5
- - 2.4 # Keep this in sync with .rubocop.yml
6
- # We test up to the latest version of Ruby here, and test these Ruby versions
7
- # against all support ActiveRecord versions. One test will be "duplicated"
8
- # below when we calculate code coverage, but I don't know how to avoid that and
9
- # still test all combinations of Ruby and ActiveRecord.
10
- before_script:
11
- - psql -c 'create database order_as_specified_test;' -U postgres
12
- - mysql -e 'CREATE DATABASE order_as_specified_test;'
13
- script:
14
- - bundle exec rspec
15
- services:
16
- - mysql
17
- - postgresql
18
- env:
19
- matrix:
20
- - ACTIVERECORD_VERSION="~> 5.2.0"
21
- - ACTIVERECORD_VERSION="~> 5.1.0"
22
- - ACTIVERECORD_VERSION="~> 5.0.0"
23
- matrix:
24
- include:
25
- - rvm: 2.6
26
- script:
27
- - bundle exec rspec
28
- - gem install --no-document rubocop rubocop-rspec-focused && rubocop
29
- env:
30
- - CODE_COVERAGE=true
31
- - ACTIVERECORD_VERSION="~> 5.2.0"
32
- branches:
33
- only:
34
- # We always run tests for PRs. This prevents running PR tests twice (once "for
35
- # the PR" and once "for the branch"), though we do want tests to run always
36
- # run on master.
37
- - master
38
- notifications:
39
- email: false
40
- slack:
41
- secure: lVaScxPymqeYlTh+KlprWDK+O18BkQTyNSBTfzsLFzWF3Dy+p1rp2aeh0AhuLVYQDrlmFZ7cDMZ1ZYDyV2Y6lLtt+4ii7rATagI8R9WUVYb90C97tu1M6v5tpIjoTEOLx9hGc66heyvq1hNCKXbTqsqmrD69FYdjuXnOfrIs6J4=