order_as_specified 1.6 → 1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dependabot/config.yml +46 -0
- data/.github/workflows/auto-approve-dependabot.yml +26 -0
- data/.github/workflows/remove-needs-qa.yml +35 -0
- data/.github/workflows/tests.yml +61 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +2 -5
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +5 -3
- data/README.md +28 -4
- data/RELEASING.md +2 -2
- data/lib/order_as_specified.rb +24 -34
- data/lib/order_as_specified/version.rb +1 -1
- data/order_as_specified.gemspec +5 -2
- data/spec/config/database.yml +6 -2
- data/spec/config/test_setup_migration.rb +1 -1
- data/spec/mysql_spec.rb +2 -2
- data/spec/postgresql_spec.rb +6 -5
- data/spec/shared/order_as_specified_examples.rb +30 -7
- data/spec/spec_helper.rb +0 -10
- data/spec/sqlite3_spec.rb +2 -2
- metadata +14 -24
- data/.travis.yml +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d928c44adb61e277076bd76af0ac1568b132a0f9ab49050d1b047fee59305714
|
4
|
+
data.tar.gz: bcbf4c9b1f4061ae9798535dff306c27c7b845bd827a9cd9f2e0ee7ee195c427
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/.rubocop.yml
CHANGED
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
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -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
|
-
|
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
|
-
|
9
|
-
gem "
|
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
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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!
|
data/lib/order_as_specified.rb
CHANGED
@@ -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 =
|
19
|
-
|
20
|
+
table = Arel::Table.new(params[:table])
|
21
|
+
node = Arel::Nodes::Case.new
|
20
22
|
|
21
|
-
|
22
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
33
|
-
"WHEN #{cond} THEN #{index}"
|
38
|
+
node.when(condition).then(index)
|
34
39
|
end
|
35
|
-
|
36
|
-
|
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
|
-
|
40
|
-
|
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
|
data/order_as_specified.gemspec
CHANGED
@@ -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
|
-
|
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
|
data/spec/config/database.yml
CHANGED
@@ -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
|
-
|
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
|
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
|
data/spec/postgresql_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 "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
|
-
|
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
|
-
|
65
|
-
|
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 "
|
62
|
-
expect
|
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 "
|
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
|
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
|
-
|
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 "
|
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.
|
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:
|
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.
|
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.
|
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=
|