1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activerecord/lib/arel/visitors/postgresql.rb
Keenan Brock b775f0cbdc Support NullsFirst for all databases.
Most databases order tables with the `NULL` value first, having it before
all other data values. Postgres has `NULLS` last.

Fortunately, ANSI SQL has an option to allow the database to specify where NULLS
come out in this sort order

    ORDER BY column ASC NULLS FIRST

MS SQL, SQLite, Oracle, and Postgres all follow this syntax. Unfortunately, MySql
does not.

Before:

PostgreSQL: both `.nulls_first()` and `.nulls_last()` work as designed.
Others: both raise a runtime error.

After:

MySQL: `.nulls_first()` works as designed.
MySQL: `.nulls_last()` raises a runtime error
Others: both work as designed
2021-05-18 16:58:21 -04:00

110 lines
3.2 KiB
Ruby

# frozen_string_literal: true
module Arel # :nodoc: all
module Visitors
class PostgreSQL < Arel::Visitors::ToSql
private
def visit_Arel_Nodes_Matches(o, collector)
op = o.case_sensitive ? " LIKE " : " ILIKE "
collector = infix_value o, collector, op
if o.escape
collector << " ESCAPE "
visit o.escape, collector
else
collector
end
end
def visit_Arel_Nodes_DoesNotMatch(o, collector)
op = o.case_sensitive ? " NOT LIKE " : " NOT ILIKE "
collector = infix_value o, collector, op
if o.escape
collector << " ESCAPE "
visit o.escape, collector
else
collector
end
end
def visit_Arel_Nodes_Regexp(o, collector)
op = o.case_sensitive ? " ~ " : " ~* "
infix_value o, collector, op
end
def visit_Arel_Nodes_NotRegexp(o, collector)
op = o.case_sensitive ? " !~ " : " !~* "
infix_value o, collector, op
end
def visit_Arel_Nodes_DistinctOn(o, collector)
collector << "DISTINCT ON ( "
visit(o.expr, collector) << " )"
end
def visit_Arel_Nodes_GroupingElement(o, collector)
collector << "( "
visit(o.expr, collector) << " )"
end
def visit_Arel_Nodes_Cube(o, collector)
collector << "CUBE"
grouping_array_or_grouping_element o, collector
end
def visit_Arel_Nodes_RollUp(o, collector)
collector << "ROLLUP"
grouping_array_or_grouping_element o, collector
end
def visit_Arel_Nodes_GroupingSet(o, collector)
collector << "GROUPING SETS"
grouping_array_or_grouping_element o, collector
end
def visit_Arel_Nodes_Lateral(o, collector)
collector << "LATERAL "
grouping_parentheses o, collector
end
def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
collector = visit o.left, collector
collector << " IS NOT DISTINCT FROM "
visit o.right, collector
end
def visit_Arel_Nodes_IsDistinctFrom(o, collector)
collector = visit o.left, collector
collector << " IS DISTINCT FROM "
visit o.right, collector
end
BIND_BLOCK = proc { |i| "$#{i}" }
private_constant :BIND_BLOCK
def bind_block; BIND_BLOCK; end
# Used by Lateral visitor to enclose select queries in parentheses
def grouping_parentheses(o, collector)
if o.expr.is_a? Nodes::SelectStatement
collector << "("
visit o.expr, collector
collector << ")"
else
visit o.expr, collector
end
end
# Utilized by GroupingSet, Cube & RollUp visitors to
# handle grouping aggregation semantics
def grouping_array_or_grouping_element(o, collector)
if o.expr.is_a? Array
collector << "( "
visit o.expr, collector
collector << " )"
else
visit o.expr, collector
end
end
end
end
end