arel 1.0.1 → 2.0.0

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 (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