Skip to content

Commit 9a7229f

Browse files
committed
Make all things passed to ARel order a real Ordering object so we can uniq them.
1 parent f5e0c39 commit 9a7229f

File tree

3 files changed

+56
-20
lines changed

3 files changed

+56
-20
lines changed

lib/arel/visitors/sqlserver.rb

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,47 @@ def initialize expr
1717
end
1818
end
1919

20+
class Ordering < Arel::Nodes::Binary
21+
def hash
22+
expr.hash
23+
end
24+
def ==(other)
25+
self.class == other.class && self.expr == other.expr
26+
end
27+
def eql?(other)
28+
self == other
29+
end
30+
end
31+
2032
end
2133

2234
class SelectManager < Arel::TreeManager
2335

2436
alias :lock_without_sqlserver :lock
2537

38+
def order(*exprs)
39+
@ast.orders.concat(exprs.map{ |x|
40+
case x
41+
when Arel::Attributes::Attribute
42+
c = engine.connection
43+
tn = x.relation.table_alias || x.relation.name
44+
expr = Nodes::SqlLiteral.new "#{c.quote_table_name(tn)}.#{c.quote_column_name(x.name)}"
45+
Nodes::Ordering.new expr
46+
when String
47+
x.split(',').map do |s|
48+
expr, direction = s.split
49+
expr = Nodes::SqlLiteral.new(expr)
50+
direction = direction =~ /desc/i ? :desc : :asc
51+
Nodes::Ordering.new expr, direction
52+
end
53+
else
54+
expr = Nodes::SqlLiteral.new x.to_s
55+
Nodes::Ordering.new expr
56+
end
57+
}.flatten)
58+
self
59+
end
60+
2661
def lock(locking=true)
2762
if Arel::Visitors::SQLServer === @visitor
2863
@ast.lock = Nodes::LockWithSQLServer.new(locking)
@@ -82,7 +117,7 @@ def visit_Arel_Nodes_SelectStatementWithOutOffset(o, windowed=false)
82117
core = o.cores.first
83118
projections = core.projections
84119
groups = core.groups
85-
orders = o.orders
120+
orders = o.orders.reverse.uniq.reverse
86121
if windowed && !function_select_statement?(o)
87122
projections = projections.map { |x| projection_without_expression(x) }
88123
elsif eager_limiting_select_statement?(o)
@@ -116,7 +151,7 @@ def visit_Arel_Nodes_SelectStatementWithOffset(o)
116151
(visit(o.limit) if o.limit && !single_distinct_select_statement?(o)),
117152
(rowtable_projections(o).map{ |x| visit(x) }.join(', ')),
118153
"FROM (",
119-
"SELECT ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.uniq.join(', ')}) AS [__rn],",
154+
"SELECT ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.join(', ')}) AS [__rn],",
120155
visit_Arel_Nodes_SelectStatementWithOutOffset(o,true),
121156
") AS [__rnt]",
122157
(visit(o.offset) if o.offset),
@@ -132,14 +167,14 @@ def visit_Arel_Nodes_SelectStatementForComplexCount(o)
132167
"FROM (",
133168
"SELECT",
134169
(visit(o.limit) if o.limit),
135-
"ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.uniq.join(', ')}) AS [__rn],",
170+
"ROW_NUMBER() OVER (ORDER BY #{orders.map{ |x| visit(x) }.join(', ')}) AS [__rn],",
136171
"1 AS [count]",
137172
visit(core.source),
138173
(visit(o.lock) if o.lock),
139174
("WHERE #{core.wheres.map{ |x| visit(x) }.join ' AND ' }" unless core.wheres.empty?),
140175
("GROUP BY #{core.groups.map { |x| visit x }.join ', ' }" unless core.groups.empty?),
141176
(visit(core.having) if core.having),
142-
("ORDER BY #{o.orders.map{ |x| visit(x) }.uniq.join(', ')}" if !o.orders.empty?),
177+
("ORDER BY #{o.orders.map{ |x| visit(x) }.join(', ')}" if !o.orders.empty?),
143178
") AS [__rnt]",
144179
(visit(o.offset) if o.offset)
145180
].compact.join ' '
@@ -226,7 +261,7 @@ def rowtable_orders(o)
226261
else
227262
tn = table_name_from_select_statement(o)
228263
[Arel::Table.new(tn, @engine).primary_key.asc]
229-
end
264+
end.reverse.uniq.reverse
230265
end
231266

232267
def projection_without_expression(projection)

test/cases/method_scoping_test_sqlserver.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def test_coerced_test_merged_scoped_find
1717
poor_jamis = developers(:poor_jamis)
1818
Developer.send(:with_scope, :find => { :conditions => "salary < 100000" }) do
1919
Developer.send(:with_scope, :find => { :offset => 1, :order => 'id asc' }) do
20-
assert_sql /ORDER BY id asc/ do
20+
assert_sql /ORDER BY id asc/i do
2121
assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
2222
end
2323
end

test/cases/scratch_test_sqlserver.rb

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
require 'cases/sqlserver_helper'
2-
require 'models/tag'
32
require 'models/tagging'
43
require 'models/post'
5-
require 'models/item'
4+
require 'models/topic'
65
require 'models/comment'
6+
require 'models/reply'
77
require 'models/author'
8-
require 'models/category'
9-
require 'models/categorization'
10-
require 'models/vertex'
11-
require 'models/edge'
12-
require 'models/book'
13-
require 'models/citation'
8+
require 'models/comment'
9+
require 'models/entrant'
10+
require 'models/developer'
11+
require 'models/company'
12+
require 'models/bird'
13+
require 'models/car'
14+
require 'models/engine'
15+
require 'models/tyre'
1416

1517
class ScratchTestSqlserver < ActiveRecord::TestCase
16-
17-
self.use_transactional_fixtures = false
18-
19-
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings,
20-
:author_favorites, :vertices, :items, :books, :edges
18+
19+
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things',
20+
:authors, :categorizations, :categories, :posts
2121

2222
should 'pass' do
23-
assert_equal 1, posts(:welcome).tags.count
23+
combined = Developer.find(:all, :order => 'developers.name, developers.salary')
24+
assert_equal combined, Developer.find(:all, :order => ['developers.name', 'developers.salary'])
2425
end
2526

2627

0 commit comments

Comments
 (0)