activerecord 6.0.6.1 → 6.1.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1143 -780
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_record/aggregations.rb +5 -5
  6. data/lib/active_record/association_relation.rb +30 -12
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +49 -26
  9. data/lib/active_record/associations/association_scope.rb +18 -20
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +32 -18
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +14 -8
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +118 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +11 -5
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +64 -54
  43. data/lib/active_record/attributes.rb +33 -8
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +152 -22
  47. data/lib/active_record/coders/yaml_column.rb +1 -1
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
  87. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  90. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  91. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
  92. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  93. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  94. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
  95. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  96. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  98. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  99. data/lib/active_record/connection_adapters.rb +52 -0
  100. data/lib/active_record/connection_handling.rb +218 -71
  101. data/lib/active_record/core.rb +264 -63
  102. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  103. data/lib/active_record/database_configurations/database_config.rb +52 -9
  104. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  105. data/lib/active_record/database_configurations/url_config.rb +15 -40
  106. data/lib/active_record/database_configurations.rb +125 -85
  107. data/lib/active_record/delegated_type.rb +209 -0
  108. data/lib/active_record/destroy_association_async_job.rb +36 -0
  109. data/lib/active_record/enum.rb +69 -34
  110. data/lib/active_record/errors.rb +47 -12
  111. data/lib/active_record/explain.rb +9 -4
  112. data/lib/active_record/explain_subscriber.rb +1 -1
  113. data/lib/active_record/fixture_set/file.rb +10 -17
  114. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  115. data/lib/active_record/fixture_set/render_context.rb +1 -1
  116. data/lib/active_record/fixture_set/table_row.rb +2 -2
  117. data/lib/active_record/fixtures.rb +58 -9
  118. data/lib/active_record/gem_version.rb +3 -3
  119. data/lib/active_record/inheritance.rb +40 -18
  120. data/lib/active_record/insert_all.rb +38 -5
  121. data/lib/active_record/integration.rb +3 -5
  122. data/lib/active_record/internal_metadata.rb +18 -7
  123. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  124. data/lib/active_record/locking/optimistic.rb +24 -17
  125. data/lib/active_record/locking/pessimistic.rb +6 -2
  126. data/lib/active_record/log_subscriber.rb +27 -8
  127. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  128. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  129. data/lib/active_record/middleware/database_selector.rb +4 -1
  130. data/lib/active_record/migration/command_recorder.rb +47 -27
  131. data/lib/active_record/migration/compatibility.rb +72 -18
  132. data/lib/active_record/migration.rb +114 -84
  133. data/lib/active_record/model_schema.rb +89 -14
  134. data/lib/active_record/nested_attributes.rb +2 -3
  135. data/lib/active_record/no_touching.rb +1 -1
  136. data/lib/active_record/persistence.rb +50 -45
  137. data/lib/active_record/query_cache.rb +15 -5
  138. data/lib/active_record/querying.rb +11 -6
  139. data/lib/active_record/railtie.rb +64 -44
  140. data/lib/active_record/railties/console_sandbox.rb +2 -4
  141. data/lib/active_record/railties/databases.rake +279 -101
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +60 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +104 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +61 -38
  155. data/lib/active_record/relation/query_methods.rb +322 -196
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +8 -7
  158. data/lib/active_record/relation/where_clause.rb +111 -61
  159. data/lib/active_record/relation.rb +100 -81
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +2 -8
  165. data/lib/active_record/scoping/default.rb +1 -3
  166. data/lib/active_record/scoping/named.rb +1 -17
  167. data/lib/active_record/secure_token.rb +16 -8
  168. data/lib/active_record/serialization.rb +5 -3
  169. data/lib/active_record/signed_id.rb +116 -0
  170. data/lib/active_record/statement_cache.rb +20 -4
  171. data/lib/active_record/store.rb +8 -3
  172. data/lib/active_record/suppressor.rb +2 -2
  173. data/lib/active_record/table_metadata.rb +42 -51
  174. data/lib/active_record/tasks/database_tasks.rb +140 -113
  175. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  176. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  177. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  178. data/lib/active_record/test_databases.rb +5 -4
  179. data/lib/active_record/test_fixtures.rb +79 -31
  180. data/lib/active_record/timestamp.rb +4 -6
  181. data/lib/active_record/touch_later.rb +21 -21
  182. data/lib/active_record/transactions.rb +19 -66
  183. data/lib/active_record/type/serialized.rb +6 -2
  184. data/lib/active_record/type.rb +8 -1
  185. data/lib/active_record/type_caster/connection.rb +0 -1
  186. data/lib/active_record/type_caster/map.rb +8 -5
  187. data/lib/active_record/validations/associated.rb +1 -1
  188. data/lib/active_record/validations/numericality.rb +35 -0
  189. data/lib/active_record/validations/uniqueness.rb +24 -4
  190. data/lib/active_record/validations.rb +1 -0
  191. data/lib/active_record.rb +7 -14
  192. data/lib/arel/attributes/attribute.rb +4 -0
  193. data/lib/arel/collectors/bind.rb +5 -0
  194. data/lib/arel/collectors/composite.rb +8 -0
  195. data/lib/arel/collectors/sql_string.rb +7 -0
  196. data/lib/arel/collectors/substitute_binds.rb +7 -0
  197. data/lib/arel/nodes/binary.rb +82 -8
  198. data/lib/arel/nodes/bind_param.rb +8 -0
  199. data/lib/arel/nodes/casted.rb +21 -9
  200. data/lib/arel/nodes/equality.rb +6 -9
  201. data/lib/arel/nodes/grouping.rb +3 -0
  202. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  203. data/lib/arel/nodes/in.rb +8 -1
  204. data/lib/arel/nodes/infix_operation.rb +13 -1
  205. data/lib/arel/nodes/join_source.rb +1 -1
  206. data/lib/arel/nodes/node.rb +7 -6
  207. data/lib/arel/nodes/ordering.rb +27 -0
  208. data/lib/arel/nodes/sql_literal.rb +3 -0
  209. data/lib/arel/nodes/table_alias.rb +7 -3
  210. data/lib/arel/nodes/unary.rb +0 -1
  211. data/lib/arel/nodes.rb +3 -1
  212. data/lib/arel/predications.rb +12 -18
  213. data/lib/arel/select_manager.rb +1 -2
  214. data/lib/arel/table.rb +13 -5
  215. data/lib/arel/visitors/dot.rb +14 -2
  216. data/lib/arel/visitors/mysql.rb +11 -1
  217. data/lib/arel/visitors/postgresql.rb +15 -4
  218. data/lib/arel/visitors/to_sql.rb +89 -78
  219. data/lib/arel/visitors.rb +0 -7
  220. data/lib/arel.rb +5 -13
  221. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  222. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  223. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  224. data/lib/rails/generators/active_record/migration.rb +6 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  227. metadata +25 -26
  228. data/lib/active_record/advisory_lock_base.rb +0 -18
  229. data/lib/active_record/attribute_decorators.rb +0 -88
  230. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  231. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  232. data/lib/active_record/define_callbacks.rb +0 -22
  233. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  234. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  235. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  236. data/lib/arel/attributes.rb +0 -22
  237. data/lib/arel/visitors/depth_first.rb +0 -203
  238. data/lib/arel/visitors/ibm_db.rb +0 -34
  239. data/lib/arel/visitors/informix.rb +0 -62
  240. data/lib/arel/visitors/mssql.rb +0 -156
  241. data/lib/arel/visitors/oracle.rb +0 -158
  242. data/lib/arel/visitors/oracle12.rb +0 -65
  243. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -6,7 +6,6 @@ module Arel # :nodoc: all
6
6
  # Abstract base class for all AST nodes
7
7
  class Node
8
8
  include Arel::FactoryMethods
9
- include Enumerable
10
9
 
11
10
  ###
12
11
  # Factory method to create a Nodes::Not node that has the recipient of
@@ -28,6 +27,10 @@ module Arel # :nodoc: all
28
27
  Nodes::And.new [self, right]
29
28
  end
30
29
 
30
+ def invert
31
+ Arel::Nodes::Not.new(self)
32
+ end
33
+
31
34
  # FIXME: this method should go away. I don't like people calling
32
35
  # to_sql on non-head nodes. This forces us to walk the AST until we
33
36
  # can find a node that has a "relation" member.
@@ -39,12 +42,10 @@ module Arel # :nodoc: all
39
42
  collector.value
40
43
  end
41
44
 
42
- # Iterate through AST, nodes will be yielded depth-first
43
- def each(&block)
44
- return enum_for(:each) unless block_given?
45
-
46
- ::Arel::Visitors::DepthFirst.new(block).accept self
45
+ def fetch_attribute
47
46
  end
47
+
48
+ def equality?; false; end
48
49
  end
49
50
  end
50
51
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Nodes
5
+ class Ordering < Unary
6
+ def nulls_first
7
+ NullsFirst.new(self)
8
+ end
9
+
10
+ def nulls_last
11
+ NullsLast.new(self)
12
+ end
13
+ end
14
+
15
+ class NullsFirst < Ordering
16
+ def reverse
17
+ NullsLast.new(expr.reverse)
18
+ end
19
+ end
20
+
21
+ class NullsLast < Ordering
22
+ def reverse
23
+ NullsFirst.new(expr.reverse)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -11,6 +11,9 @@ module Arel # :nodoc: all
11
11
  def encode_with(coder)
12
12
  coder.scalar = self.to_s
13
13
  end
14
+
15
+ def fetch_attribute
16
+ end
14
17
  end
15
18
  end
16
19
  end
@@ -8,15 +8,19 @@ module Arel # :nodoc: all
8
8
  alias :table_alias :name
9
9
 
10
10
  def [](name)
11
- Attribute.new(self, name)
11
+ relation.is_a?(Table) ? relation[name, self] : Attribute.new(self, name)
12
12
  end
13
13
 
14
14
  def table_name
15
15
  relation.respond_to?(:name) ? relation.name : name
16
16
  end
17
17
 
18
- def type_cast_for_database(*args)
19
- relation.type_cast_for_database(*args)
18
+ def type_cast_for_database(attr_name, value)
19
+ relation.type_cast_for_database(attr_name, value)
20
+ end
21
+
22
+ def type_for_attribute(name)
23
+ relation.type_for_attribute(name)
20
24
  end
21
25
 
22
26
  def able_to_type_cast?
@@ -36,7 +36,6 @@ module Arel # :nodoc: all
36
36
  Offset
37
37
  On
38
38
  OptimizerHints
39
- Ordering
40
39
  RollUp
41
40
  }.each do |name|
42
41
  const_set(name, Class.new(Unary))
data/lib/arel/nodes.rb CHANGED
@@ -18,6 +18,8 @@ require "arel/nodes/false"
18
18
  # unary
19
19
  require "arel/nodes/unary"
20
20
  require "arel/nodes/grouping"
21
+ require "arel/nodes/homogeneous_in"
22
+ require "arel/nodes/ordering"
21
23
  require "arel/nodes/ascending"
22
24
  require "arel/nodes/descending"
23
25
  require "arel/nodes/unqualified_column"
@@ -26,7 +28,7 @@ require "arel/nodes/with"
26
28
  # binary
27
29
  require "arel/nodes/binary"
28
30
  require "arel/nodes/equality"
29
- require "arel/nodes/in" # Why is this subclassed from equality?
31
+ require "arel/nodes/in"
30
32
  require "arel/nodes/join_source"
31
33
  require "arel/nodes/delete_statement"
32
34
  require "arel/nodes/table_alias"
@@ -60,13 +60,6 @@ module Arel # :nodoc: all
60
60
  case other
61
61
  when Arel::SelectManager
62
62
  Arel::Nodes::In.new(self, other.ast)
63
- when Range
64
- if $VERBOSE
65
- warn <<-eowarn
66
- Passing a range to `#in` is deprecated. Call `#between`, instead.
67
- eowarn
68
- end
69
- between(other)
70
63
  when Enumerable
71
64
  Nodes::In.new self, quoted_array(other)
72
65
  else
@@ -110,13 +103,6 @@ Passing a range to `#in` is deprecated. Call `#between`, instead.
110
103
  case other
111
104
  when Arel::SelectManager
112
105
  Arel::Nodes::NotIn.new(self, other.ast)
113
- when Range
114
- if $VERBOSE
115
- warn <<-eowarn
116
- Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
117
- eowarn
118
- end
119
- not_between(other)
120
106
  when Enumerable
121
107
  Nodes::NotIn.new self, quoted_array(other)
122
108
  else
@@ -220,6 +206,18 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
220
206
  Nodes::Concat.new self, other
221
207
  end
222
208
 
209
+ def contains(other)
210
+ Arel::Nodes::Contains.new self, quoted_node(other)
211
+ end
212
+
213
+ def overlaps(other)
214
+ Arel::Nodes::Overlaps.new self, quoted_node(other)
215
+ end
216
+
217
+ def quoted_array(others)
218
+ others.map { |v| quoted_node(v) }
219
+ end
220
+
223
221
  private
224
222
  def grouping_any(method_id, others, *extras)
225
223
  nodes = others.map { |expr| send(method_id, expr, *extras) }
@@ -237,10 +235,6 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
237
235
  Nodes.build_quoted(other, self)
238
236
  end
239
237
 
240
- def quoted_array(others)
241
- others.map { |v| quoted_node(v) }
242
- end
243
-
244
238
  def infinity?(value)
245
239
  value.respond_to?(:infinite?) && value.infinite?
246
240
  end
@@ -186,8 +186,7 @@ module Arel # :nodoc: all
186
186
  def where_sql(engine = Table.engine)
187
187
  return if @ctx.wheres.empty?
188
188
 
189
- viz = Visitors::WhereSql.new(engine.connection.visitor, engine.connection)
190
- Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value
189
+ Nodes::SqlLiteral.new("WHERE #{Nodes::And.new(@ctx.wheres).to_sql(engine)}")
191
190
  end
192
191
 
193
192
  def union(operation, other = nil)
data/lib/arel/table.rb CHANGED
@@ -4,6 +4,7 @@ module Arel # :nodoc: all
4
4
  class Table
5
5
  include Arel::Crud
6
6
  include Arel::FactoryMethods
7
+ include Arel::AliasPredication
7
8
 
8
9
  @engine = nil
9
10
  class << self; attr_accessor :engine; end
@@ -13,8 +14,9 @@ module Arel # :nodoc: all
13
14
  # TableAlias and Table both have a #table_name which is the name of the underlying table
14
15
  alias :table_name :name
15
16
 
16
- def initialize(name, as: nil, type_caster: nil)
17
+ def initialize(name, as: nil, klass: nil, type_caster: klass&.type_caster)
17
18
  @name = name.to_s
19
+ @klass = klass
18
20
  @type_caster = type_caster
19
21
 
20
22
  # Sometime AR sends an :as parameter to table, to let the table know
@@ -78,8 +80,10 @@ module Arel # :nodoc: all
78
80
  from.having expr
79
81
  end
80
82
 
81
- def [](name)
82
- ::Arel::Attribute.new self, name
83
+ def [](name, table = self)
84
+ name = name.to_s if name.is_a?(Symbol)
85
+ name = @klass.attribute_aliases[name] || name if @klass
86
+ Attribute.new(table, name)
83
87
  end
84
88
 
85
89
  def hash
@@ -96,8 +100,12 @@ module Arel # :nodoc: all
96
100
  end
97
101
  alias :== :eql?
98
102
 
99
- def type_cast_for_database(attribute_name, value)
100
- type_caster.type_cast_for_database(attribute_name, value)
103
+ def type_cast_for_database(attr_name, value)
104
+ type_caster.type_cast_for_database(attr_name, value)
105
+ end
106
+
107
+ def type_for_attribute(name)
108
+ type_caster.type_for_attribute(name)
101
109
  end
102
110
 
103
111
  def able_to_type_cast?
@@ -157,7 +157,13 @@ module Arel # :nodoc: all
157
157
  end
158
158
 
159
159
  def visit_Arel_Nodes_Casted(o)
160
- visit_edge o, "val"
160
+ visit_edge o, "value"
161
+ visit_edge o, "attribute"
162
+ end
163
+
164
+ def visit_Arel_Nodes_HomogeneousIn(o)
165
+ visit_edge o, "values"
166
+ visit_edge o, "type"
161
167
  visit_edge o, "attribute"
162
168
  end
163
169
 
@@ -218,7 +224,13 @@ module Arel # :nodoc: all
218
224
  alias :visit_Symbol :visit_String
219
225
  alias :visit_Arel_Nodes_SqlLiteral :visit_String
220
226
 
221
- def visit_Arel_Nodes_BindParam(o); end
227
+ def visit_Arel_Nodes_BindParam(o)
228
+ edge("value") { visit o.value }
229
+ end
230
+
231
+ def visit_ActiveModel_Attribute(o)
232
+ edge("value_before_type_cast") { visit o.value_before_type_cast }
233
+ end
222
234
 
223
235
  def visit_Hash(o)
224
236
  o.each_with_index do |pair, i|
@@ -15,7 +15,9 @@ module Arel # :nodoc: all
15
15
 
16
16
  ###
17
17
  # :'(
18
- # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214
18
+ # To retrieve all rows from a certain offset up to the end of the result set,
19
+ # you can use some large number for the second parameter.
20
+ # https://dev.mysql.com/doc/refman/en/select.html
19
21
  def visit_Arel_Nodes_SelectStatement(o, collector)
20
22
  if o.offset && !o.limit
21
23
  o.limit = Arel::Nodes::Limit.new(18446744073709551615)
@@ -48,6 +50,14 @@ module Arel # :nodoc: all
48
50
  visit_Arel_Nodes_IsNotDistinctFrom o, collector
49
51
  end
50
52
 
53
+ def visit_Arel_Nodes_Regexp(o, collector)
54
+ infix_value o, collector, " REGEXP "
55
+ end
56
+
57
+ def visit_Arel_Nodes_NotRegexp(o, collector)
58
+ infix_value o, collector, " NOT REGEXP "
59
+ end
60
+
51
61
  # In the simple case, MySQL allows us to place JOINs directly into the UPDATE
52
62
  # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
53
63
  # these, we must use a subquery.
@@ -41,10 +41,6 @@ module Arel # :nodoc: all
41
41
  visit(o.expr, collector) << " )"
42
42
  end
43
43
 
44
- def visit_Arel_Nodes_BindParam(o, collector)
45
- collector.add_bind(o.value) { |i| "$#{i}" }
46
- end
47
-
48
44
  def visit_Arel_Nodes_GroupingElement(o, collector)
49
45
  collector << "( "
50
46
  visit(o.expr, collector) << " )"
@@ -82,6 +78,21 @@ module Arel # :nodoc: all
82
78
  visit o.right, collector
83
79
  end
84
80
 
81
+ def visit_Arel_Nodes_NullsFirst(o, collector)
82
+ visit o.expr, collector
83
+ collector << " NULLS FIRST"
84
+ end
85
+
86
+ def visit_Arel_Nodes_NullsLast(o, collector)
87
+ visit o.expr, collector
88
+ collector << " NULLS LAST"
89
+ end
90
+
91
+ BIND_BLOCK = proc { |i| "$#{i}" }
92
+ private_constant :BIND_BLOCK
93
+
94
+ def bind_block; BIND_BLOCK; end
95
+
85
96
  # Used by Lateral visitor to enclose select queries in parentheses
86
97
  def grouping_parentheses(o, collector)
87
98
  if o.expr.is_a? Nodes::SelectStatement
@@ -82,12 +82,9 @@ module Arel # :nodoc: all
82
82
  end
83
83
 
84
84
  def visit_Arel_Nodes_Casted(o, collector)
85
- collector << quoted(o.val, o.attribute).to_s
86
- end
87
-
88
- def visit_Arel_Nodes_Quoted(o, collector)
89
- collector << quoted(o.expr, nil).to_s
85
+ collector << quote(o.value_for_database).to_s
90
86
  end
87
+ alias :visit_Arel_Nodes_Quoted :visit_Arel_Nodes_Casted
91
88
 
92
89
  def visit_Arel_Nodes_True(o, collector)
93
90
  collector << "TRUE"
@@ -195,12 +192,12 @@ module Arel # :nodoc: all
195
192
 
196
193
  def visit_Arel_Nodes_With(o, collector)
197
194
  collector << "WITH "
198
- inject_join o.children, collector, ", "
195
+ collect_ctes(o.children, collector)
199
196
  end
200
197
 
201
198
  def visit_Arel_Nodes_WithRecursive(o, collector)
202
199
  collector << "WITH RECURSIVE "
203
- inject_join o.children, collector, ", "
200
+ collect_ctes(o.children, collector)
204
201
  end
205
202
 
206
203
  def visit_Arel_Nodes_Union(o, collector)
@@ -324,6 +321,29 @@ module Arel # :nodoc: all
324
321
  end
325
322
  end
326
323
 
324
+ def visit_Arel_Nodes_HomogeneousIn(o, collector)
325
+ collector.preparable = false
326
+
327
+ collector << quote_table_name(o.table_name) << "." << quote_column_name(o.column_name)
328
+
329
+ if o.type == :in
330
+ collector << " IN ("
331
+ else
332
+ collector << " NOT IN ("
333
+ end
334
+
335
+ values = o.casted_values
336
+
337
+ if values.empty?
338
+ collector << @connection.quote(nil)
339
+ else
340
+ collector.add_binds(values, o.proc_for_binds, &bind_block)
341
+ end
342
+
343
+ collector << ")"
344
+ collector
345
+ end
346
+
327
347
  def visit_Arel_SelectManager(o, collector)
328
348
  collector << "("
329
349
  visit(o.ast, collector) << ")"
@@ -513,64 +533,35 @@ module Arel # :nodoc: all
513
533
  end
514
534
 
515
535
  def visit_Arel_Nodes_In(o, collector)
516
- unless Array === o.right
517
- return collect_in_clause(o.left, o.right, collector)
518
- end
519
-
520
- unless o.right.empty?
521
- o.right.delete_if { |value| unboundable?(value) }
522
- end
536
+ collector.preparable = false
537
+ attr, values = o.left, o.right
523
538
 
524
- return collector << "1=0" if o.right.empty?
525
-
526
- in_clause_length = @connection.in_clause_length
527
-
528
- if !in_clause_length || o.right.length <= in_clause_length
529
- collect_in_clause(o.left, o.right, collector)
530
- else
531
- collector << "("
532
- o.right.each_slice(in_clause_length).each_with_index do |right, i|
533
- collector << " OR " unless i == 0
534
- collect_in_clause(o.left, right, collector)
539
+ if Array === values
540
+ unless values.empty?
541
+ values.delete_if { |value| unboundable?(value) }
535
542
  end
536
- collector << ")"
543
+
544
+ return collector << "1=0" if values.empty?
537
545
  end
538
- end
539
546
 
540
- def collect_in_clause(left, right, collector)
541
- collector = visit left, collector
542
- collector << " IN ("
543
- visit(right, collector) << ")"
547
+ visit(attr, collector) << " IN ("
548
+ visit(values, collector) << ")"
544
549
  end
545
550
 
546
551
  def visit_Arel_Nodes_NotIn(o, collector)
547
- unless Array === o.right
548
- return collect_not_in_clause(o.left, o.right, collector)
549
- end
550
-
551
- unless o.right.empty?
552
- o.right.delete_if { |value| unboundable?(value) }
553
- end
552
+ collector.preparable = false
553
+ attr, values = o.left, o.right
554
554
 
555
- return collector << "1=1" if o.right.empty?
556
-
557
- in_clause_length = @connection.in_clause_length
558
-
559
- if !in_clause_length || o.right.length <= in_clause_length
560
- collect_not_in_clause(o.left, o.right, collector)
561
- else
562
- o.right.each_slice(in_clause_length).each_with_index do |right, i|
563
- collector << " AND " unless i == 0
564
- collect_not_in_clause(o.left, right, collector)
555
+ if Array === values
556
+ unless values.empty?
557
+ values.delete_if { |value| unboundable?(value) }
565
558
  end
566
- collector
559
+
560
+ return collector << "1=1" if values.empty?
567
561
  end
568
- end
569
562
 
570
- def collect_not_in_clause(left, right, collector)
571
- collector = visit left, collector
572
- collector << " NOT IN ("
573
- visit(right, collector) << ")"
563
+ visit(attr, collector) << " NOT IN ("
564
+ visit(values, collector) << ")"
574
565
  end
575
566
 
576
567
  def visit_Arel_Nodes_And(o, collector)
@@ -578,9 +569,18 @@ module Arel # :nodoc: all
578
569
  end
579
570
 
580
571
  def visit_Arel_Nodes_Or(o, collector)
581
- collector = visit o.left, collector
582
- collector << " OR "
583
- visit o.right, collector
572
+ stack = [o.right, o.left]
573
+
574
+ while o = stack.pop
575
+ if o.is_a?(Arel::Nodes::Or)
576
+ stack.push o.right, o.left
577
+ else
578
+ visit o, collector
579
+ collector << " OR " unless stack.empty?
580
+ end
581
+ end
582
+
583
+ collector
584
584
  end
585
585
 
586
586
  def visit_Arel_Nodes_Assignment(o, collector)
@@ -689,28 +689,23 @@ module Arel # :nodoc: all
689
689
  join_name = o.relation.table_alias || o.relation.name
690
690
  collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
691
691
  end
692
- alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
693
- alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
694
- alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute
695
- alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute
696
- alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
697
- alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
698
692
 
699
- def literal(o, collector); collector << o.to_s; end
693
+ BIND_BLOCK = proc { "?" }
694
+ private_constant :BIND_BLOCK
695
+
696
+ def bind_block; BIND_BLOCK; end
700
697
 
701
698
  def visit_Arel_Nodes_BindParam(o, collector)
702
- collector.add_bind(o.value) { "?" }
699
+ collector.add_bind(o.value, &bind_block)
703
700
  end
704
701
 
705
- alias :visit_Arel_Nodes_SqlLiteral :literal
706
- alias :visit_Integer :literal
702
+ def visit_Arel_Nodes_SqlLiteral(o, collector)
703
+ collector.preparable = false
704
+ collector << o.to_s
705
+ end
707
706
 
708
- def quoted(o, a)
709
- if a && a.able_to_type_cast?
710
- quote(a.type_cast_for_database(o))
711
- else
712
- quote(o)
713
- end
707
+ def visit_Integer(o, collector)
708
+ collector << o.to_s
714
709
  end
715
710
 
716
711
  def unsupported(o, collector)
@@ -738,11 +733,6 @@ module Arel # :nodoc: all
738
733
  visit o.right, collector
739
734
  end
740
735
 
741
- alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation
742
- alias :visit_Arel_Nodes_Subtraction :visit_Arel_Nodes_InfixOperation
743
- alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation
744
- alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation
745
-
746
736
  def visit_Arel_Nodes_UnaryOperation(o, collector)
747
737
  collector << " #{o.operator} "
748
738
  visit o.expr, collector
@@ -883,6 +873,27 @@ module Arel # :nodoc: all
883
873
  collector << " IS NULL)"
884
874
  collector << " THEN 0 ELSE 1 END"
885
875
  end
876
+
877
+ def collect_ctes(children, collector)
878
+ children.each_with_index do |child, i|
879
+ collector << ", " unless i == 0
880
+
881
+ case child
882
+ when Arel::Nodes::As
883
+ name = child.left.name
884
+ relation = child.right
885
+ when Arel::Nodes::TableAlias
886
+ name = child.name
887
+ relation = child.relation
888
+ end
889
+
890
+ collector << quote_table_name(name)
891
+ collector << " AS "
892
+ visit relation, collector
893
+ end
894
+
895
+ collector
896
+ end
886
897
  end
887
898
  end
888
899
  end
data/lib/arel/visitors.rb CHANGED
@@ -1,18 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "arel/visitors/visitor"
4
- require "arel/visitors/depth_first"
5
4
  require "arel/visitors/to_sql"
6
5
  require "arel/visitors/sqlite"
7
6
  require "arel/visitors/postgresql"
8
7
  require "arel/visitors/mysql"
9
- require "arel/visitors/mssql"
10
- require "arel/visitors/oracle"
11
- require "arel/visitors/oracle12"
12
- require "arel/visitors/where_sql"
13
8
  require "arel/visitors/dot"
14
- require "arel/visitors/ibm_db"
15
- require "arel/visitors/informix"
16
9
 
17
10
  module Arel # :nodoc: all
18
11
  module Visitors
data/lib/arel.rb CHANGED
@@ -12,7 +12,7 @@ require "arel/math"
12
12
  require "arel/alias_predication"
13
13
  require "arel/order_predications"
14
14
  require "arel/table"
15
- require "arel/attributes"
15
+ require "arel/attributes/attribute"
16
16
 
17
17
  require "arel/visitors"
18
18
  require "arel/collectors/sql_string"
@@ -43,20 +43,12 @@ module Arel
43
43
  end
44
44
 
45
45
  def self.arel_node?(value) # :nodoc:
46
- value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
46
+ value.is_a?(Arel::Nodes::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
47
47
  end
48
48
 
49
- def self.fetch_attribute(value) # :nodoc:
50
- case value
51
- when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
52
- if value.left.is_a?(Arel::Attributes::Attribute)
53
- yield value.left
54
- elsif value.right.is_a?(Arel::Attributes::Attribute)
55
- yield value.right
56
- end
49
+ def self.fetch_attribute(value, &block) # :nodoc:
50
+ unless String === value
51
+ value.fetch_attribute(&block)
57
52
  end
58
53
  end
59
-
60
- ## Convenience Alias
61
- Node = Arel::Nodes::Node # :nodoc:
62
54
  end
@@ -7,6 +7,7 @@ module ActiveRecord
7
7
  class MigrationGenerator < Base # :nodoc:
8
8
  argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
9
9
 
10
+ class_option :timestamps, type: :boolean
10
11
  class_option :primary_key_type, type: :string, desc: "The type for primary key"
11
12
  class_option :database, type: :string, aliases: %i(--db), desc: "The database for your migration. By default, the current environment's primary database is used."
12
13
 
@@ -6,6 +6,8 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
6
6
  t.string :password_digest<%= attribute.inject_options %>
7
7
  <% elsif attribute.token? -%>
8
8
  t.string :<%= attribute.name %><%= attribute.inject_options %>
9
+ <% elsif attribute.reference? -%>
10
+ t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %><%= foreign_key_type %>
9
11
  <% elsif !attribute.virtual? -%>
10
12
  t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
11
13
  <% end -%>
@@ -3,7 +3,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
3
3
  def change
4
4
  <% attributes.each do |attribute| -%>
5
5
  <%- if attribute.reference? -%>
6
- add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
6
+ add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %><%= foreign_key_type %>
7
7
  <%- elsif attribute.token? -%>
8
8
  add_column :<%= table_name %>, :<%= attribute.name %>, :string<%= attribute.inject_options %>
9
9
  add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>, unique: true
@@ -20,7 +20,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
20
20
  create_join_table :<%= join_tables.first %>, :<%= join_tables.second %> do |t|
21
21
  <%- attributes.each do |attribute| -%>
22
22
  <%- if attribute.reference? -%>
23
- t.references :<%= attribute.name %><%= attribute.inject_options %>
23
+ t.references :<%= attribute.name %><%= attribute.inject_options %><%= foreign_key_type %>
24
24
  <%- elsif !attribute.virtual? -%>
25
25
  <%= '# ' unless attribute.has_index? -%>t.index <%= attribute.index_name %><%= attribute.inject_index_options %>
26
26
  <%- end -%>
@@ -32,7 +32,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
32
32
  <% attributes.each do |attribute| -%>
33
33
  <%- if migration_action -%>
34
34
  <%- if attribute.reference? -%>
35
- remove_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
35
+ remove_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %><%= foreign_key_type %>
36
36
  <%- else -%>
37
37
  <%- if attribute.has_index? -%>
38
38
  remove_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>