order_as_specified 1.5 → 1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +3 -15
- data/.travis.yml +33 -20
- data/CHANGELOG.md +10 -0
- data/Gemfile +3 -1
- data/README.md +4 -1
- data/RELEASING.md +14 -0
- data/lib/order_as_specified.rb +25 -7
- data/lib/order_as_specified/version.rb +1 -1
- data/order_as_specified.gemspec +3 -4
- data/spec/config/database.yml +6 -0
- data/spec/config/test_setup_migration.rb +1 -0
- data/spec/mysql_spec.rb +16 -0
- data/spec/postgresql_spec.rb +0 -2
- data/spec/shared/order_as_specified_examples.rb +56 -2
- data/spec/spec_helper.rb +3 -2
- metadata +14 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 119668cc688124610b87036f0f929c0fbcc35ef4acea5e1c2a1cdc48c1101241
|
4
|
+
data.tar.gz: a17df8766bfe178cac883311d8ba4b165b4e43a9c4afd1d8e4b8af0e099d5010
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a53e19dc18fb420fbf88f1fb535b46a0a5c5b13a84158c237a350243f8cfefa5f78ae048087bcc939ea7ecab12e4b7aec5c62bae7960d921a83704f9a53a45e
|
7
|
+
data.tar.gz: 0ca1d4697d3634f442edb58173cf4d7f6199571ae1a69415cb6cb2d8b93079ff588023e5549f99ca998979cfeff93ee3ea1f2f0810afd90c8501df829d41e104
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,17 +1,5 @@
|
|
1
|
-
|
2
|
-
-
|
1
|
+
inherit_from:
|
2
|
+
- https://raw.githubusercontent.com/panorama-ed/code-conventions/master/rubocop.yml
|
3
3
|
|
4
4
|
AllCops:
|
5
|
-
TargetRubyVersion: 2.
|
6
|
-
|
7
|
-
AbcSize:
|
8
|
-
Enabled: false
|
9
|
-
|
10
|
-
DotPosition:
|
11
|
-
EnforcedStyle: trailing
|
12
|
-
|
13
|
-
MethodLength:
|
14
|
-
Enabled: false
|
15
|
-
|
16
|
-
StringLiterals:
|
17
|
-
EnforcedStyle: double_quotes
|
5
|
+
TargetRubyVersion: 2.4 # Keep this in sync with .travis.yml
|
data/.travis.yml
CHANGED
@@ -1,28 +1,41 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.
|
4
|
-
- 2.5
|
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.
|
5
10
|
before_script:
|
6
|
-
|
7
|
-
|
8
|
-
- chmod +x ./cc-test-reporter
|
9
|
-
- ./cc-test-reporter before-build
|
11
|
+
- psql -c 'create database order_as_specified_test;' -U postgres
|
12
|
+
- mysql -e 'CREATE DATABASE order_as_specified_test;'
|
10
13
|
script:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
addons:
|
16
|
-
postgresql: "9.3"
|
14
|
+
- bundle exec rspec
|
15
|
+
services:
|
16
|
+
- mysql
|
17
|
+
- postgresql
|
17
18
|
env:
|
18
|
-
global:
|
19
|
-
CC_TEST_REPORTER_ID=781c439d68cbb928316deaec1c7136f98423e1db87238f99cbc95183de94df9e
|
20
19
|
matrix:
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
24
38
|
notifications:
|
25
39
|
email: false
|
26
|
-
|
27
|
-
|
28
|
-
secure: pLL6WXsWnvigZNgcYYwr0el3AG3WbRXOV4zAoBx/pAD/y51/KOjWboUO5szOqIicdSBJTIY5el7wK4uUi5elseumjl1jvOQSG7izvCGzDekuJuOTj9f6MdLtigbIaWO5/NWtXw0/JGHDQJpB4HyOv1mGAjQ3Y6MKxMNv+RUsgRI=
|
40
|
+
slack:
|
41
|
+
secure: lVaScxPymqeYlTh+KlprWDK+O18BkQTyNSBTfzsLFzWF3Dy+p1rp2aeh0AhuLVYQDrlmFZ7cDMZ1ZYDyV2Y6lLtt+4ii7rATagI8R9WUVYb90C97tu1M6v5tpIjoTEOLx9hGc66heyvq1hNCKXbTqsqmrD69FYdjuXnOfrIs6J4=
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# Unreleased (`master`)
|
2
|
+
|
3
|
+
# 1.6
|
4
|
+
|
5
|
+
We are dropping official support for Ruby 2.3 and below, though they may
|
6
|
+
continue to work.
|
7
|
+
|
8
|
+
This release adds support for ordering by `Range`s. Big thanks to
|
9
|
+
[Karl-Aksel Puulmann](https://github.com/macobo) for adding this functionality!
|
10
|
+
|
1
11
|
# 1.5
|
2
12
|
|
3
13
|
This release improves performance by switching to use `CASE` statements. Huge
|
data/Gemfile
CHANGED
@@ -5,4 +5,6 @@ source "https://rubygems.org"
|
|
5
5
|
# Specify your gem's dependencies in order_as_specified.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
-
|
8
|
+
if ENV["TRAVIS"] == "true" && ENV["ACTIVERECORD_VERSION"]
|
9
|
+
gem "activerecord", ENV["ACTIVERECORD_VERSION"]
|
10
|
+
end
|
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
[![Code
|
1
|
+
[![Code Coverage](https://codecov.io/gh/panorama-ed/order_as_specified/branch/master/graph/badge.svg)](https://codecov.io/gh/panorama-ed/order_as_specified)
|
2
|
+
[![Build Status](https://travis-ci.com/panorama-ed/order_as_specified.svg)](https://travis-ci.com/panorama-ed/order_as_specified)
|
3
|
+
[![Inline docs](http://inch-ci.org/github/panorama-ed/order_as_specified.png)](http://inch-ci.org/github/panorama-ed/order_as_specified)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/order_as_specified.svg)](http://badge.fury.io/rb/order_as_specified)
|
2
5
|
|
3
6
|
# OrderAsSpecified
|
4
7
|
|
data/RELEASING.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Releasing
|
2
|
+
|
3
|
+
## These are steps for the maintainer to take to release a new version of this gem.
|
4
|
+
|
5
|
+
1. Create a new branch for bumping the version.
|
6
|
+
1. On the new branch, update the VERSION constant in `lib/order_as_specified/version.rb`.
|
7
|
+
1. Update the Changelog.
|
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
|
+
1. Make a PR.
|
12
|
+
1. Merge the PR.
|
13
|
+
1. Push to rubygems: `gem build order_as_specified.gemspec && gem push *.gem && rm *.gem`
|
14
|
+
1. Celebrate!
|
data/lib/order_as_specified.rb
CHANGED
@@ -18,15 +18,15 @@ module OrderAsSpecified
|
|
18
18
|
table = connection.quote_table_name(params[:table])
|
19
19
|
attribute = connection.quote_column_name(params[:attribute])
|
20
20
|
|
21
|
-
# We have to explicitly quote for now because SQL sanitization for ORDER BY
|
22
|
-
# queries isn't in less current versions of Rails.
|
23
|
-
# See: https://github.com/rails/rails/pull/13008
|
24
|
-
db_connection = ActiveRecord::Base.connection
|
25
21
|
conditions = params[:values].map do |value|
|
26
22
|
raise OrderAsSpecified::Error, "Cannot order by `nil`" if value.nil?
|
27
23
|
|
28
|
-
|
29
|
-
|
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
30
|
end
|
31
31
|
|
32
32
|
when_queries = conditions.map.with_index do |cond, index|
|
@@ -53,7 +53,9 @@ module OrderAsSpecified
|
|
53
53
|
# @param hash [Hash] the ActiveRecord-style arguments, such as:
|
54
54
|
# { other_objects: { id: [1, 5, 3] } }
|
55
55
|
def extract_params(hash, table = table_name)
|
56
|
-
|
56
|
+
unless hash.size == 1
|
57
|
+
raise OrderAsSpecified::Error, "Could not parse params"
|
58
|
+
end
|
57
59
|
|
58
60
|
key, val = hash.first
|
59
61
|
|
@@ -67,4 +69,20 @@ module OrderAsSpecified
|
|
67
69
|
}
|
68
70
|
end
|
69
71
|
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
|
70
88
|
end
|
data/order_as_specified.gemspec
CHANGED
@@ -23,11 +23,10 @@ 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
|
+
spec.add_development_dependency "mysql2"
|
26
28
|
spec.add_development_dependency "pg"
|
27
29
|
spec.add_development_dependency "rspec"
|
28
30
|
spec.add_development_dependency "rspec-rails"
|
29
|
-
spec.add_development_dependency "
|
30
|
-
spec.add_development_dependency "rubocop-rspec-focused"
|
31
|
-
spec.add_development_dependency "simplecov"
|
32
|
-
spec.add_development_dependency "sqlite3"
|
31
|
+
spec.add_development_dependency "sqlite3", "~> 1.3.13"
|
33
32
|
end
|
data/spec/config/database.yml
CHANGED
data/spec/mysql_spec.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "shared/order_as_specified_examples"
|
5
|
+
require "config/test_setup_migration"
|
6
|
+
|
7
|
+
RSpec.describe "MySQL" do
|
8
|
+
before :all do
|
9
|
+
ActiveRecord::Base.establish_connection(:mysql_test)
|
10
|
+
TestSetupMigration.migrate(:up)
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) { ActiveRecord::Base.remove_connection }
|
14
|
+
|
15
|
+
include_examples ".order_as_specified"
|
16
|
+
end
|
data/spec/postgresql_spec.rb
CHANGED
@@ -4,7 +4,6 @@ require "spec_helper"
|
|
4
4
|
require "shared/order_as_specified_examples"
|
5
5
|
require "config/test_setup_migration"
|
6
6
|
|
7
|
-
# rubocop:disable Metrics/BlockLength
|
8
7
|
RSpec.describe "PostgreSQL" do
|
9
8
|
before :all do
|
10
9
|
ActiveRecord::Base.establish_connection(:postgresql_test)
|
@@ -68,4 +67,3 @@ RSpec.describe "PostgreSQL" do
|
|
68
67
|
end
|
69
68
|
end
|
70
69
|
end
|
71
|
-
# rubocop:enable Metrics/BlockLength
|
@@ -4,7 +4,6 @@ require "support/application_record"
|
|
4
4
|
require "support/test_class"
|
5
5
|
require "support/association_test_class"
|
6
6
|
|
7
|
-
# rubocop:disable Metrics/BlockLength
|
8
7
|
RSpec.shared_examples ".order_as_specified" do
|
9
8
|
# Clean up after each test. This is a lot lighter for these few tests than
|
10
9
|
# trying to wrangle with RSpec-Rails to get transactional tests to work.
|
@@ -81,6 +80,54 @@ RSpec.shared_examples ".order_as_specified" do
|
|
81
80
|
end
|
82
81
|
end
|
83
82
|
|
83
|
+
context "when the order is a range" do
|
84
|
+
subject do
|
85
|
+
TestClass.order_as_specified(number_field: ranges).order(:number_field)
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:ranges) { [(3..4), (0..2)] }
|
89
|
+
let(:numbers) { [0, 1, 2, 3, 4] }
|
90
|
+
|
91
|
+
let!(:test_objects) do
|
92
|
+
numbers.each do |i|
|
93
|
+
TestClass.create(number_field: i)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "sorts according to range" do
|
98
|
+
expect(subject.map(&:number_field)).to eq [
|
99
|
+
*numbers.drop(3),
|
100
|
+
*numbers.take(3)
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
context "exclusive ranges" do
|
105
|
+
let(:numbers) { [0, 1, 2, 3, 4, 0.9, 1.5] }
|
106
|
+
|
107
|
+
let(:ranges) { [(1...2), (0...1), (2...5)] }
|
108
|
+
|
109
|
+
it "sorts according to range" do
|
110
|
+
expect(subject.map(&:number_field)).to eq [
|
111
|
+
1,
|
112
|
+
1.5,
|
113
|
+
0,
|
114
|
+
0.9,
|
115
|
+
2,
|
116
|
+
3,
|
117
|
+
4
|
118
|
+
]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "reverse ranges" do
|
123
|
+
let(:ranges) { [(5..0)] }
|
124
|
+
|
125
|
+
it "raises an error" do
|
126
|
+
expect { subject }.to raise_error(OrderAsSpecified::Error)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
84
131
|
context "with another table name specified" do
|
85
132
|
subject do
|
86
133
|
TestClass.
|
@@ -149,5 +196,12 @@ RSpec.shared_examples ".order_as_specified" do
|
|
149
196
|
expect(sql).to include(pattern)
|
150
197
|
end
|
151
198
|
end
|
199
|
+
|
200
|
+
context "invalid hash input" do
|
201
|
+
subject { TestClass.order_as_specified({}) }
|
202
|
+
|
203
|
+
it "raises an error" do
|
204
|
+
expect { subject }.to raise_error(OrderAsSpecified::Error)
|
205
|
+
end
|
206
|
+
end
|
152
207
|
end
|
153
|
-
# rubocop:enable Metrics/BlockLength
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
if ENV["TRAVIS"] == "true"
|
3
|
+
if ENV["TRAVIS"] == "true" && ENV["CODE_COVERAGE"] == "true"
|
4
4
|
require "simplecov"
|
5
|
-
|
5
|
+
require "codecov"
|
6
|
+
SimpleCov.formatter = SimpleCov::Formatter::Codecov
|
6
7
|
SimpleCov.start do
|
7
8
|
# Omit the spec directory from being counted in code coverage calculations.
|
8
9
|
add_filter "/spec/"
|
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.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jacob Evelyn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: codecov
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: mysql2
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,21 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop
|
70
|
+
name: pg
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
86
72
|
requirements:
|
87
73
|
- - ">="
|
@@ -95,7 +81,7 @@ dependencies:
|
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: '0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
84
|
+
name: rspec
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
87
|
- - ">="
|
@@ -109,7 +95,7 @@ dependencies:
|
|
109
95
|
- !ruby/object:Gem::Version
|
110
96
|
version: '0'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
98
|
+
name: rspec-rails
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
114
100
|
requirements:
|
115
101
|
- - ">="
|
@@ -126,16 +112,16 @@ dependencies:
|
|
126
112
|
name: sqlite3
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
128
114
|
requirements:
|
129
|
-
- - "
|
115
|
+
- - "~>"
|
130
116
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
117
|
+
version: 1.3.13
|
132
118
|
type: :development
|
133
119
|
prerelease: false
|
134
120
|
version_requirements: !ruby/object:Gem::Requirement
|
135
121
|
requirements:
|
136
|
-
- - "
|
122
|
+
- - "~>"
|
137
123
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
124
|
+
version: 1.3.13
|
139
125
|
description: Obtain ActiveRecord results with a custom ordering with no need to store
|
140
126
|
anything in the database.
|
141
127
|
email:
|
@@ -151,12 +137,14 @@ files:
|
|
151
137
|
- Gemfile
|
152
138
|
- LICENSE.txt
|
153
139
|
- README.md
|
140
|
+
- RELEASING.md
|
154
141
|
- lib/order_as_specified.rb
|
155
142
|
- lib/order_as_specified/error.rb
|
156
143
|
- lib/order_as_specified/version.rb
|
157
144
|
- order_as_specified.gemspec
|
158
145
|
- spec/config/database.yml
|
159
146
|
- spec/config/test_setup_migration.rb
|
147
|
+
- spec/mysql_spec.rb
|
160
148
|
- spec/order_as_specified_spec.rb
|
161
149
|
- spec/postgresql_spec.rb
|
162
150
|
- spec/shared/order_as_specified_examples.rb
|
@@ -192,6 +180,7 @@ summary: Add arbitrary ordering to ActiveRecord queries.
|
|
192
180
|
test_files:
|
193
181
|
- spec/config/database.yml
|
194
182
|
- spec/config/test_setup_migration.rb
|
183
|
+
- spec/mysql_spec.rb
|
195
184
|
- spec/order_as_specified_spec.rb
|
196
185
|
- spec/postgresql_spec.rb
|
197
186
|
- spec/shared/order_as_specified_examples.rb
|