From 2db4ec6a28a59a3f74a4979ae5bc117e5c7573c4 Mon Sep 17 00:00:00 2001 From: Alexander Staubo Date: Thu, 23 Feb 2012 14:06:05 +0100 Subject: [PATCH] Add #extract, which produces ANSI SQL function EXTRACT( from ). --- lib/arel/expressions.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/extract.rb | 23 +++++++++++++++++++++++ lib/arel/visitors/dot.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 4 ++++ test/nodes/test_extract.rb | 19 +++++++++++++++++++ 6 files changed, 57 insertions(+) create mode 100644 lib/arel/nodes/extract.rb create mode 100644 test/nodes/test_extract.rb diff --git a/lib/arel/expressions.rb b/lib/arel/expressions.rb index d1fbfd83d9..fa18f15b67 100644 --- a/lib/arel/expressions.rb +++ b/lib/arel/expressions.rb @@ -19,5 +19,9 @@ module Arel def average Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id') end + + def extract field + Nodes::Extract.new [self], field + end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index b9b5353df7..0477591cae 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -36,6 +36,7 @@ require 'arel/nodes/and' # We should make Function a Unary node and deprecate the use of "aliaz" require 'arel/nodes/function' require 'arel/nodes/count' +require 'arel/nodes/extract' require 'arel/nodes/values' require 'arel/nodes/named_function' diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb new file mode 100644 index 0000000000..1c9ee78816 --- /dev/null +++ b/lib/arel/nodes/extract.rb @@ -0,0 +1,23 @@ +module Arel + module Nodes + + class Extract < Arel::Nodes::Unary + include Arel::Expression + include Arel::Predications + + attr_accessor :field + attr_accessor :alias + + def initialize expr, field, aliaz = nil + super(expr) + @field = field + @alias = aliaz && SqlLiteral.new(aliaz) + end + + def as aliaz + self.alias = SqlLiteral.new(aliaz) + self + end + end + end +end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 800b44b602..8a83ebf48e 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -103,6 +103,12 @@ module Arel alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Sum :function + def extract o + visit_edge o, "expressions" + visit_edge o, "alias" + end + alias :visit_Arel_Nodes_Extract :extract + def visit_Arel_Nodes_NamedFunction o visit_edge o, "name" visit_edge o, "expressions" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index c22df6289d..a6be451e6f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -272,6 +272,10 @@ key on UpdateManager using UpdateManager#key= }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end + def visit_Arel_Nodes_Extract o + "EXTRACT(#{o.field.to_s.upcase} FROM #{visit o.expr})#{o.alias ? " AS #{visit o.alias}" : ''}" + end + def visit_Arel_Nodes_Count o "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x diff --git a/test/nodes/test_extract.rb b/test/nodes/test_extract.rb new file mode 100644 index 0000000000..bd1dfa4750 --- /dev/null +++ b/test/nodes/test_extract.rb @@ -0,0 +1,19 @@ +require 'helper' + +describe Arel::Nodes::Extract do + it "should extract field" do + table = Arel::Table.new :users + table[:timestamp].extract('date').to_sql.must_be_like %{ + EXTRACT(DATE FROM "users"."timestamp") + } + end + + describe "as" do + it 'should alias the extract' do + table = Arel::Table.new :users + table[:timestamp].extract('date').as('foo').to_sql.must_be_like %{ + EXTRACT(DATE FROM "users"."timestamp") AS foo + } + end + end +end