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
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
# Unreleased (`master`)
|
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
|
+
|
8
|
+
# 1.6
|
9
|
+
|
10
|
+
We are dropping official support for Ruby 2.3 and below, though they may
|
11
|
+
continue to work.
|
12
|
+
|
13
|
+
This release adds support for ordering by `Range`s. Big thanks to
|
14
|
+
[Karl-Aksel Puulmann](https://github.com/macobo) for adding this functionality!
|
15
|
+
|
16
|
+
# 1.5
|
17
|
+
|
18
|
+
This release improves performance by switching to use `CASE` statements. Huge
|
19
|
+
thanks to [Yen-Nan (Maso) Lin](https://github.com/masolin) for this improvement!
|
20
|
+
|
21
|
+
# 1.4
|
22
|
+
|
23
|
+
This release removes deprecation warnings for ActiveRecord 5.2 users, and drops
|
24
|
+
support for ActiveRecord 4.x. Many thanks to
|
25
|
+
[George Protacio-Karaszi](https://github.com/GeorgeKaraszi) for pointing out
|
26
|
+
this issue!
|
27
|
+
|
28
|
+
# 1.3
|
29
|
+
|
30
|
+
This release adds support for ActiveRecord 5.1. Many thanks to
|
31
|
+
[cohki0305](https://github.com/cohki0305) for identifying the issue,
|
32
|
+
[Billy Ferguson](https://github.com/fergyfresh) for investigating it, and
|
33
|
+
especially to [Alex Heeton](https://github.com/heeton) for fixing it.
|
34
|
+
|
1
35
|
# 1.2
|
2
36
|
|
3
37
|
This release contains an important change: `order_as_specified` is no longer
|
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
@@ -1,6 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
|
-
|
5
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
6
|
+
|
7
|
+
# Specify your gem's dependencies in unique_attributes.gemspec
|
4
8
|
gemspec
|
5
9
|
|
6
|
-
|
10
|
+
group :development do
|
11
|
+
gem "panolint", github: "panorama-ed/panolint", branch: "main"
|
12
|
+
end
|
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
[](https://codecov.io/gh/panorama-ed/order_as_specified)
|
2
|
+
[](https://travis-ci.com/panorama-ed/order_as_specified)
|
3
|
+
[](http://inch-ci.org/github/panorama-ed/order_as_specified)
|
4
|
+
[](http://badge.fury.io/rb/order_as_specified)
|
2
5
|
|
3
6
|
# OrderAsSpecified
|
4
7
|
|
@@ -26,8 +29,8 @@ TestObject.order_as_specified(language: ["es", "en", "fr"])
|
|
26
29
|
|
27
30
|
Other gems like `ranked-model`, `acts_as_sortable`, etc. assume you want the
|
28
31
|
same ordering each time, and store data to keep track of this in the database.
|
29
|
-
They're great at what they do, but if
|
30
|
-
don't always want an ordering, this gem is your friend.
|
32
|
+
They're great at what they do, but if you want to change the ordering, or if
|
33
|
+
you don't always want an ordering, this gem is your friend.
|
31
34
|
|
32
35
|
## Installation
|
33
36
|
|
@@ -139,6 +142,20 @@ TestObject.order_as_specified(language: ["fr", "es"])
|
|
139
142
|
]>
|
140
143
|
```
|
141
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
|
+
|
142
159
|
In databases that support it (such as PostgreSQL), you can also use an option to
|
143
160
|
add a `DISTINCT ON` to your query when you would otherwise have duplicates:
|
144
161
|
|
@@ -151,10 +168,32 @@ TestObject.order_as_specified(distinct_on: true, language: ["fr", "en"])
|
|
151
168
|
]>
|
152
169
|
```
|
153
170
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
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
|
+
```
|
185
|
+
|
186
|
+
## Limitations
|
187
|
+
|
188
|
+
Databases may have limitations on the underlying number of fields you can have
|
189
|
+
in an `ORDER BY` clause. For example, in PostgreSQL if you pass in more than
|
190
|
+
1664 list elements you'll [receive this error](https://github.com/panorama-ed/order_as_specified/issues/34):
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
PG::ProgramLimitExceeded: ERROR: target lists can have at most 1664 entries
|
194
|
+
```
|
195
|
+
|
196
|
+
That's a database limitation that this gem cannot avoid, unfortunately.
|
158
197
|
|
159
198
|
## Documentation
|
160
199
|
|
@@ -169,8 +208,7 @@ We have documentation on [RubyDoc](http://www.rubydoc.info/github/panorama-ed/or
|
|
169
208
|
5. Create a new Pull Request
|
170
209
|
|
171
210
|
**Make sure your changes have appropriate tests (`bundle exec rspec`)
|
172
|
-
and conform to the Rubocop style specified.**
|
173
|
-
[overcommit](https://github.com/causes/overcommit) to enforce good code.
|
211
|
+
and conform to the Rubocop style specified.**
|
174
212
|
|
175
213
|
## License
|
176
214
|
|
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. Make a PR.
|
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
|
+
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
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "order_as_specified/version"
|
2
4
|
require "order_as_specified/error"
|
3
5
|
|
@@ -5,31 +7,44 @@ require "order_as_specified/error"
|
|
5
7
|
# the database in an arbitrary order, without having to store anything extra
|
6
8
|
# in the database. Simply `extend` it into your class and then you can use the
|
7
9
|
# `order_as_specified` class method.
|
8
|
-
|
9
10
|
module OrderAsSpecified
|
10
11
|
# @param hash [Hash] the ActiveRecord arguments hash
|
11
12
|
# @return [ActiveRecord::Relation] the objects, ordered as specified
|
12
13
|
def order_as_specified(hash)
|
13
14
|
distinct_on = hash.delete(:distinct_on)
|
15
|
+
case_insensitive = hash.delete(:case_insensitive)
|
16
|
+
|
14
17
|
params = extract_params(hash)
|
18
|
+
return all if params[:values].empty?
|
15
19
|
|
16
|
-
table =
|
17
|
-
|
20
|
+
table = Arel::Table.new(params[:table])
|
21
|
+
node = Arel::Nodes::Case.new
|
18
22
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
24
30
|
|
25
|
-
|
26
|
-
|
31
|
+
attribute.between(value)
|
32
|
+
elsif case_insensitive
|
33
|
+
attribute.matches(value)
|
34
|
+
else
|
35
|
+
attribute.eq(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
node.when(condition).then(index)
|
27
39
|
end
|
28
40
|
|
29
|
-
|
41
|
+
node.else(node.conditions.size)
|
42
|
+
scope = order(Arel::Nodes::Ascending.new(table.grouping(node)))
|
30
43
|
|
31
44
|
if distinct_on
|
32
|
-
|
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}.*"))
|
33
48
|
end
|
34
49
|
|
35
50
|
scope
|
@@ -43,13 +58,15 @@ module OrderAsSpecified
|
|
43
58
|
# @param table [String/Symbol] the name of the table, default: the class table
|
44
59
|
# @param hash [Hash] the ActiveRecord-style arguments, such as:
|
45
60
|
# { other_objects: { id: [1, 5, 3] } }
|
46
|
-
def extract_params(table = table_name
|
47
|
-
|
61
|
+
def extract_params(hash, table = table_name)
|
62
|
+
unless hash.size == 1
|
63
|
+
raise OrderAsSpecified::Error, "Could not parse params"
|
64
|
+
end
|
48
65
|
|
49
66
|
key, val = hash.first
|
50
67
|
|
51
68
|
if val.is_a? Hash
|
52
|
-
extract_params(key,
|
69
|
+
extract_params(hash[key], key)
|
53
70
|
else
|
54
71
|
{
|
55
72
|
table: table,
|
data/order_as_specified.gemspec
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require "order_as_specified/version"
|
5
6
|
|
@@ -19,14 +20,16 @@ Gem::Specification.new do |spec|
|
|
19
20
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
21
|
spec.require_paths = ["lib"]
|
21
22
|
|
22
|
-
spec.add_dependency "activerecord", ">=
|
23
|
+
spec.add_dependency "activerecord", ">= 5.0.0"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler"
|
26
|
+
spec.add_development_dependency "mysql2"
|
27
|
+
spec.add_development_dependency "pg"
|
28
|
+
spec.add_development_dependency "rspec"
|
29
|
+
spec.add_development_dependency "rspec-rails"
|
23
30
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
spec.add_development_dependency "
|
28
|
-
spec.add_development_dependency "rspec", "~> 3.2"
|
29
|
-
spec.add_development_dependency "rspec-rails", "~> 3.2"
|
30
|
-
spec.add_development_dependency "rubocop", "~> 0.29"
|
31
|
-
spec.add_development_dependency "sqlite3", ">= 1.3"
|
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,5 +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
|
12
|
+
|
13
|
+
mysql_test:
|
14
|
+
adapter: mysql2
|
15
|
+
host: 127.0.0.1
|
16
|
+
encoding: utf8
|
17
|
+
database: order_as_specified_test
|
18
|
+
username: mysql
|
19
|
+
password: mysql
|
@@ -1,9 +1,15 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
VersionedMigration = ActiveRecord::Migration[ActiveRecord::Migration.current_version] # rubocop:disable Layout/LineLength
|
4
|
+
|
5
|
+
class TestSetupMigration < VersionedMigration
|
2
6
|
def up
|
3
|
-
|
7
|
+
db_connection = ActiveRecord::Base.connection
|
8
|
+
return if db_connection.try(:data_source_exists?, :test_classes)
|
4
9
|
|
5
10
|
create_table :test_classes do |t|
|
6
11
|
t.string :field
|
12
|
+
t.float :number_field
|
7
13
|
end
|
8
14
|
|
9
15
|
create_table :association_test_classes do |t|
|
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 # rubocop:disable RSpec/BeforeAfterAll
|
9
|
+
ActiveRecord::Base.establish_connection(:mysql_test)
|
10
|
+
TestSetupMigration.migrate(:up)
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) { ActiveRecord::Base.remove_connection } # rubocop:disable RSpec/BeforeAfterAll
|
14
|
+
|
15
|
+
include_examples ".order_as_specified"
|
16
|
+
end
|
data/spec/postgresql_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 "PostgreSQL" do
|
6
|
-
before :all do
|
8
|
+
before :all do # rubocop:disable RSpec/BeforeAfterAll
|
7
9
|
ActiveRecord::Base.establish_connection(:postgresql_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
|
|
@@ -21,25 +23,28 @@ RSpec.describe "PostgreSQL" do
|
|
21
23
|
end
|
22
24
|
|
23
25
|
let(:shuffled_objects) do
|
24
|
-
fields = 3
|
25
|
-
5
|
26
|
+
fields = Array.new(3) { |i| "Field #{i}" } * 2
|
27
|
+
Array.new(5) { |i| TestClass.create(field: fields[i]) }.shuffle
|
26
28
|
end
|
27
29
|
|
28
30
|
it "returns distinct objects" do
|
29
31
|
expect(subject.length).to eq 3
|
30
32
|
end
|
31
33
|
|
32
|
-
|
34
|
+
describe "input safety" do
|
33
35
|
before(:each) { TestClass.create(field: "foo") }
|
34
36
|
|
35
37
|
it "sanitizes column values" do
|
36
|
-
# Attempt to inject code to add a 'hi' field to each record. If the SQL
|
37
|
-
# are properly sanitized, the code will be ignored and the
|
38
|
-
# instances will not respond to #hi. If not, the code
|
39
|
-
# each of the returned model instances will have a #hi
|
40
|
-
# new field.
|
38
|
+
# Attempt to inject code to add a 'hi' field to each record. If the SQL
|
39
|
+
# inputs are properly sanitized, the code will be ignored and the
|
40
|
+
# returned model instances will not respond to #hi. If not, the code
|
41
|
+
# will execute and each of the returned model instances will have a #hi
|
42
|
+
# method to access the new field.
|
41
43
|
bad_value = "foo') field, 'hi'::varchar AS hi FROM test_classes --"
|
42
|
-
record = TestClass.order_as_specified(
|
44
|
+
record = TestClass.order_as_specified(
|
45
|
+
distinct_on: true,
|
46
|
+
field: [bad_value]
|
47
|
+
).to_a.first
|
43
48
|
expect(record).to_not respond_to(:hi)
|
44
49
|
end
|
45
50
|
|
@@ -48,10 +53,17 @@ RSpec.describe "PostgreSQL" do
|
|
48
53
|
quoted_table = AssociationTestClass.connection.quote_table_name(table)
|
49
54
|
|
50
55
|
column = "id"
|
51
|
-
quoted_column = AssociationTestClass.
|
56
|
+
quoted_column = AssociationTestClass.
|
57
|
+
connection.
|
58
|
+
quote_column_name(column)
|
59
|
+
|
60
|
+
sql = TestClass.order_as_specified(
|
61
|
+
distinct_on: true,
|
62
|
+
table => { column => ["foo"] }
|
63
|
+
).to_sql
|
52
64
|
|
53
|
-
|
54
|
-
expect(sql).to
|
65
|
+
pattern = /DISTINCT ON \(\s*CASE WHEN #{quoted_table}.#{quoted_column}/
|
66
|
+
expect(sql).to match(pattern)
|
55
67
|
end
|
56
68
|
end
|
57
69
|
end
|