square-arel 2.0.9.20110222133018

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. data/.autotest +26 -0
  2. data/History.txt +105 -0
  3. data/MIT-LICENSE.txt +20 -0
  4. data/Manifest.txt +124 -0
  5. data/README.markdown +94 -0
  6. data/Rakefile +20 -0
  7. data/lib/arel.rb +39 -0
  8. data/lib/arel/attributes.rb +20 -0
  9. data/lib/arel/attributes/attribute.rb +18 -0
  10. data/lib/arel/compatibility/wheres.rb +33 -0
  11. data/lib/arel/crud.rb +37 -0
  12. data/lib/arel/delete_manager.rb +18 -0
  13. data/lib/arel/deprecated.rb +4 -0
  14. data/lib/arel/expression.rb +4 -0
  15. data/lib/arel/expressions.rb +23 -0
  16. data/lib/arel/insert_manager.rb +34 -0
  17. data/lib/arel/nodes.rb +53 -0
  18. data/lib/arel/nodes/and.rb +6 -0
  19. data/lib/arel/nodes/as.rb +6 -0
  20. data/lib/arel/nodes/assignment.rb +6 -0
  21. data/lib/arel/nodes/avg.rb +6 -0
  22. data/lib/arel/nodes/between.rb +6 -0
  23. data/lib/arel/nodes/binary.rb +12 -0
  24. data/lib/arel/nodes/count.rb +13 -0
  25. data/lib/arel/nodes/delete_statement.rb +19 -0
  26. data/lib/arel/nodes/does_not_match.rb +6 -0
  27. data/lib/arel/nodes/equality.rb +9 -0
  28. data/lib/arel/nodes/except.rb +7 -0
  29. data/lib/arel/nodes/exists.rb +7 -0
  30. data/lib/arel/nodes/function.rb +18 -0
  31. data/lib/arel/nodes/greater_than.rb +6 -0
  32. data/lib/arel/nodes/greater_than_or_equal.rb +6 -0
  33. data/lib/arel/nodes/group.rb +6 -0
  34. data/lib/arel/nodes/grouping.rb +6 -0
  35. data/lib/arel/nodes/having.rb +6 -0
  36. data/lib/arel/nodes/in.rb +6 -0
  37. data/lib/arel/nodes/inner_join.rb +6 -0
  38. data/lib/arel/nodes/insert_statement.rb +19 -0
  39. data/lib/arel/nodes/intersect.rb +7 -0
  40. data/lib/arel/nodes/join.rb +13 -0
  41. data/lib/arel/nodes/less_than.rb +6 -0
  42. data/lib/arel/nodes/less_than_or_equal.rb +6 -0
  43. data/lib/arel/nodes/limit.rb +7 -0
  44. data/lib/arel/nodes/lock.rb +6 -0
  45. data/lib/arel/nodes/matches.rb +6 -0
  46. data/lib/arel/nodes/max.rb +6 -0
  47. data/lib/arel/nodes/min.rb +6 -0
  48. data/lib/arel/nodes/node.rb +44 -0
  49. data/lib/arel/nodes/not.rb +6 -0
  50. data/lib/arel/nodes/not_equal.rb +6 -0
  51. data/lib/arel/nodes/not_in.rb +6 -0
  52. data/lib/arel/nodes/offset.rb +7 -0
  53. data/lib/arel/nodes/on.rb +6 -0
  54. data/lib/arel/nodes/or.rb +6 -0
  55. data/lib/arel/nodes/ordering.rb +20 -0
  56. data/lib/arel/nodes/outer_join.rb +6 -0
  57. data/lib/arel/nodes/select_core.rb +26 -0
  58. data/lib/arel/nodes/select_statement.rb +22 -0
  59. data/lib/arel/nodes/sql_literal.rb +8 -0
  60. data/lib/arel/nodes/string_join.rb +11 -0
  61. data/lib/arel/nodes/sum.rb +6 -0
  62. data/lib/arel/nodes/table_alias.rb +13 -0
  63. data/lib/arel/nodes/top.rb +6 -0
  64. data/lib/arel/nodes/unary.rb +11 -0
  65. data/lib/arel/nodes/union.rb +7 -0
  66. data/lib/arel/nodes/union_all.rb +7 -0
  67. data/lib/arel/nodes/unqualified_column.rb +16 -0
  68. data/lib/arel/nodes/update_statement.rb +21 -0
  69. data/lib/arel/nodes/values.rb +14 -0
  70. data/lib/arel/predications.rb +183 -0
  71. data/lib/arel/relation.rb +6 -0
  72. data/lib/arel/select_manager.rb +237 -0
  73. data/lib/arel/sql/engine.rb +10 -0
  74. data/lib/arel/sql_literal.rb +4 -0
  75. data/lib/arel/table.rb +134 -0
  76. data/lib/arel/tree_manager.rb +36 -0
  77. data/lib/arel/update_manager.rb +49 -0
  78. data/lib/arel/visitors.rb +38 -0
  79. data/lib/arel/visitors/depth_first.rb +154 -0
  80. data/lib/arel/visitors/dot.rb +230 -0
  81. data/lib/arel/visitors/join_sql.rb +40 -0
  82. data/lib/arel/visitors/mssql.rb +16 -0
  83. data/lib/arel/visitors/mysql.rb +34 -0
  84. data/lib/arel/visitors/oracle.rb +116 -0
  85. data/lib/arel/visitors/order_clauses.rb +11 -0
  86. data/lib/arel/visitors/postgresql.rb +58 -0
  87. data/lib/arel/visitors/sqlite.rb +11 -0
  88. data/lib/arel/visitors/to_sql.rb +331 -0
  89. data/lib/arel/visitors/visitor.rb +27 -0
  90. data/lib/arel/visitors/where_sql.rb +9 -0
  91. data/square-arel.gemspec +36 -0
  92. data/test/attributes/test_attribute.rb +664 -0
  93. data/test/helper.rb +13 -0
  94. data/test/nodes/test_as.rb +16 -0
  95. data/test/nodes/test_count.rb +18 -0
  96. data/test/nodes/test_delete_statement.rb +14 -0
  97. data/test/nodes/test_equality.rb +74 -0
  98. data/test/nodes/test_insert_statement.rb +18 -0
  99. data/test/nodes/test_node.rb +33 -0
  100. data/test/nodes/test_not.rb +20 -0
  101. data/test/nodes/test_or.rb +22 -0
  102. data/test/nodes/test_select_core.rb +22 -0
  103. data/test/nodes/test_select_statement.rb +13 -0
  104. data/test/nodes/test_sql_literal.rb +52 -0
  105. data/test/nodes/test_sum.rb +12 -0
  106. data/test/nodes/test_update_statement.rb +18 -0
  107. data/test/support/fake_record.rb +91 -0
  108. data/test/test_activerecord_compat.rb +18 -0
  109. data/test/test_attributes.rb +46 -0
  110. data/test/test_crud.rb +69 -0
  111. data/test/test_delete_manager.rb +42 -0
  112. data/test/test_insert_manager.rb +125 -0
  113. data/test/test_select_manager.rb +659 -0
  114. data/test/test_table.rb +193 -0
  115. data/test/test_update_manager.rb +86 -0
  116. data/test/visitors/test_depth_first.rb +212 -0
  117. data/test/visitors/test_dot.rb +29 -0
  118. data/test/visitors/test_join_sql.rb +35 -0
  119. data/test/visitors/test_mssql.rb +18 -0
  120. data/test/visitors/test_mysql.rb +45 -0
  121. data/test/visitors/test_oracle.rb +147 -0
  122. data/test/visitors/test_postgres.rb +36 -0
  123. data/test/visitors/test_sqlite.rb +18 -0
  124. data/test/visitors/test_to_sql.rb +255 -0
  125. metadata +261 -0
@@ -0,0 +1,16 @@
1
+ module Arel
2
+ module Visitors
3
+ class MSSQL < Arel::Visitors::ToSql
4
+ private
5
+
6
+ def visit_Arel_Nodes_Limit o
7
+ ""
8
+ end
9
+
10
+ def visit_Arel_Nodes_Top o
11
+ "TOP #{visit o.expr}"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ module Arel
2
+ module Visitors
3
+ class MySQL < Arel::Visitors::ToSql
4
+ private
5
+ def visit_Arel_Nodes_Lock o
6
+ visit o.expr
7
+ end
8
+
9
+ ###
10
+ # :'(
11
+ # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214
12
+ def visit_Arel_Nodes_SelectStatement o
13
+ o.limit = Arel::Nodes::Limit.new(18446744073709551615) if o.offset && !o.limit
14
+ super
15
+ end
16
+
17
+ def visit_Arel_Nodes_SelectCore o
18
+ o.froms ||= Arel.sql('DUAL')
19
+ super
20
+ end
21
+
22
+ def visit_Arel_Nodes_UpdateStatement o
23
+ [
24
+ "UPDATE #{visit o.relation}",
25
+ ("SET #{o.values.map { |value| visit value }.join ', '}" unless o.values.empty?),
26
+ ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?),
27
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
28
+ (visit(o.limit) if o.limit),
29
+ ].compact.join ' '
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,116 @@
1
+ module Arel
2
+ module Visitors
3
+ class Oracle < Arel::Visitors::ToSql
4
+ private
5
+
6
+ def visit_Arel_Nodes_SelectStatement o
7
+ o = order_hacks(o)
8
+
9
+ # if need to select first records without ORDER BY and GROUP BY and without DISTINCT
10
+ # then can use simple ROWNUM in WHERE clause
11
+ if o.limit && o.orders.empty? && !o.offset && o.cores.first.projections.first !~ /^DISTINCT /
12
+ o.cores.last.wheres.push Nodes::LessThanOrEqual.new(
13
+ Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr
14
+ )
15
+ return super
16
+ end
17
+
18
+ if o.limit && o.offset
19
+ o = o.dup
20
+ limit = o.limit.expr.to_i
21
+ offset = o.offset
22
+ o.offset = nil
23
+ sql = super(o)
24
+ return <<-eosql
25
+ SELECT * FROM (
26
+ SELECT raw_sql_.*, rownum raw_rnum_
27
+ FROM (#{sql}) raw_sql_
28
+ WHERE rownum <= #{offset.value.to_i + limit}
29
+ )
30
+ WHERE #{visit offset}
31
+ eosql
32
+ end
33
+
34
+ if o.limit
35
+ o = o.dup
36
+ limit = o.limit.expr
37
+ return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{visit limit}"
38
+ end
39
+
40
+ if o.offset
41
+ o = o.dup
42
+ offset = o.offset
43
+ o.offset = nil
44
+ sql = super(o)
45
+ return <<-eosql
46
+ SELECT * FROM (
47
+ SELECT raw_sql_.*, rownum raw_rnum_
48
+ FROM (#{sql}) raw_sql_
49
+ )
50
+ WHERE #{visit offset}
51
+ eosql
52
+ end
53
+
54
+ super
55
+ end
56
+
57
+ def visit_Arel_Nodes_Limit o
58
+ end
59
+
60
+ def visit_Arel_Nodes_Offset o
61
+ "raw_rnum_ > #{visit o.value}"
62
+ end
63
+
64
+ def visit_Arel_Nodes_Except o
65
+ "( #{visit o.left} MINUS #{visit o.right} )"
66
+ end
67
+
68
+ ###
69
+ # Hacks for the order clauses specific to Oracle
70
+ def order_hacks o
71
+ return o if o.orders.empty?
72
+ return o unless o.cores.any? do |core|
73
+ core.projections.any? do |projection|
74
+ /DISTINCT.*FIRST_VALUE/ === projection
75
+ end
76
+ end
77
+ # Previous version with join and split broke ORDER BY clause
78
+ # if it contained functions with several arguments (separated by ',').
79
+ #
80
+ # orders = o.orders.map { |x| visit x }.join(', ').split(',')
81
+ orders = o.orders.map do |x|
82
+ string = visit x
83
+ if string.include?(',')
84
+ split_order_string(string)
85
+ else
86
+ string
87
+ end
88
+ end.flatten
89
+ o.orders = []
90
+ orders.each_with_index do |order, i|
91
+ o.orders <<
92
+ Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i === order}")
93
+ end
94
+ o
95
+ end
96
+
97
+ # Split string by commas but count opening and closing brackets
98
+ # and ignore commas inside brackets.
99
+ def split_order_string(string)
100
+ array = []
101
+ i = 0
102
+ string.split(',').each do |part|
103
+ if array[i]
104
+ array[i] << ',' << part
105
+ else
106
+ # to ensure that array[i] will be String and not Arel::Nodes::SqlLiteral
107
+ array[i] = '' << part
108
+ end
109
+ i += 1 if array[i].count('(') == array[i].count(')')
110
+ end
111
+ array
112
+ end
113
+
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,11 @@
1
+ module Arel
2
+ module Visitors
3
+ class OrderClauses < Arel::Visitors::ToSql
4
+ private
5
+
6
+ def visit_Arel_Nodes_SelectStatement o
7
+ o.orders.map { |x| visit x }
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,58 @@
1
+ module Arel
2
+ module Visitors
3
+ class PostgreSQL < Arel::Visitors::ToSql
4
+ private
5
+ def visit_Arel_Nodes_Lock o
6
+ visit o.expr
7
+ end
8
+
9
+ def visit_Arel_Nodes_SelectStatement o
10
+ if !o.orders.empty? && using_distinct_on?(o)
11
+ subquery = o.dup
12
+ subquery.orders = []
13
+ subquery.limit = nil
14
+ subquery.offset = nil
15
+
16
+ sql = super(subquery)
17
+ [
18
+ "SELECT * FROM (#{sql}) AS id_list",
19
+ "ORDER BY #{aliased_orders(o.orders).join(', ')}",
20
+ (visit(o.limit) if o.limit),
21
+ (visit(o.offset) if o.offset),
22
+ ].compact.join ' '
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ def visit_Arel_Nodes_Matches o
29
+ "#{visit o.left} ILIKE #{visit o.right}"
30
+ end
31
+
32
+ def visit_Arel_Nodes_DoesNotMatch o
33
+ "#{visit o.left} NOT ILIKE #{visit o.right}"
34
+ end
35
+
36
+ def using_distinct_on?(o)
37
+ o.cores.any? do |core|
38
+ core.projections.any? do |projection|
39
+ /DISTINCT ON/ === projection
40
+ end
41
+ end
42
+ end
43
+
44
+ def aliased_orders orders
45
+ #orders = o.orders.map { |x| visit x }.join(', ').split(',')
46
+ list = []
47
+ orders.each_with_index do |o,i|
48
+ list <<
49
+ [
50
+ "id_list.alias_#{i}",
51
+ (o.index(/desc/i) && 'DESC')
52
+ ].compact.join(' ')
53
+ end
54
+ list
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ module Arel
2
+ module Visitors
3
+ class SQLite < Arel::Visitors::ToSql
4
+ private
5
+ def visit_Arel_Nodes_SelectStatement o
6
+ o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,331 @@
1
+ require 'bigdecimal'
2
+ require 'date'
3
+
4
+ module Arel
5
+ module Visitors
6
+ class ToSql < Arel::Visitors::Visitor
7
+ def initialize engine
8
+ @engine = engine
9
+ @connection = nil
10
+ @quoted_tables = {}
11
+ @quoted_columns = {}
12
+ end
13
+
14
+ def accept object
15
+ Thread.current[:arel_visitors_to_sql_last_column] = nil
16
+ @engine.connection_pool.with_connection do |conn|
17
+ @connection = conn
18
+ super
19
+ end
20
+ end
21
+
22
+ private
23
+ def visit_Arel_Nodes_DeleteStatement o
24
+ [
25
+ "DELETE FROM #{visit o.relation}",
26
+ ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?)
27
+ ].compact.join ' '
28
+ end
29
+
30
+ def visit_Arel_Nodes_UpdateStatement o
31
+ if o.orders.empty? && o.limit.nil?
32
+ wheres = o.wheres
33
+ else
34
+ stmt = Nodes::SelectStatement.new
35
+ core = stmt.cores.first
36
+ core.froms = o.relation
37
+ core.projections = [o.relation.primary_key]
38
+ stmt.limit = o.limit
39
+ stmt.orders = o.orders
40
+
41
+ wheres = [Nodes::In.new(o.relation.primary_key, [stmt])]
42
+ end
43
+
44
+ [
45
+ "UPDATE #{visit o.relation}",
46
+ ("SET #{o.values.map { |value| visit value }.join ', '}" unless o.values.empty?),
47
+ ("WHERE #{wheres.map { |x| visit x }.join ' AND '}" unless wheres.empty?)
48
+ ].compact.join ' '
49
+ end
50
+
51
+ def visit_Arel_Nodes_InsertStatement o
52
+ [
53
+ "INSERT INTO #{visit o.relation}",
54
+
55
+ ("(#{o.columns.map { |x|
56
+ quote_column_name x.name
57
+ }.join ', '})" unless o.columns.empty?),
58
+
59
+ (visit o.values if o.values),
60
+ ].compact.join ' '
61
+ end
62
+
63
+ def visit_Arel_Nodes_Exists o
64
+ "EXISTS (#{visit o.select_stmt})#{
65
+ o.alias ? " AS #{visit o.alias}" : ''}"
66
+ end
67
+
68
+ def visit_Arel_Nodes_Values o
69
+ "VALUES (#{o.expressions.zip(o.columns).map { |value, column|
70
+ quote(value, column && column.column)
71
+ }.join ', '})"
72
+ end
73
+
74
+ def visit_Arel_Nodes_SelectStatement o
75
+ [
76
+ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
77
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
78
+ (visit(o.limit) if o.limit),
79
+ (visit(o.offset) if o.offset),
80
+ (visit(o.lock) if o.lock),
81
+ ].compact.join ' '
82
+ end
83
+
84
+ def visit_Arel_Nodes_SelectCore o
85
+ [
86
+ "SELECT",
87
+ (visit(o.top) if o.top),
88
+ "#{o.projections.map { |x| visit x }.join ', '}",
89
+ ("FROM #{visit o.froms}" if o.froms),
90
+ ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.empty?),
91
+ ("GROUP BY #{o.groups.map { |x| visit x }.join ', ' }" unless o.groups.empty?),
92
+ (visit(o.having) if o.having),
93
+ ].compact.join ' '
94
+ end
95
+
96
+ def visit_Arel_Nodes_Having o
97
+ "HAVING #{visit o.expr}"
98
+ end
99
+
100
+ def visit_Arel_Nodes_Offset o
101
+ "OFFSET #{visit o.expr}"
102
+ end
103
+
104
+ def visit_Arel_Nodes_Limit o
105
+ "LIMIT #{visit o.expr}"
106
+ end
107
+
108
+ # FIXME: this does nothing on most databases, but does on MSSQL
109
+ def visit_Arel_Nodes_Top o
110
+ ""
111
+ end
112
+
113
+ # FIXME: this does nothing on SQLLite3, but should do things on other
114
+ # databases.
115
+ def visit_Arel_Nodes_Lock o
116
+ end
117
+
118
+ def visit_Arel_Nodes_Grouping o
119
+ "(#{visit o.expr})"
120
+ end
121
+
122
+ def visit_Arel_Nodes_Ordering o
123
+ "#{visit o.expr} #{o.descending? ? 'DESC' : 'ASC'}"
124
+ end
125
+
126
+ def visit_Arel_Nodes_Group o
127
+ visit o.expr
128
+ end
129
+
130
+ def visit_Arel_Nodes_Count o
131
+ "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
132
+ visit x
133
+ }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
134
+ end
135
+
136
+ def visit_Arel_Nodes_Sum o
137
+ "SUM(#{o.expressions.map { |x|
138
+ visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
139
+ end
140
+
141
+ def visit_Arel_Nodes_Max o
142
+ "MAX(#{o.expressions.map { |x|
143
+ visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
144
+ end
145
+
146
+ def visit_Arel_Nodes_Min o
147
+ "MIN(#{o.expressions.map { |x|
148
+ visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
149
+ end
150
+
151
+ def visit_Arel_Nodes_Avg o
152
+ "AVG(#{o.expressions.map { |x|
153
+ visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
154
+ end
155
+
156
+ def visit_Arel_Nodes_TableAlias o
157
+ "#{visit o.relation} #{quote_table_name o.name}"
158
+ end
159
+
160
+ def visit_Arel_Nodes_Between o
161
+ "#{visit o.left} BETWEEN #{visit o.right}"
162
+ end
163
+
164
+ def visit_Arel_Nodes_GreaterThanOrEqual o
165
+ "#{visit o.left} >= #{visit o.right}"
166
+ end
167
+
168
+ def visit_Arel_Nodes_GreaterThan o
169
+ "#{visit o.left} > #{visit o.right}"
170
+ end
171
+
172
+ def visit_Arel_Nodes_LessThanOrEqual o
173
+ "#{visit o.left} <= #{visit o.right}"
174
+ end
175
+
176
+ def visit_Arel_Nodes_LessThan o
177
+ "#{visit o.left} < #{visit o.right}"
178
+ end
179
+
180
+ def visit_Arel_Nodes_Matches o
181
+ "#{visit o.left} LIKE #{visit o.right}"
182
+ end
183
+
184
+ def visit_Arel_Nodes_DoesNotMatch o
185
+ "#{visit o.left} NOT LIKE #{visit o.right}"
186
+ end
187
+
188
+ def visit_Arel_Nodes_StringJoin o
189
+ "#{visit o.left} #{visit o.right}"
190
+ end
191
+
192
+ def visit_Arel_Nodes_OuterJoin o
193
+ "#{visit o.left} LEFT OUTER JOIN #{visit o.right} #{visit o.constraint}"
194
+ end
195
+
196
+ def visit_Arel_Nodes_InnerJoin o
197
+ "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}"
198
+ end
199
+
200
+ def visit_Arel_Nodes_On o
201
+ "ON #{visit o.expr}"
202
+ end
203
+
204
+ def visit_Arel_Nodes_Not o
205
+ "NOT (#{visit o.expr})"
206
+ end
207
+
208
+ def visit_Arel_Nodes_Union o
209
+ "( #{visit o.left} UNION #{visit o.right} )"
210
+ end
211
+
212
+ def visit_Arel_Nodes_UnionAll o
213
+ "( #{visit o.left} UNION ALL #{visit o.right} )"
214
+ end
215
+
216
+ def visit_Arel_Nodes_Intersect o
217
+ "( #{visit o.left} INTERSECT #{visit o.right} )"
218
+ end
219
+
220
+ def visit_Arel_Nodes_Except o
221
+ "( #{visit o.left} EXCEPT #{visit o.right} )"
222
+ end
223
+
224
+ def visit_Arel_Table o
225
+ if o.table_alias
226
+ "#{quote_table_name o.name} #{quote_table_name o.table_alias}"
227
+ else
228
+ quote_table_name o.name
229
+ end
230
+ end
231
+
232
+ def visit_Arel_Nodes_In o
233
+ "#{visit o.left} IN (#{visit o.right})"
234
+ end
235
+
236
+ def visit_Arel_Nodes_NotIn o
237
+ "#{visit o.left} NOT IN (#{visit o.right})"
238
+ end
239
+
240
+ def visit_Arel_Nodes_And o
241
+ "#{visit o.left} AND #{visit o.right}"
242
+ end
243
+
244
+ def visit_Arel_Nodes_Or o
245
+ "#{visit o.left} OR #{visit o.right}"
246
+ end
247
+
248
+ def visit_Arel_Nodes_Assignment o
249
+ right = quote(o.right, o.left.column)
250
+ "#{visit o.left} = #{right}"
251
+ end
252
+
253
+ def visit_Arel_Nodes_Equality o
254
+ right = o.right
255
+
256
+ if right.nil?
257
+ "#{visit o.left} IS NULL"
258
+ else
259
+ "#{visit o.left} = #{visit right}"
260
+ end
261
+ end
262
+
263
+ def visit_Arel_Nodes_NotEqual o
264
+ right = o.right
265
+
266
+ if right.nil?
267
+ "#{visit o.left} IS NOT NULL"
268
+ else
269
+ "#{visit o.left} != #{visit right}"
270
+ end
271
+ end
272
+
273
+ def visit_Arel_Nodes_As o
274
+ "#{visit o.left} AS #{visit o.right}"
275
+ end
276
+
277
+ def visit_Arel_Nodes_UnqualifiedColumn o
278
+ "#{quote_column_name o.name}"
279
+ end
280
+
281
+ def visit_Arel_Attributes_Attribute o
282
+ Thread.current[:arel_visitors_to_sql_last_column] = o.column
283
+ join_name = o.relation.table_alias || o.relation.name
284
+ "#{quote_table_name join_name}.#{quote_column_name o.name}"
285
+ end
286
+ alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
287
+ alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
288
+ alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute
289
+ alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute
290
+ alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
291
+ alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
292
+
293
+ def visit_Fixnum o; o end
294
+ alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum
295
+ alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated
296
+ alias :visit_Bignum :visit_Fixnum
297
+
298
+ def visit_String o; quote(o, Thread.current[:arel_visitors_to_sql_last_column]) end
299
+
300
+ alias :visit_ActiveSupport_Multibyte_Chars :visit_String
301
+ alias :visit_BigDecimal :visit_String
302
+ alias :visit_Date :visit_String
303
+ alias :visit_DateTime :visit_String
304
+ alias :visit_FalseClass :visit_String
305
+ alias :visit_Float :visit_String
306
+ alias :visit_Hash :visit_String
307
+ alias :visit_Symbol :visit_String
308
+ alias :visit_Time :visit_String
309
+ alias :visit_TrueClass :visit_String
310
+ alias :visit_NilClass :visit_String
311
+ alias :visit_ActiveSupport_StringInquirer :visit_String
312
+ alias :visit_Class :visit_String
313
+
314
+ def visit_Array o
315
+ o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ')
316
+ end
317
+
318
+ def quote value, column = nil
319
+ @connection.quote value, column
320
+ end
321
+
322
+ def quote_table_name name
323
+ @quoted_tables[name] ||= @connection.quote_table_name(name)
324
+ end
325
+
326
+ def quote_column_name name
327
+ @quoted_columns[name] ||= @connection.quote_column_name(name)
328
+ end
329
+ end
330
+ end
331
+ end