Add ability to config PostgreSQL ORDER BY ... NULLS FIRST or NULLS LAST, close #1125

This commit is contained in:
lichao 2020-12-09 18:59:48 +08:00
parent 150eeb2f08
commit 2f5c6f60e8
5 changed files with 69 additions and 1 deletions

View File

@ -250,6 +250,20 @@ the order indicator arrow by passing `hide_indicator: true` in the sort link:
default_order: { last_name: 'asc', first_name: 'desc' }) %>
```
#### PostgreSQL's sort option
The `NULLS FIRST` and `NULLS LAST` options can be used to determine whether nulls appear before or after non-null values in the sort ordering.
You may want to configure it like this:
```rb
Ransack.configure do |c|
c.postgres_fields_sort_option = :nulls_first # or :nulls_last
end
```
See this feature: https://www.postgresql.org/docs/13/queries-order.html
### Advanced Mode
"Advanced" searches (ab)use Rails' nested attributes functionality in order to

View File

@ -42,6 +42,13 @@ module Ransack
if scope_or_sort.is_a?(Symbol)
relation = relation.send(scope_or_sort)
else
case Ransack.options[:postgres_fields_sort_option]
when :nulls_first
scope_or_sort = scope_or_sort.direction == :asc ? "#{scope_or_sort.to_sql} NULLS FIRST" : "#{scope_or_sort.to_sql} NULLS LAST"
when :nulls_last
scope_or_sort = scope_or_sort.direction == :asc ? "#{scope_or_sort.to_sql} NULLS LAST" : "#{scope_or_sort.to_sql} NULLS FIRST"
end
relation = relation.order(scope_or_sort)
end
end

View File

@ -33,7 +33,8 @@ module Ransack
:up_arrow => '▼'.freeze,
:down_arrow => '▲'.freeze,
:default_arrow => nil,
:sanitize_scope_args => true
:sanitize_scope_args => true,
:postgres_fields_sort_option => nil
}
def configure
@ -141,6 +142,21 @@ module Ransack
self.options[:sanitize_scope_args] = boolean
end
# The `NULLS FIRST` and `NULLS LAST` options can be used to determine
# whether nulls appear before or after non-null values in the sort ordering.
#
# User may want to configure it like this:
#
# Ransack.configure do |c|
# c.postgres_fields_sort_option = :nulls_first # or :nulls_last
# end
#
# See this feature: https://www.postgresql.org/docs/13/queries-order.html
#
def postgres_fields_sort_option=(setting)
self.options[:postgres_fields_sort_option] = setting
end
# By default, Ransack displays sort order indicator arrows in sort links.
# The default may be globally overridden in an initializer file like
# `config/initializers/ransack.rb` as follows:

View File

@ -173,5 +173,15 @@ module Ransack
.to eq false
end
end
it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
default = Ransack.options.clone
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
expect(Ransack.options[:postgres_fields_sort_option]).to eq :nulls_first
Ransack.options = default
end
end
end

View File

@ -507,6 +507,27 @@ module Ransack
@s.sorts = 'id asc'
expect(@s.result.first.id).to eq 1
end
it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
default = Ransack.options.clone
s = Search.new(Person, s: 'name asc')
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC"
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
s = Search.new(Person, s: 'name asc')
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS FIRST"
s = Search.new(Person, s: 'name desc')
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS LAST"
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_last }
s = Search.new(Person, s: 'name asc')
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS LAST"
s = Search.new(Person, s: 'name desc')
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS FIRST"
Ransack.options = default
end
end
describe '#method_missing' do