diff options
-rw-r--r-- | .travis.yml | 8 | ||||
-rw-r--r-- | History.txt | 6 | ||||
-rw-r--r-- | lib/arel.rb | 2 | ||||
-rw-r--r-- | lib/arel/nodes/unary.rb | 8 | ||||
-rw-r--r-- | lib/arel/visitors/depth_first.rb | 5 | ||||
-rw-r--r-- | lib/arel/visitors/dot.rb | 5 | ||||
-rw-r--r-- | lib/arel/visitors/oracle12.rb | 12 | ||||
-rw-r--r-- | lib/arel/visitors/postgresql.rb | 36 | ||||
-rw-r--r-- | lib/arel/visitors/to_sql.rb | 7 | ||||
-rw-r--r-- | test/visitors/test_oracle12.rb | 22 | ||||
-rw-r--r-- | test/visitors/test_postgres.rb | 78 | ||||
-rw-r--r-- | test/visitors/test_to_sql.rb | 2 |
12 files changed, 174 insertions, 17 deletions
diff --git a/.travis.yml b/.travis.yml index 31d4b9ed3a..363f53f6ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,16 +9,20 @@ env: - JRUBY_OPTS='--dev -J-Xmx1024M' rvm: - rbx-2 + - jruby-9.0.5.0 - jruby-head - 2.0.0 - 2.1 - - 2.2.4 - - 2.3.0 + - 2.2.5 + - 2.3.1 - ruby-head matrix: fast_finish: true allow_failures: + - rvm: jruby-9.0.5.0 + - rvm: jruby-head - rvm: ruby-head + - rvm: jruby-head bundler_args: --jobs 3 --retry 3 notifications: email: false diff --git a/History.txt b/History.txt index 9d4cd32461..07cb9024fd 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +=== 7.0.1 / unreleased + +* Enhancements + + * Support Ruby 2.4 unified Integer class + === 7.0.0 / 2015-12-17 * Enhancements diff --git a/lib/arel.rb b/lib/arel.rb index f32929e70f..2bd56372ef 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/delete_manager' require 'arel/nodes' module Arel - VERSION = '7.0.0' + VERSION = '7.0.1.pre' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index a0062ff5be..50946980b4 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -22,15 +22,19 @@ module Arel %w{ Bin + Cube + DistinctOn Group + GroupingElement + GroupingSet Limit + Lock Not Offset On Ordering + RollUp Top - Lock - DistinctOn }.each do |name| const_set(name, Class.new(Unary)) end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index fb21fb1e70..80b3c3c346 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -18,6 +18,10 @@ module Arel end alias :visit_Arel_Nodes_Else :unary alias :visit_Arel_Nodes_Group :unary + alias :visit_Arel_Nodes_Cube :unary + alias :visit_Arel_Nodes_RollUp :unary + alias :visit_Arel_Nodes_GroupingSet :unary + alias :visit_Arel_Nodes_GroupingElement :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary @@ -137,6 +141,7 @@ module Arel alias :visit_FalseClass :terminal alias :visit_Fixnum :terminal alias :visit_Float :terminal + alias :visit_Integer :terminal alias :visit_NilClass :terminal alias :visit_String :terminal alias :visit_Symbol :terminal diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index da75423523..ca8d2b0bd0 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -69,6 +69,10 @@ module Arel visit_edge o, "expr" end alias :visit_Arel_Nodes_Group :unary + alias :visit_Arel_Nodes_Cube :unary + alias :visit_Arel_Nodes_RollUp :unary + alias :visit_Arel_Nodes_GroupingSet :unary + alias :visit_Arel_Nodes_GroupingElement :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary @@ -201,6 +205,7 @@ module Arel alias :visit_TrueClass :visit_String alias :visit_FalseClass :visit_String alias :visit_Arel_Nodes_BindParam :visit_String + alias :visit_Integer :visit_String alias :visit_Fixnum :visit_String alias :visit_BigDecimal :visit_String alias :visit_Float :visit_String diff --git a/lib/arel/visitors/oracle12.rb b/lib/arel/visitors/oracle12.rb index 4a42343c9b..9b722e8c0c 100644 --- a/lib/arel/visitors/oracle12.rb +++ b/lib/arel/visitors/oracle12.rb @@ -6,10 +6,12 @@ module Arel def visit_Arel_Nodes_SelectStatement o, collector # Oracle does not allow LIMIT clause with select for update if o.limit && o.lock - o = o.dup - o.limit = [] + raise ArgumentError, <<-MSG + 'Combination of limit and lock is not supported. + because generated SQL statements + `SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.` + MSG end - super end @@ -48,6 +50,10 @@ module Arel super end + + def visit_Arel_Nodes_BindParam o, collector + collector.add_bind(o) { |i| ":a#{i}" } + end end end end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 1ef0261bdd..ef0f0ea2ef 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -1,6 +1,10 @@ module Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql + CUBE = 'CUBE' + ROLLUP = 'ROLLUP' + GROUPING_SET = 'GROUPING SET' + private def visit_Arel_Nodes_Matches o, collector @@ -43,6 +47,38 @@ module Arel def visit_Arel_Nodes_BindParam o, collector collector.add_bind(o) { |i| "$#{i}" } 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_SET + grouping_array_or_grouping_element o, collector + 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 diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 1435f3e21d..5429bf4ee8 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -329,13 +329,13 @@ module Arel end if o.orders.any? - collector << ' ' if o.partitions.any? + collector << SPACE if o.partitions.any? collector << "ORDER BY " collector = inject_join o.orders, collector, ", " end if o.framing - collector << ' ' if o.partitions.any? or o.orders.any? + collector << SPACE if o.partitions.any? or o.orders.any? collector = visit o.framing, collector end @@ -544,7 +544,7 @@ module Arel collector = visit o.left, collector end if o.right.any? - collector << " " if o.left + collector << SPACE if o.left collector = inject_join o.right, collector, ' ' end collector @@ -742,6 +742,7 @@ module Arel alias :visit_Arel_Nodes_SqlLiteral :literal alias :visit_Bignum :literal alias :visit_Fixnum :literal + alias :visit_Integer :literal def quoted o, a if a && a.able_to_type_cast? diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb index df0f01b30b..5dac2994cf 100644 --- a/test/visitors/test_oracle12.rb +++ b/test/visitors/test_oracle12.rb @@ -2,9 +2,10 @@ require 'helper' module Arel module Visitors - describe 'the oracle visitor' do + describe 'the oracle12 visitor' do before do - @visitor = Oracle12.new Table.engine.connection_pool + @visitor = Oracle12.new Table.engine.connection + @table = Table.new(:users) end def compile node @@ -29,12 +30,13 @@ module Arel end describe 'locking' do - it 'removes limit when locking' do + it 'generates ArgumentError if limit and lock are used' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) stmt.lock = Nodes::Lock.new(Arel.sql('FOR UPDATE')) - sql = compile(stmt) - sql.must_be_like "SELECT FOR UPDATE" + assert_raises ArgumentError do + sql = compile(stmt) + end end it 'defaults to FOR UPDATE when locking' do @@ -42,6 +44,16 @@ module Arel compile(node).must_be_like "FOR UPDATE" end end + + describe "Nodes::BindParam" do + it "increments each bind param" do + query = @table[:name].eq(Arel::Nodes::BindParam.new) + .and(@table[:id].eq(Arel::Nodes::BindParam.new)) + compile(query).must_be_like %{ + "users"."name" = :a1 AND "users"."id" = :a2 + } + end + end end end end diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 4b7dbe367f..f97b734b7d 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -182,6 +182,84 @@ module Arel } end end + + describe "Nodes::Cube" do + it "should know how to visit with array arguments" do + node = Arel::Nodes::Cube.new([@table[:name], @table[:bool]]) + compile(node).must_be_like %{ + CUBE( "users"."name", "users"."bool" ) + } + end + + it "should know how to visit with CubeDimension Argument" do + dimensions = Arel::Nodes::GroupingElement.new([@table[:name], @table[:bool]]) + node = Arel::Nodes::Cube.new(dimensions) + compile(node).must_be_like %{ + CUBE( "users"."name", "users"."bool" ) + } + end + + it "should know how to generate paranthesis when supplied with many Dimensions" do + dim1 = Arel::Nodes::GroupingElement.new(@table[:name]) + dim2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) + node = Arel::Nodes::Cube.new([dim1, dim2]) + compile(node).must_be_like %{ + CUBE( ( "users"."name" ), ( "users"."bool", "users"."created_at" ) ) + } + end + end + + describe "Nodes::GroupingSet" do + it "should know how to visit with array arguments" do + node = Arel::Nodes::GroupingSet.new([@table[:name], @table[:bool]]) + compile(node).must_be_like %{ + GROUPING SET( "users"."name", "users"."bool" ) + } + end + + it "should know how to visit with CubeDimension Argument" do + group = Arel::Nodes::GroupingElement.new([@table[:name], @table[:bool]]) + node = Arel::Nodes::GroupingSet.new(group) + compile(node).must_be_like %{ + GROUPING SET( "users"."name", "users"."bool" ) + } + end + + it "should know how to generate paranthesis when supplied with many Dimensions" do + group1 = Arel::Nodes::GroupingElement.new(@table[:name]) + group2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) + node = Arel::Nodes::GroupingSet.new([group1, group2]) + compile(node).must_be_like %{ + GROUPING SET( ( "users"."name" ), ( "users"."bool", "users"."created_at" ) ) + } + end + end + + describe "Nodes::RollUp" do + it "should know how to visit with array arguments" do + node = Arel::Nodes::RollUp.new([@table[:name], @table[:bool]]) + compile(node).must_be_like %{ + ROLLUP( "users"."name", "users"."bool" ) + } + end + + it "should know how to visit with CubeDimension Argument" do + group = Arel::Nodes::GroupingElement.new([@table[:name], @table[:bool]]) + node = Arel::Nodes::RollUp.new(group) + compile(node).must_be_like %{ + ROLLUP( "users"."name", "users"."bool" ) + } + end + + it "should know how to generate paranthesis when supplied with many Dimensions" do + group1 = Arel::Nodes::GroupingElement.new(@table[:name]) + group2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) + node = Arel::Nodes::RollUp.new([group1, group2]) + compile(node).must_be_like %{ + ROLLUP( ( "users"."name" ), ( "users"."bool", "users"."created_at" ) ) + } + end + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 6da86c2dee..6833d4e8f5 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -695,7 +695,7 @@ module Arel it 'supports #when with two arguments and no #then' do node = Arel::Nodes::Case.new @table[:name] - { foo: 1, bar: 0 }.reduce(node) { |node, pair| node.when *pair } + { foo: 1, bar: 0 }.reduce(node) { |_node, pair| _node.when(*pair) } compile(node).must_be_like %{ CASE "users"."name" WHEN 'foo' THEN 1 WHEN 'bar' THEN 0 END |