diff options
-rw-r--r-- | lib/arel/crud.rb | 1 | ||||
-rw-r--r-- | lib/arel/delete_manager.rb | 5 | ||||
-rw-r--r-- | lib/arel/nodes/delete_statement.rb | 2 | ||||
-rw-r--r-- | lib/arel/visitors/mssql.rb | 17 | ||||
-rw-r--r-- | lib/arel/visitors/to_sql.rb | 10 | ||||
-rw-r--r-- | test/test_delete_manager.rb | 8 | ||||
-rw-r--r-- | test/visitors/test_mssql.rb | 9 |
7 files changed, 47 insertions, 5 deletions
diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 2dfe27445c..d310c7381f 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -31,6 +31,7 @@ module Arel def compile_delete dm = DeleteManager.new + dm.take @ast.limit.expr if @ast.limit dm.wheres = @ctx.wheres dm.from @ctx.froms dm diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb index af33c60740..20e988e01f 100644 --- a/lib/arel/delete_manager.rb +++ b/lib/arel/delete_manager.rb @@ -11,6 +11,11 @@ module Arel self end + def take limit + @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit + self + end + def wheres= list @ast.wheres = list end diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb index 3bac8225ec..8aaf8ca0b6 100644 --- a/lib/arel/nodes/delete_statement.rb +++ b/lib/arel/nodes/delete_statement.rb @@ -1,6 +1,8 @@ module Arel module Nodes class DeleteStatement < Arel::Nodes::Binary + attr_accessor :limit + alias :relation :left alias :relation= :left= alias :wheres :right diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 7c65ad33f2..92362a0c5f 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -66,6 +66,23 @@ module Arel end end + def visit_Arel_Nodes_DeleteStatement o, collector + collector << 'DELETE ' + if o.limit + collector << 'TOP (' + visit o.limit.expr, collector + collector << ') ' + end + collector << 'FROM ' + collector = visit o.relation, collector + if o.wheres.any? + collector << ' WHERE ' + inject_join o.wheres, collector, AND + else + collector + end + end + def determine_order_by orders, x if orders.any? orders diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7dfa86a575..ba176a552c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -74,14 +74,14 @@ module Arel end def visit_Arel_Nodes_DeleteStatement o, collector - collector << "DELETE FROM " + collector << 'DELETE FROM ' collector = visit o.relation, collector if o.wheres.any? - collector << " WHERE " - inject_join o.wheres, collector, AND - else - collector + collector << ' WHERE ' + collector = inject_join o.wheres, collector, AND end + + maybe_visit o.limit, collector end # FIXME: we should probably have a 2-pass visitor for this diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb index b16b52cb9e..ece2389d88 100644 --- a/test/test_delete_manager.rb +++ b/test/test_delete_manager.rb @@ -8,6 +8,14 @@ module Arel end end + it 'handles limit properly' do + table = Table.new(:users) + dm = Arel::DeleteManager.new + dm.take 10 + dm.from table + assert_match(/LIMIT 10/, dm.to_sql) + end + describe 'from' do it 'uses from' do table = Table.new(:users) diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index 7574aeb0a2..fe228bce4b 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -45,6 +45,15 @@ module Arel connection.verify end + it 'should use TOP for limited deletes' do + stmt = Nodes::DeleteStatement.new + stmt.relation = @table + stmt.limit = Nodes::Limit.new(10) + sql = compile(stmt) + + sql.must_be_like "DELETE TOP (10) FROM \"users\"" + end + it 'should go over query ORDER BY if .order()' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) |