order_as_specified 1.2 → 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 +5 -5
- 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/.rubocop.yml +2 -260
- data/CHANGELOG.md +34 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -2
- data/README.md +47 -9
- data/RELEASING.md +14 -0
- data/lib/order_as_specified.rb +32 -15
- data/lib/order_as_specified/error.rb +2 -0
- data/lib/order_as_specified/version.rb +3 -1
- data/order_as_specified.gemspec +14 -11
- data/spec/config/database.yml +10 -0
- data/spec/config/test_setup_migration.rb +8 -2
- data/spec/mysql_spec.rb +16 -0
- data/spec/order_as_specified_spec.rb +2 -0
- data/spec/postgresql_spec.rb +26 -14
- data/spec/shared/order_as_specified_examples.rb +107 -7
- data/spec/spec_helper.rb +1 -2
- data/spec/sqlite3_spec.rb +4 -2
- data/spec/support/application_record.rb +5 -0
- data/spec/support/association_test_class.rb +3 -1
- data/spec/support/test_class.rb +3 -1
- metadata +50 -71
- data/.overcommit.yml +0 -8
- data/.travis.yml +0 -20
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "support/application_record"
|
1
4
|
require "support/test_class"
|
2
5
|
require "support/association_test_class"
|
3
6
|
|
@@ -10,7 +13,7 @@ RSpec.shared_examples ".order_as_specified" do
|
|
10
13
|
end
|
11
14
|
|
12
15
|
let(:shuffled_objects) do
|
13
|
-
5
|
16
|
+
Array.new(5) { |i| TestClass.create(field: "Field #{i}") }.shuffle
|
14
17
|
end
|
15
18
|
let(:shuffled_object_fields) { shuffled_objects.map(&:field) }
|
16
19
|
let(:shuffled_object_ids) { shuffled_objects.map(&:id) }
|
@@ -50,11 +53,75 @@ RSpec.shared_examples ".order_as_specified" do
|
|
50
53
|
|
51
54
|
context "when the order includes nil" do
|
52
55
|
let(:shuffled_objects) do
|
53
|
-
5
|
56
|
+
Array.new(5) do |i|
|
54
57
|
TestClass.create(field: (i == 0 ? nil : "Field #{i}"))
|
55
58
|
end.shuffle
|
56
59
|
end
|
57
60
|
|
61
|
+
it "returns results in the given order" do
|
62
|
+
expect(subject.map(&:id)).to eq shuffled_object_ids
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when the order is empty array" do
|
68
|
+
subject { TestClass.order_as_specified(field: []) }
|
69
|
+
|
70
|
+
let(:test_objects) do
|
71
|
+
Array.new(5) do |i|
|
72
|
+
TestClass.create(field: "Field #{i}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it "keep the original order" do
|
77
|
+
test_objects # Build test objects
|
78
|
+
expect(subject.map(&:id)).
|
79
|
+
to eq test_objects.map(&:id)
|
80
|
+
end
|
81
|
+
end
|
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 "when ranges are exclusive" 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 "when ranges are in reverse order" do
|
123
|
+
let(:ranges) { [(5..0)] }
|
124
|
+
|
58
125
|
it "raises an error" do
|
59
126
|
expect { subject }.to raise_error(OrderAsSpecified::Error)
|
60
127
|
end
|
@@ -96,21 +163,22 @@ RSpec.shared_examples ".order_as_specified" do
|
|
96
163
|
end
|
97
164
|
end
|
98
165
|
|
99
|
-
|
166
|
+
describe "input safety" do
|
100
167
|
before(:each) do
|
101
168
|
2.times { |i| TestClass.create(field: "foo#{i}") }
|
102
169
|
end
|
103
170
|
|
104
171
|
it "sanitizes column values" do
|
105
|
-
# Verify that the result set includes two records when using good column
|
172
|
+
# Verify that the result set includes two records when using good column
|
173
|
+
# value.
|
106
174
|
good_value = "foo"
|
107
175
|
records = TestClass.order_as_specified(field: [good_value]).to_a
|
108
176
|
expect(records.count).to eq(2)
|
109
177
|
|
110
178
|
# Attempt to inject a LIMIT clause into the query. If the SQL inputs are
|
111
179
|
# properly sanitized, it will be ignored and the returned result set will
|
112
|
-
# include two records. If not, the LIMIT clause will execute and the
|
113
|
-
# set will include just one record.
|
180
|
+
# include two records. If not, the LIMIT clause will execute and the
|
181
|
+
# result set will include just one record.
|
114
182
|
bad_value = "' LIMIT 1 --"
|
115
183
|
records = TestClass.order_as_specified(field: [bad_value]).to_a
|
116
184
|
expect(records.count).to eq(2)
|
@@ -124,7 +192,39 @@ RSpec.shared_examples ".order_as_specified" do
|
|
124
192
|
quoted_column = AssociationTestClass.connection.quote_column_name(column)
|
125
193
|
|
126
194
|
sql = TestClass.order_as_specified(table => { column => ["foo"] }).to_sql
|
127
|
-
|
195
|
+
pattern = "ORDER BY (CASE WHEN #{quoted_table}.#{quoted_column}"
|
196
|
+
expect(sql).to include(pattern)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context "when hash input is invalid" 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
|
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])
|
128
228
|
end
|
129
229
|
end
|
130
230
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/sqlite3_spec.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
require "shared/order_as_specified_examples"
|
3
5
|
require "config/test_setup_migration"
|
4
6
|
|
5
7
|
RSpec.describe "SQLite3" do
|
6
|
-
before :all do
|
8
|
+
before :all do # rubocop:disable RSpec/BeforeAfterAll
|
7
9
|
ActiveRecord::Base.establish_connection(:sqlite3_test)
|
8
10
|
TestSetupMigration.migrate(:up)
|
9
11
|
end
|
10
12
|
|
11
|
-
after(:all) { ActiveRecord::Base.remove_connection }
|
13
|
+
after(:all) { ActiveRecord::Base.remove_connection } # rubocop:disable RSpec/BeforeAfterAll
|
12
14
|
|
13
15
|
include_examples ".order_as_specified"
|
14
16
|
end
|
data/spec/support/test_class.rb
CHANGED
metadata
CHANGED
@@ -1,141 +1,113 @@
|
|
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
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 5.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 5.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: mysql2
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: overcommit
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ~>
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.23'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ~>
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0.23'
|
54
|
+
version: '0'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: pg
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
72
58
|
requirements:
|
73
|
-
- -
|
59
|
+
- - ">="
|
74
60
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0
|
61
|
+
version: '0'
|
76
62
|
type: :development
|
77
63
|
prerelease: false
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
79
65
|
requirements:
|
80
|
-
- -
|
66
|
+
- - ">="
|
81
67
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0
|
68
|
+
version: '0'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: rspec
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
86
72
|
requirements:
|
87
|
-
- -
|
73
|
+
- - ">="
|
88
74
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
75
|
+
version: '0'
|
90
76
|
type: :development
|
91
77
|
prerelease: false
|
92
78
|
version_requirements: !ruby/object:Gem::Requirement
|
93
79
|
requirements:
|
94
|
-
- -
|
80
|
+
- - ">="
|
95
81
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
82
|
+
version: '0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: rspec-rails
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
|
-
- -
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '3.2'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ~>
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '3.2'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rubocop
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ~>
|
87
|
+
- - ">="
|
116
88
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0
|
89
|
+
version: '0'
|
118
90
|
type: :development
|
119
91
|
prerelease: false
|
120
92
|
version_requirements: !ruby/object:Gem::Requirement
|
121
93
|
requirements:
|
122
|
-
- -
|
94
|
+
- - ">="
|
123
95
|
- !ruby/object:Gem::Version
|
124
|
-
version: '0
|
96
|
+
version: '0'
|
125
97
|
- !ruby/object:Gem::Dependency
|
126
98
|
name: sqlite3
|
127
99
|
requirement: !ruby/object:Gem::Requirement
|
128
100
|
requirements:
|
129
|
-
- -
|
101
|
+
- - "~>"
|
130
102
|
- !ruby/object:Gem::Version
|
131
|
-
version: '1.
|
103
|
+
version: '1.4'
|
132
104
|
type: :development
|
133
105
|
prerelease: false
|
134
106
|
version_requirements: !ruby/object:Gem::Requirement
|
135
107
|
requirements:
|
136
|
-
- -
|
108
|
+
- - "~>"
|
137
109
|
- !ruby/object:Gem::Version
|
138
|
-
version: '1.
|
110
|
+
version: '1.4'
|
139
111
|
description: Obtain ActiveRecord results with a custom ordering with no need to store
|
140
112
|
anything in the database.
|
141
113
|
email:
|
@@ -144,59 +116,66 @@ executables: []
|
|
144
116
|
extensions: []
|
145
117
|
extra_rdoc_files: []
|
146
118
|
files:
|
147
|
-
- .
|
148
|
-
- .
|
149
|
-
- .
|
150
|
-
- .
|
119
|
+
- ".dependabot/config.yml"
|
120
|
+
- ".github/workflows/auto-approve-dependabot.yml"
|
121
|
+
- ".github/workflows/remove-needs-qa.yml"
|
122
|
+
- ".github/workflows/tests.yml"
|
123
|
+
- ".gitignore"
|
124
|
+
- ".rubocop.yml"
|
151
125
|
- CHANGELOG.md
|
126
|
+
- CODE_OF_CONDUCT.md
|
152
127
|
- Gemfile
|
153
128
|
- LICENSE.txt
|
154
129
|
- README.md
|
130
|
+
- RELEASING.md
|
155
131
|
- lib/order_as_specified.rb
|
156
132
|
- lib/order_as_specified/error.rb
|
157
133
|
- lib/order_as_specified/version.rb
|
158
134
|
- order_as_specified.gemspec
|
159
135
|
- spec/config/database.yml
|
160
136
|
- spec/config/test_setup_migration.rb
|
137
|
+
- spec/mysql_spec.rb
|
161
138
|
- spec/order_as_specified_spec.rb
|
162
139
|
- spec/postgresql_spec.rb
|
163
140
|
- spec/shared/order_as_specified_examples.rb
|
164
141
|
- spec/spec_helper.rb
|
165
142
|
- spec/sqlite3_spec.rb
|
143
|
+
- spec/support/application_record.rb
|
166
144
|
- spec/support/association_test_class.rb
|
167
145
|
- spec/support/test_class.rb
|
168
146
|
homepage: https://github.com/panorama-ed/order_as_specified
|
169
147
|
licenses:
|
170
148
|
- MIT
|
171
149
|
metadata: {}
|
172
|
-
post_install_message:
|
150
|
+
post_install_message:
|
173
151
|
rdoc_options: []
|
174
152
|
require_paths:
|
175
153
|
- lib
|
176
154
|
required_ruby_version: !ruby/object:Gem::Requirement
|
177
155
|
requirements:
|
178
|
-
- -
|
156
|
+
- - ">="
|
179
157
|
- !ruby/object:Gem::Version
|
180
158
|
version: '0'
|
181
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
160
|
requirements:
|
183
|
-
- -
|
161
|
+
- - ">="
|
184
162
|
- !ruby/object:Gem::Version
|
185
163
|
version: '0'
|
186
164
|
requirements: []
|
187
|
-
rubyforge_project:
|
188
|
-
rubygems_version: 2.
|
189
|
-
signing_key:
|
165
|
+
rubyforge_project:
|
166
|
+
rubygems_version: 2.7.6.2
|
167
|
+
signing_key:
|
190
168
|
specification_version: 4
|
191
169
|
summary: Add arbitrary ordering to ActiveRecord queries.
|
192
170
|
test_files:
|
193
171
|
- spec/config/database.yml
|
194
172
|
- spec/config/test_setup_migration.rb
|
173
|
+
- spec/mysql_spec.rb
|
195
174
|
- spec/order_as_specified_spec.rb
|
196
175
|
- spec/postgresql_spec.rb
|
197
176
|
- spec/shared/order_as_specified_examples.rb
|
198
177
|
- spec/spec_helper.rb
|
199
178
|
- spec/sqlite3_spec.rb
|
179
|
+
- spec/support/application_record.rb
|
200
180
|
- spec/support/association_test_class.rb
|
201
181
|
- spec/support/test_class.rb
|
202
|
-
has_rdoc:
|