diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/arel.rb | 1 | ||||
-rw-r--r-- | lib/arel/attributes/attribute.rb | 7 | ||||
-rw-r--r-- | lib/arel/expression.rb | 1 | ||||
-rw-r--r-- | lib/arel/factory_methods.rb | 6 | ||||
-rw-r--r-- | lib/arel/nodes.rb | 4 | ||||
-rw-r--r-- | lib/arel/nodes/select_core.rb | 17 | ||||
-rw-r--r-- | lib/arel/nodes/sql_literal.rb | 1 | ||||
-rw-r--r-- | lib/arel/nodes/terminal.rb | 6 | ||||
-rw-r--r-- | lib/arel/nodes/unary.rb | 1 | ||||
-rw-r--r-- | lib/arel/order_predications.rb | 13 | ||||
-rw-r--r-- | lib/arel/predications.rb | 24 | ||||
-rw-r--r-- | lib/arel/visitors/postgresql.rb | 27 | ||||
-rw-r--r-- | lib/arel/visitors/to_sql.rb | 13 |
13 files changed, 68 insertions, 53 deletions
diff --git a/lib/arel.rb b/lib/arel.rb index de429f532e..bc599514e2 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -4,6 +4,7 @@ require 'arel/factory_methods' require 'arel/expressions' require 'arel/predications' require 'arel/math' +require 'arel/order_predications' require 'arel/table' require 'arel/attributes' require 'arel/compatibility/wheres' diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 5aea87ac43..b9fd8da67e 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -3,7 +3,14 @@ module Arel class Attribute < Struct.new :relation, :name include Arel::Expressions include Arel::Predications + include Arel::OrderPredications include Arel::Math + + ### + # Create a node for lowering this attribute + def lower + relation.lower self + end end class String < Attribute; end diff --git a/lib/arel/expression.rb b/lib/arel/expression.rb index eb2c21bfd3..3884d6ede6 100644 --- a/lib/arel/expression.rb +++ b/lib/arel/expression.rb @@ -1,4 +1,5 @@ module Arel module Expression + include Arel::OrderPredications end end diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 2ced1f8971..9fd0878ada 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -25,5 +25,11 @@ module Arel def grouping expr Nodes::Grouping.new expr end + + ### + # Create a LOWER() function + def lower column + Nodes::NamedFunction.new 'LOWER', [column] + end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index cf2aeb2ddc..9576930a54 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -5,6 +5,10 @@ require 'arel/nodes/select_core' require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' +# terminal + +require 'arel/nodes/terminal' + # unary require 'arel/nodes/unary' require 'arel/nodes/unqualified_column' diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 7f577e0a05..bee0a5930c 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -2,15 +2,18 @@ module Arel module Nodes class SelectCore < Arel::Nodes::Node attr_accessor :top, :projections, :wheres, :groups - attr_accessor :having, :source + attr_accessor :having, :source, :set_quantifier def initialize - @source = JoinSource.new nil - @top = nil - @projections = [] - @wheres = [] - @groups = [] - @having = nil + @source = JoinSource.new nil + @top = nil + + # http://savage.net.au/SQL/sql-92.bnf.html#set%20quantifier + @set_quantifier = nil + @projections = [] + @wheres = [] + @groups = [] + @having = nil end def from diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index c76a16daf1..ad0bb00484 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -3,6 +3,7 @@ module Arel class SqlLiteral < String include Arel::Expressions include Arel::Predications + include Arel::OrderPredications end end end diff --git a/lib/arel/nodes/terminal.rb b/lib/arel/nodes/terminal.rb new file mode 100644 index 0000000000..c6b4f4e1e2 --- /dev/null +++ b/lib/arel/nodes/terminal.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Distinct < Arel::Nodes::Node + end + end +end diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 1c834913fa..5c4add4792 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -20,6 +20,7 @@ module Arel On Top Lock + DistinctOn }.each do |name| const_set(name, Class.new(Unary)) end diff --git a/lib/arel/order_predications.rb b/lib/arel/order_predications.rb new file mode 100644 index 0000000000..af163c9454 --- /dev/null +++ b/lib/arel/order_predications.rb @@ -0,0 +1,13 @@ +module Arel + module OrderPredications + + def asc + Nodes::Ordering.new self, :asc + end + + def desc + Nodes::Ordering.new self, :desc + end + + end +end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 75c4c75855..08cbf16d9d 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,5 +1,6 @@ module Arel module Predications + def as other Nodes::As.new self, Nodes::SqlLiteral.new(other) end @@ -152,32 +153,17 @@ module Arel grouping_all :lteq, others end - def asc - Nodes::Ordering.new self, :asc - end - - def desc - Nodes::Ordering.new self, :desc - end - private def grouping_any method_id, others - others = others.dup - first = send method_id, others.shift - - Nodes::Grouping.new others.inject(first) { |memo,expr| - Nodes::Or.new(memo, send(method_id, expr)) + nodes = others.map {|expr| send(method_id, expr)} + Nodes::Grouping.new nodes.inject { |memo,node| + Nodes::Or.new(memo, node) } end def grouping_all method_id, others - others = others.dup - first = send method_id, others.shift - - Nodes::Grouping.new others.inject(first) { |memo,expr| - Nodes::And.new([memo, send(method_id, expr)]) - } + Nodes::Grouping.new Nodes::And.new(others.map {|expr| send(method_id, expr)}) end end end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index c423dc6fc6..377a65a216 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -6,25 +6,6 @@ module Arel visit o.expr end - def visit_Arel_Nodes_SelectStatement o - if !o.orders.empty? && using_distinct_on?(o) - subquery = o.dup - subquery.orders = [] - subquery.limit = nil - subquery.offset = nil - - sql = super(subquery) - [ - "SELECT * FROM (#{sql}) AS id_list", - "ORDER BY #{aliased_orders(o.orders).join(', ')}", - (visit(o.limit) if o.limit), - (visit(o.offset) if o.offset), - ].compact.join ' ' - else - super - end - end - def visit_Arel_Nodes_Matches o "#{visit o.left} ILIKE #{visit o.right}" end @@ -33,12 +14,8 @@ module Arel "#{visit o.left} NOT ILIKE #{visit o.right}" end - def using_distinct_on?(o) - o.cores.any? do |core| - core.projections.any? do |projection| - /DISTINCT ON/ === projection - end - end + def visit_Arel_Nodes_DistinctOn o + "DISTINCT ON ( #{visit o.expr} )" end def aliased_orders orders diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 061e46a436..73319364d5 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -125,8 +125,9 @@ key on UpdateManager using UpdateManager#key= [ "SELECT", (visit(o.top) if o.top), - "#{o.projections.map { |x| visit x }.join ', '}", - visit(o.source), + (visit(o.set_quantifier) if o.set_quantifier), + ("#{o.projections.map { |x| visit x }.join ', '}" unless o.projections.empty?), + (visit(o.source) if o.source), ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.empty?), ("GROUP BY #{o.groups.map { |x| visit x }.join ', ' }" unless o.groups.empty?), (visit(o.having) if o.having), @@ -137,6 +138,14 @@ key on UpdateManager using UpdateManager#key= visit o.expr end + def visit_Arel_Nodes_Distinct o + 'DISTINCT' + end + + def visit_Arel_Nodes_DistinctOn o + raise NotImplementedError, 'DISTINCT ON not implemented for this db' + end + def visit_Arel_Nodes_With o "WITH #{o.children.map { |x| visit x }.join(', ')}" end |