arel 1.0.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (247) hide show
  1. data/MIT-LICENSE.txt +20 -0
  2. data/Manifest.txt +105 -0
  3. data/README.markdown +12 -32
  4. data/Rakefile +17 -0
  5. data/arel.gemspec +39 -0
  6. data/lib/arel.rb +30 -9
  7. data/lib/arel/attributes.rb +20 -0
  8. data/lib/arel/attributes/attribute.rb +190 -0
  9. data/lib/arel/compatibility/wheres.rb +33 -0
  10. data/lib/arel/crud.rb +37 -0
  11. data/lib/arel/delete_manager.rb +22 -0
  12. data/lib/arel/deprecated.rb +4 -0
  13. data/lib/arel/expression.rb +4 -0
  14. data/lib/arel/expressions.rb +23 -0
  15. data/lib/arel/insert_manager.rb +34 -0
  16. data/lib/arel/nodes.rb +44 -0
  17. data/lib/arel/nodes/and.rb +6 -0
  18. data/lib/arel/nodes/assignment.rb +6 -0
  19. data/lib/arel/nodes/avg.rb +6 -0
  20. data/lib/arel/nodes/between.rb +6 -0
  21. data/lib/arel/nodes/binary.rb +12 -0
  22. data/lib/arel/nodes/count.rb +13 -0
  23. data/lib/arel/nodes/delete_statement.rb +17 -0
  24. data/lib/arel/nodes/does_not_match.rb +6 -0
  25. data/lib/arel/nodes/equality.rb +9 -0
  26. data/lib/arel/nodes/exists.rb +11 -0
  27. data/lib/arel/nodes/function.rb +18 -0
  28. data/lib/arel/nodes/greater_than.rb +6 -0
  29. data/lib/arel/nodes/greater_than_or_equal.rb +6 -0
  30. data/lib/arel/nodes/group.rb +11 -0
  31. data/lib/arel/nodes/grouping.rb +11 -0
  32. data/lib/arel/nodes/having.rb +11 -0
  33. data/lib/arel/nodes/in.rb +6 -0
  34. data/lib/arel/nodes/inner_join.rb +6 -0
  35. data/lib/arel/nodes/insert_statement.rb +19 -0
  36. data/lib/arel/nodes/join.rb +13 -0
  37. data/lib/arel/nodes/less_than.rb +6 -0
  38. data/lib/arel/nodes/less_than_or_equal.rb +6 -0
  39. data/lib/arel/nodes/lock.rb +6 -0
  40. data/lib/arel/nodes/matches.rb +6 -0
  41. data/lib/arel/nodes/max.rb +6 -0
  42. data/lib/arel/nodes/min.rb +6 -0
  43. data/lib/arel/nodes/node.rb +30 -0
  44. data/lib/arel/nodes/not_equal.rb +6 -0
  45. data/lib/arel/nodes/not_in.rb +6 -0
  46. data/lib/arel/nodes/offset.rb +11 -0
  47. data/lib/arel/nodes/on.rb +11 -0
  48. data/lib/arel/nodes/or.rb +6 -0
  49. data/lib/arel/nodes/ordering.rb +19 -0
  50. data/lib/arel/nodes/outer_join.rb +6 -0
  51. data/lib/arel/nodes/select_core.rb +25 -0
  52. data/lib/arel/nodes/select_statement.rb +22 -0
  53. data/lib/arel/nodes/sql_literal.rb +7 -0
  54. data/lib/arel/nodes/string_join.rb +11 -0
  55. data/lib/arel/nodes/sum.rb +6 -0
  56. data/lib/arel/nodes/table_alias.rb +21 -0
  57. data/lib/arel/nodes/unqualified_column.rb +19 -0
  58. data/lib/arel/nodes/update_statement.rb +21 -0
  59. data/lib/arel/nodes/values.rb +12 -0
  60. data/lib/arel/relation.rb +6 -0
  61. data/lib/arel/select_manager.rb +203 -0
  62. data/lib/arel/sql/engine.rb +10 -0
  63. data/lib/arel/sql_literal.rb +1 -10
  64. data/lib/arel/table.rb +126 -0
  65. data/lib/arel/tree_manager.rb +26 -0
  66. data/lib/arel/update_manager.rb +48 -0
  67. data/lib/arel/visitors.rb +30 -0
  68. data/lib/arel/visitors/dot.rb +233 -0
  69. data/lib/arel/visitors/join_sql.rb +38 -0
  70. data/lib/arel/visitors/mysql.rb +16 -0
  71. data/lib/arel/visitors/oracle.rb +69 -0
  72. data/lib/arel/visitors/order_clauses.rb +9 -0
  73. data/lib/arel/visitors/postgresql.rb +54 -0
  74. data/lib/arel/visitors/to_sql.rb +301 -0
  75. data/lib/arel/visitors/where_sql.rb +9 -0
  76. data/spec/activerecord_compat_spec.rb +18 -0
  77. data/spec/attributes/attribute_spec.rb +648 -0
  78. data/spec/attributes_spec.rb +33 -6
  79. data/spec/crud_spec.rb +69 -0
  80. data/spec/delete_manager_spec.rb +53 -0
  81. data/spec/insert_manager_spec.rb +141 -0
  82. data/spec/nodes/count_spec.rb +18 -0
  83. data/spec/nodes/delete_statement_spec.rb +15 -0
  84. data/spec/nodes/equality_spec.rb +72 -0
  85. data/spec/nodes/insert_statement_spec.rb +18 -0
  86. data/spec/nodes/or_spec.rb +20 -0
  87. data/spec/nodes/select_core_spec.rb +21 -0
  88. data/spec/nodes/select_statement_spec.rb +14 -0
  89. data/spec/nodes/sql_literal_spec.rb +26 -0
  90. data/spec/nodes/sum_spec.rb +12 -0
  91. data/spec/nodes/update_statement_spec.rb +18 -0
  92. data/spec/select_manager_spec.rb +581 -0
  93. data/spec/spec.opts +3 -0
  94. data/spec/spec_helper.rb +6 -21
  95. data/spec/support/fake_record.rb +89 -0
  96. data/spec/support/shared/tree_manager_shared.rb +9 -0
  97. data/spec/table_spec.rb +176 -0
  98. data/spec/update_manager_spec.rb +89 -0
  99. data/spec/visitors/join_sql_spec.rb +35 -0
  100. data/spec/visitors/oracle_spec.rb +111 -0
  101. data/spec/visitors/to_sql_spec.rb +134 -0
  102. metadata +160 -260
  103. data/lib/arel/algebra.rb +0 -10
  104. data/lib/arel/algebra/attributes.rb +0 -7
  105. data/lib/arel/algebra/attributes/attribute.rb +0 -304
  106. data/lib/arel/algebra/attributes/boolean.rb +0 -21
  107. data/lib/arel/algebra/attributes/decimal.rb +0 -9
  108. data/lib/arel/algebra/attributes/float.rb +0 -9
  109. data/lib/arel/algebra/attributes/integer.rb +0 -10
  110. data/lib/arel/algebra/attributes/string.rb +0 -10
  111. data/lib/arel/algebra/attributes/time.rb +0 -6
  112. data/lib/arel/algebra/core_extensions.rb +0 -3
  113. data/lib/arel/algebra/core_extensions/hash.rb +0 -7
  114. data/lib/arel/algebra/core_extensions/object.rb +0 -13
  115. data/lib/arel/algebra/core_extensions/symbol.rb +0 -9
  116. data/lib/arel/algebra/expression.rb +0 -56
  117. data/lib/arel/algebra/header.rb +0 -66
  118. data/lib/arel/algebra/ordering.rb +0 -31
  119. data/lib/arel/algebra/predicates.rb +0 -306
  120. data/lib/arel/algebra/relations.rb +0 -16
  121. data/lib/arel/algebra/relations/operations/from.rb +0 -14
  122. data/lib/arel/algebra/relations/operations/group.rb +0 -14
  123. data/lib/arel/algebra/relations/operations/having.rb +0 -14
  124. data/lib/arel/algebra/relations/operations/join.rb +0 -103
  125. data/lib/arel/algebra/relations/operations/lock.rb +0 -10
  126. data/lib/arel/algebra/relations/operations/order.rb +0 -23
  127. data/lib/arel/algebra/relations/operations/project.rb +0 -20
  128. data/lib/arel/algebra/relations/operations/skip.rb +0 -14
  129. data/lib/arel/algebra/relations/operations/take.rb +0 -18
  130. data/lib/arel/algebra/relations/operations/where.rb +0 -24
  131. data/lib/arel/algebra/relations/relation.rb +0 -205
  132. data/lib/arel/algebra/relations/row.rb +0 -29
  133. data/lib/arel/algebra/relations/utilities/compound.rb +0 -55
  134. data/lib/arel/algebra/relations/utilities/externalization.rb +0 -26
  135. data/lib/arel/algebra/relations/utilities/nil.rb +0 -7
  136. data/lib/arel/algebra/relations/writes.rb +0 -47
  137. data/lib/arel/algebra/value.rb +0 -53
  138. data/lib/arel/engines.rb +0 -2
  139. data/lib/arel/engines/memory.rb +0 -2
  140. data/lib/arel/engines/memory/engine.rb +0 -10
  141. data/lib/arel/engines/memory/relations.rb +0 -2
  142. data/lib/arel/engines/memory/relations/array.rb +0 -37
  143. data/lib/arel/engines/memory/relations/operations.rb +0 -9
  144. data/lib/arel/engines/sql.rb +0 -6
  145. data/lib/arel/engines/sql/attributes.rb +0 -45
  146. data/lib/arel/engines/sql/christener.rb +0 -20
  147. data/lib/arel/engines/sql/compilers/ibm_db_compiler.rb +0 -48
  148. data/lib/arel/engines/sql/compilers/mysql_compiler.rb +0 -11
  149. data/lib/arel/engines/sql/compilers/oracle_compiler.rb +0 -106
  150. data/lib/arel/engines/sql/compilers/postgresql_compiler.rb +0 -50
  151. data/lib/arel/engines/sql/compilers/sqlite_compiler.rb +0 -9
  152. data/lib/arel/engines/sql/core_extensions.rb +0 -4
  153. data/lib/arel/engines/sql/core_extensions/array.rb +0 -24
  154. data/lib/arel/engines/sql/core_extensions/nil_class.rb +0 -15
  155. data/lib/arel/engines/sql/core_extensions/object.rb +0 -19
  156. data/lib/arel/engines/sql/core_extensions/range.rb +0 -19
  157. data/lib/arel/engines/sql/engine.rb +0 -47
  158. data/lib/arel/engines/sql/formatters.rb +0 -138
  159. data/lib/arel/engines/sql/relations.rb +0 -3
  160. data/lib/arel/engines/sql/relations/compiler.rb +0 -153
  161. data/lib/arel/engines/sql/relations/table.rb +0 -100
  162. data/lib/arel/engines/sql/relations/utilities/nil.rb +0 -6
  163. data/lib/arel/recursion/base_case.rb +0 -13
  164. data/lib/arel/session.rb +0 -35
  165. data/lib/arel/version.rb +0 -3
  166. data/spec/algebra/unit/predicates/binary_spec.rb +0 -35
  167. data/spec/algebra/unit/predicates/equality_spec.rb +0 -29
  168. data/spec/algebra/unit/predicates/in_spec.rb +0 -12
  169. data/spec/algebra/unit/predicates/inequality_spec.rb +0 -32
  170. data/spec/algebra/unit/predicates/predicate_spec.rb +0 -22
  171. data/spec/algebra/unit/primitives/attribute_spec.rb +0 -175
  172. data/spec/algebra/unit/primitives/expression_spec.rb +0 -39
  173. data/spec/algebra/unit/primitives/value_spec.rb +0 -15
  174. data/spec/algebra/unit/relations/alias_spec.rb +0 -16
  175. data/spec/algebra/unit/relations/delete_spec.rb +0 -9
  176. data/spec/algebra/unit/relations/group_spec.rb +0 -10
  177. data/spec/algebra/unit/relations/insert_spec.rb +0 -9
  178. data/spec/algebra/unit/relations/join_spec.rb +0 -18
  179. data/spec/algebra/unit/relations/order_spec.rb +0 -21
  180. data/spec/algebra/unit/relations/project_spec.rb +0 -34
  181. data/spec/algebra/unit/relations/relation_spec.rb +0 -241
  182. data/spec/algebra/unit/relations/skip_spec.rb +0 -10
  183. data/spec/algebra/unit/relations/table_spec.rb +0 -38
  184. data/spec/algebra/unit/relations/take_spec.rb +0 -10
  185. data/spec/algebra/unit/relations/update_spec.rb +0 -9
  186. data/spec/algebra/unit/relations/where_spec.rb +0 -19
  187. data/spec/algebra/unit/session/session_spec.rb +0 -84
  188. data/spec/attributes/boolean_spec.rb +0 -57
  189. data/spec/attributes/float_spec.rb +0 -119
  190. data/spec/attributes/header_spec.rb +0 -42
  191. data/spec/attributes/integer_spec.rb +0 -119
  192. data/spec/attributes/string_spec.rb +0 -43
  193. data/spec/attributes/time_spec.rb +0 -24
  194. data/spec/engines/memory/integration/joins/cross_engine_spec.rb +0 -61
  195. data/spec/engines/memory/unit/relations/array_spec.rb +0 -33
  196. data/spec/engines/memory/unit/relations/insert_spec.rb +0 -28
  197. data/spec/engines/memory/unit/relations/join_spec.rb +0 -32
  198. data/spec/engines/memory/unit/relations/order_spec.rb +0 -28
  199. data/spec/engines/memory/unit/relations/project_spec.rb +0 -27
  200. data/spec/engines/memory/unit/relations/skip_spec.rb +0 -31
  201. data/spec/engines/memory/unit/relations/take_spec.rb +0 -28
  202. data/spec/engines/memory/unit/relations/where_spec.rb +0 -43
  203. data/spec/engines/sql/integration/joins/with_adjacency_spec.rb +0 -258
  204. data/spec/engines/sql/integration/joins/with_aggregations_spec.rb +0 -221
  205. data/spec/engines/sql/integration/joins/with_compounds_spec.rb +0 -137
  206. data/spec/engines/sql/unit/engine_spec.rb +0 -65
  207. data/spec/engines/sql/unit/predicates/binary_spec.rb +0 -140
  208. data/spec/engines/sql/unit/predicates/equality_spec.rb +0 -75
  209. data/spec/engines/sql/unit/predicates/in_spec.rb +0 -179
  210. data/spec/engines/sql/unit/predicates/noteq_spec.rb +0 -75
  211. data/spec/engines/sql/unit/predicates/predicates_spec.rb +0 -79
  212. data/spec/engines/sql/unit/primitives/attribute_spec.rb +0 -36
  213. data/spec/engines/sql/unit/primitives/expression_spec.rb +0 -28
  214. data/spec/engines/sql/unit/primitives/literal_spec.rb +0 -43
  215. data/spec/engines/sql/unit/primitives/value_spec.rb +0 -29
  216. data/spec/engines/sql/unit/relations/alias_spec.rb +0 -53
  217. data/spec/engines/sql/unit/relations/delete_spec.rb +0 -83
  218. data/spec/engines/sql/unit/relations/from_spec.rb +0 -64
  219. data/spec/engines/sql/unit/relations/group_spec.rb +0 -72
  220. data/spec/engines/sql/unit/relations/having_spec.rb +0 -78
  221. data/spec/engines/sql/unit/relations/insert_spec.rb +0 -143
  222. data/spec/engines/sql/unit/relations/join_spec.rb +0 -180
  223. data/spec/engines/sql/unit/relations/lock_spec.rb +0 -86
  224. data/spec/engines/sql/unit/relations/order_spec.rb +0 -161
  225. data/spec/engines/sql/unit/relations/project_spec.rb +0 -143
  226. data/spec/engines/sql/unit/relations/skip_spec.rb +0 -41
  227. data/spec/engines/sql/unit/relations/table_spec.rb +0 -122
  228. data/spec/engines/sql/unit/relations/take_spec.rb +0 -75
  229. data/spec/engines/sql/unit/relations/update_spec.rb +0 -203
  230. data/spec/engines/sql/unit/relations/where_spec.rb +0 -72
  231. data/spec/relations/join_spec.rb +0 -42
  232. data/spec/relations/relation_spec.rb +0 -31
  233. data/spec/shared/relation_spec.rb +0 -255
  234. data/spec/sql/christener_spec.rb +0 -70
  235. data/spec/support/connections/mysql_connection.rb +0 -14
  236. data/spec/support/connections/oracle_connection.rb +0 -17
  237. data/spec/support/connections/postgresql_connection.rb +0 -13
  238. data/spec/support/connections/sqlite3_connection.rb +0 -24
  239. data/spec/support/guards.rb +0 -28
  240. data/spec/support/matchers/disambiguate_attributes.rb +0 -28
  241. data/spec/support/matchers/hash_the_same_as.rb +0 -26
  242. data/spec/support/matchers/have_rows.rb +0 -18
  243. data/spec/support/model.rb +0 -67
  244. data/spec/support/schemas/mysql_schema.rb +0 -26
  245. data/spec/support/schemas/oracle_schema.rb +0 -20
  246. data/spec/support/schemas/postgresql_schema.rb +0 -26
  247. data/spec/support/schemas/sqlite3_schema.rb +0 -26
@@ -0,0 +1,38 @@
1
+ module Arel
2
+ module Visitors
3
+ ###
4
+ # This class produces SQL for JOIN clauses but omits the "single-source"
5
+ # part of the Join grammar:
6
+ #
7
+ # http://www.sqlite.org/syntaxdiagrams.html#join-source
8
+ #
9
+ # This visitor is used in SelectManager#join_sql and is for backwards
10
+ # compatibility with Arel V1.0
11
+ class JoinSql < Arel::Visitors::ToSql
12
+ def visit_Arel_Nodes_SelectCore o
13
+ [o.froms].grep(Nodes::Join).map { |x| visit x }.join ', '
14
+ end
15
+
16
+ def visit_Arel_Nodes_StringJoin o
17
+ [
18
+ (visit o.left if Nodes::Join === o.left),
19
+ visit(o.right)
20
+ ].compact.join ' '
21
+ end
22
+
23
+ def visit_Arel_Nodes_OuterJoin o
24
+ [
25
+ (visit o.left if Nodes::Join === o.left),
26
+ "LEFT OUTER JOIN #{visit o.right} #{visit o.constraint if o.constraint}"
27
+ ].compact.join ' '
28
+ end
29
+
30
+ def visit_Arel_Nodes_InnerJoin o
31
+ [
32
+ (visit o.left if Nodes::Join === o.left),
33
+ "INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}"
34
+ ].compact.join ' '
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ module Arel
2
+ module Visitors
3
+ class MySQL < Arel::Visitors::ToSql
4
+ def visit_Arel_Nodes_UpdateStatement o
5
+ [
6
+ "UPDATE #{visit o.relation}",
7
+ ("SET #{o.values.map { |value| visit value }.join ', '}" unless o.values.empty?),
8
+ ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?),
9
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
10
+ ("LIMIT #{o.limit}" if o.limit),
11
+ ].compact.join ' '
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,69 @@
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
14
+ )
15
+ o.limit = nil
16
+ return super
17
+ end
18
+
19
+ if o.limit && o.offset
20
+ o = o.dup
21
+ limit = o.limit.to_i
22
+ offset = o.offset
23
+ o.limit = nil
24
+ o.offset = nil
25
+ sql = super(o)
26
+ return <<-eosql
27
+ SELECT * FROM (
28
+ SELECT raw_sql_.*, rownum raw_rnum_
29
+ FROM (#{sql}) raw_sql_
30
+ WHERE rownum <= #{offset.value.to_i + limit}
31
+ )
32
+ WHERE #{visit offset}
33
+ eosql
34
+ end
35
+
36
+ if o.limit
37
+ o = o.dup
38
+ limit = o.limit
39
+ o.limit = nil
40
+ return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{limit}"
41
+ end
42
+
43
+ super
44
+ end
45
+
46
+ def visit_Arel_Nodes_Offset o
47
+ "raw_rnum_ > #{visit o.value}"
48
+ end
49
+
50
+ ###
51
+ # Hacks for the order clauses specific to Oracle
52
+ def order_hacks o
53
+ return o if o.orders.empty?
54
+ return o unless o.cores.any? do |core|
55
+ core.projections.any? do |projection|
56
+ /DISTINCT.*FIRST_VALUE/ === projection
57
+ end
58
+ end
59
+ orders = o.orders.map { |x| visit x }.join(', ').split(',')
60
+ o.orders = []
61
+ orders.each_with_index do |order, i|
62
+ o.orders <<
63
+ Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i === order}")
64
+ end
65
+ o
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,9 @@
1
+ module Arel
2
+ module Visitors
3
+ class OrderClauses < Arel::Visitors::ToSql
4
+ def visit_Arel_Nodes_SelectStatement o
5
+ o.orders.map { |x| visit x }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,54 @@
1
+ module Arel
2
+ module Visitors
3
+ class PostgreSQL < Arel::Visitors::ToSql
4
+ private
5
+ def visit_Arel_Nodes_SelectStatement o
6
+ if !o.orders.empty? && using_distinct_on?(o)
7
+ subquery = o.dup
8
+ subquery.orders = []
9
+ subquery.limit = nil
10
+ subquery.offset = nil
11
+
12
+ sql = super(subquery)
13
+ [
14
+ "SELECT * FROM (#{sql}) AS id_list",
15
+ "ORDER BY #{aliased_orders(o.orders).join(', ')}",
16
+ ("LIMIT #{o.limit}" if o.limit),
17
+ (visit(o.offset) if o.offset),
18
+ ].compact.join ' '
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def visit_Arel_Nodes_Matches o
25
+ "#{visit o.left} ILIKE #{visit o.right}"
26
+ end
27
+
28
+ def visit_Arel_Nodes_DoesNotMatch o
29
+ "#{visit o.left} NOT ILIKE #{visit o.right}"
30
+ end
31
+
32
+ def using_distinct_on?(o)
33
+ o.cores.any? do |core|
34
+ core.projections.any? do |projection|
35
+ /DISTINCT ON/ === projection
36
+ end
37
+ end
38
+ end
39
+
40
+ def aliased_orders orders
41
+ #orders = o.orders.map { |x| visit x }.join(', ').split(',')
42
+ list = []
43
+ orders.each_with_index do |o,i|
44
+ list <<
45
+ [
46
+ "id_list.alias_#{i}",
47
+ (o.index(/desc/i) && 'DESC')
48
+ ].compact.join(' ')
49
+ end
50
+ list
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,301 @@
1
+ require 'bigdecimal'
2
+ require 'date'
3
+
4
+ module Arel
5
+ module Visitors
6
+ class ToSql
7
+ def initialize engine
8
+ @engine = engine
9
+ @connection = nil
10
+ @last_column = nil
11
+ @quoted_tables = {}
12
+ @quoted_columns = {}
13
+ end
14
+
15
+ def accept object
16
+ @last_column = nil
17
+ @engine.connection_pool.with_connection do |conn|
18
+ @connection = conn
19
+ visit object
20
+ end
21
+ end
22
+
23
+ private
24
+ def visit_Arel_Nodes_DeleteStatement o
25
+ [
26
+ "DELETE FROM #{visit o.relation}",
27
+ ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?)
28
+ ].compact.join ' '
29
+ end
30
+
31
+ def visit_Arel_Nodes_UpdateStatement o
32
+ if o.orders.empty? && o.limit.nil?
33
+ wheres = o.wheres
34
+ else
35
+ stmt = Nodes::SelectStatement.new
36
+ core = stmt.cores.first
37
+ core.froms = o.relation
38
+ core.projections = [o.relation.primary_key]
39
+ stmt.limit = o.limit
40
+ stmt.orders = o.orders
41
+
42
+ wheres = [Nodes::In.new(o.relation.primary_key, [stmt])]
43
+ end
44
+
45
+ [
46
+ "UPDATE #{visit o.relation}",
47
+ ("SET #{o.values.map { |value| visit value }.join ', '}" unless o.values.empty?),
48
+ ("WHERE #{wheres.map { |x| visit x }.join ' AND '}" unless wheres.empty?)
49
+ ].compact.join ' '
50
+ end
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
+ end
66
+
67
+ def visit_Arel_Nodes_Values o
68
+ "VALUES (#{o.expressions.zip(o.columns).map { |value, column|
69
+ quote(value, column && column.column)
70
+ }.join ', '})"
71
+ end
72
+
73
+ def visit_Arel_Nodes_SelectStatement o
74
+ [
75
+ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
76
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
77
+ ("LIMIT #{o.limit}" if o.limit),
78
+ (visit(o.offset) if o.offset),
79
+ (visit(o.lock) if o.lock),
80
+ ].compact.join ' '
81
+ end
82
+
83
+ def visit_Arel_Nodes_SelectCore o
84
+ [
85
+ "SELECT #{o.projections.map { |x| visit x }.join ', '}",
86
+ ("FROM #{visit o.froms}" if o.froms),
87
+ ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.empty?),
88
+ ("GROUP BY #{o.groups.map { |x| visit x }.join ', ' }" unless o.groups.empty?),
89
+ (visit(o.having) if o.having),
90
+ ].compact.join ' '
91
+ end
92
+
93
+ def visit_Arel_Nodes_Having o
94
+ "HAVING #{visit o.expr}"
95
+ end
96
+
97
+ def visit_Arel_Nodes_Offset o
98
+ "OFFSET #{visit o.value}"
99
+ end
100
+
101
+ # FIXME: this does nothing on SQLLite3, but should do things on other
102
+ # databases.
103
+ def visit_Arel_Nodes_Lock o
104
+ end
105
+
106
+ def visit_Arel_Nodes_Grouping o
107
+ "(#{visit o.expr})"
108
+ end
109
+
110
+ def visit_Arel_Nodes_Ordering o
111
+ "#{visit o.expr} #{o.descending? ? 'DESC' : 'ASC'}"
112
+ end
113
+
114
+ def visit_Arel_Nodes_Group o
115
+ visit o.expr
116
+ end
117
+
118
+ def visit_Arel_Nodes_Count o
119
+ "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
120
+ visit x
121
+ }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
122
+ end
123
+
124
+ def visit_Arel_Nodes_Sum o
125
+ "SUM(#{o.expressions.map { |x|
126
+ visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
127
+ end
128
+
129
+ def visit_Arel_Nodes_Max o
130
+ "MAX(#{o.expressions.map { |x|
131
+ visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
132
+ end
133
+
134
+ def visit_Arel_Nodes_Min o
135
+ "MIN(#{o.expressions.map { |x|
136
+ visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
137
+ end
138
+
139
+ def visit_Arel_Nodes_Avg o
140
+ "AVG(#{o.expressions.map { |x|
141
+ visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
142
+ end
143
+
144
+ def visit_Arel_Nodes_TableAlias o
145
+ "#{visit o.relation} #{quote_table_name o.name}"
146
+ end
147
+
148
+ def visit_Arel_Nodes_Between o
149
+ "#{visit o.left} BETWEEN #{visit o.right}"
150
+ end
151
+
152
+ def visit_Arel_Nodes_GreaterThanOrEqual o
153
+ "#{visit o.left} >= #{visit o.right}"
154
+ end
155
+
156
+ def visit_Arel_Nodes_GreaterThan o
157
+ "#{visit o.left} > #{visit o.right}"
158
+ end
159
+
160
+ def visit_Arel_Nodes_LessThanOrEqual o
161
+ "#{visit o.left} <= #{visit o.right}"
162
+ end
163
+
164
+ def visit_Arel_Nodes_LessThan o
165
+ "#{visit o.left} < #{visit o.right}"
166
+ end
167
+
168
+ def visit_Arel_Nodes_Matches o
169
+ "#{visit o.left} LIKE #{visit o.right}"
170
+ end
171
+
172
+ def visit_Arel_Nodes_DoesNotMatch o
173
+ "#{visit o.left} NOT LIKE #{visit o.right}"
174
+ end
175
+
176
+ def visit_Arel_Nodes_StringJoin o
177
+ "#{visit o.left} #{visit o.right}"
178
+ end
179
+
180
+ def visit_Arel_Nodes_OuterJoin o
181
+ "#{visit o.left} LEFT OUTER JOIN #{visit o.right} #{visit o.constraint}"
182
+ end
183
+
184
+ def visit_Arel_Nodes_InnerJoin o
185
+ "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}"
186
+ end
187
+
188
+ def visit_Arel_Nodes_On o
189
+ "ON #{visit o.expr}"
190
+ end
191
+
192
+ def visit_Arel_Table o
193
+ if o.table_alias
194
+ "#{quote_table_name o.name} #{quote_table_name o.table_alias}"
195
+ else
196
+ quote_table_name o.name
197
+ end
198
+ end
199
+
200
+ def visit_Arel_Nodes_In o
201
+ right = o.right
202
+ "#{visit o.left} IN (#{
203
+ right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ')
204
+ })"
205
+ end
206
+
207
+ def visit_Arel_Nodes_NotIn o
208
+ right = o.right
209
+ "#{visit o.left} NOT IN (#{
210
+ right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ')
211
+ })"
212
+ end
213
+
214
+ def visit_Arel_Nodes_And o
215
+ "#{visit o.left} AND #{visit o.right}"
216
+ end
217
+
218
+ def visit_Arel_Nodes_Or o
219
+ "#{visit o.left} OR #{visit o.right}"
220
+ end
221
+
222
+ def visit_Arel_Nodes_Assignment o
223
+ right = quote(o.right, o.left.column)
224
+ "#{visit o.left} = #{right}"
225
+ end
226
+
227
+ def visit_Arel_Nodes_Equality o
228
+ right = o.right
229
+
230
+ if right.nil?
231
+ "#{visit o.left} IS NULL"
232
+ else
233
+ "#{visit o.left} = #{visit right}"
234
+ end
235
+ end
236
+
237
+ def visit_Arel_Nodes_NotEqual o
238
+ right = o.right
239
+
240
+ if right.nil?
241
+ "#{visit o.left} IS NOT NULL"
242
+ else
243
+ "#{visit o.left} != #{visit right}"
244
+ end
245
+ end
246
+
247
+ def visit_Arel_Nodes_UnqualifiedColumn o
248
+ "#{quote_column_name o.name}"
249
+ end
250
+
251
+ def visit_Arel_Attributes_Attribute o
252
+ @last_column = o.column
253
+ join_name = o.relation.table_alias || o.relation.name
254
+ "#{quote_table_name join_name}.#{quote_column_name o.name}"
255
+ end
256
+ alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
257
+ alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
258
+ alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute
259
+ alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute
260
+ alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
261
+ alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
262
+
263
+ def visit_Fixnum o; o end
264
+ alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum
265
+ alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated
266
+
267
+ def visit_String o; quote(o, @last_column) end
268
+
269
+ alias :visit_ActiveSupport_Multibyte_Chars :visit_String
270
+ alias :visit_BigDecimal :visit_String
271
+ alias :visit_Date :visit_String
272
+ alias :visit_DateTime :visit_String
273
+ alias :visit_FalseClass :visit_String
274
+ alias :visit_Float :visit_String
275
+ alias :visit_Hash :visit_String
276
+ alias :visit_Symbol :visit_String
277
+ alias :visit_Time :visit_String
278
+ alias :visit_TrueClass :visit_String
279
+
280
+ DISPATCH = Hash.new do |hash, klass|
281
+ hash[klass] = "visit_#{klass.name.gsub('::', '_')}"
282
+ end
283
+
284
+ def visit object
285
+ send DISPATCH[object.class], object
286
+ end
287
+
288
+ def quote value, column = nil
289
+ @connection.quote value, column
290
+ end
291
+
292
+ def quote_table_name name
293
+ @quoted_tables[name] ||= @connection.quote_table_name(name)
294
+ end
295
+
296
+ def quote_column_name name
297
+ @quoted_columns[name] ||= @connection.quote_column_name(name)
298
+ end
299
+ end
300
+ end
301
+ end