@@ -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 )
0 commit comments