activerecord 6.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (268) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +872 -582
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record.rb +7 -13
  6. data/lib/active_record/aggregations.rb +1 -2
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations.rb +116 -13
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +49 -29
  11. data/lib/active_record/associations/association_scope.rb +17 -15
  12. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  14. data/lib/active_record/associations/builder/association.rb +9 -3
  15. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  16. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
  18. data/lib/active_record/associations/builder/has_many.rb +6 -2
  19. data/lib/active_record/associations/builder/has_one.rb +11 -14
  20. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  21. data/lib/active_record/associations/collection_association.rb +25 -8
  22. data/lib/active_record/associations/collection_proxy.rb +14 -7
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +24 -3
  25. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  26. data/lib/active_record/associations/has_one_association.rb +15 -1
  27. data/lib/active_record/associations/join_dependency.rb +77 -42
  28. data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
  29. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  30. data/lib/active_record/associations/preloader.rb +13 -8
  31. data/lib/active_record/associations/preloader/association.rb +51 -25
  32. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  33. data/lib/active_record/associations/singular_association.rb +1 -1
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/attribute_assignment.rb +10 -9
  36. data/lib/active_record/attribute_methods.rb +64 -54
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  38. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  39. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  40. data/lib/active_record/attribute_methods/query.rb +3 -6
  41. data/lib/active_record/attribute_methods/read.rb +8 -12
  42. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +12 -21
  45. data/lib/active_record/attributes.rb +32 -8
  46. data/lib/active_record/autosave_association.rb +63 -44
  47. data/lib/active_record/base.rb +2 -14
  48. data/lib/active_record/callbacks.rb +153 -24
  49. data/lib/active_record/coders/yaml_column.rb +1 -2
  50. data/lib/active_record/connection_adapters.rb +50 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +86 -37
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +4 -9
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -76
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
  64. data/lib/active_record/connection_adapters/column.rb +15 -1
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  77. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
  81. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  90. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  93. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  101. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  102. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  103. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  104. data/lib/active_record/connection_adapters/postgresql_adapter.rb +81 -57
  105. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  106. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  107. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
  108. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  109. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  110. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  111. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
  112. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  113. data/lib/active_record/connection_handling.rb +211 -81
  114. data/lib/active_record/core.rb +237 -69
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations.rb +124 -85
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  118. data/lib/active_record/database_configurations/database_config.rb +52 -9
  119. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  120. data/lib/active_record/database_configurations/url_config.rb +15 -41
  121. data/lib/active_record/delegated_type.rb +209 -0
  122. data/lib/active_record/destroy_association_async_job.rb +36 -0
  123. data/lib/active_record/dynamic_matchers.rb +2 -3
  124. data/lib/active_record/enum.rb +40 -16
  125. data/lib/active_record/errors.rb +47 -12
  126. data/lib/active_record/explain.rb +9 -5
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +10 -17
  129. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  130. data/lib/active_record/fixture_set/render_context.rb +1 -1
  131. data/lib/active_record/fixture_set/table_row.rb +2 -3
  132. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  133. data/lib/active_record/fixtures.rb +54 -11
  134. data/lib/active_record/gem_version.rb +1 -1
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +39 -10
  137. data/lib/active_record/integration.rb +3 -5
  138. data/lib/active_record/internal_metadata.rb +16 -7
  139. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  140. data/lib/active_record/locking/optimistic.rb +22 -17
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +27 -9
  143. data/lib/active_record/middleware/database_selector.rb +4 -2
  144. data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
  145. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  146. data/lib/active_record/migration.rb +114 -84
  147. data/lib/active_record/migration/command_recorder.rb +53 -45
  148. data/lib/active_record/migration/compatibility.rb +70 -20
  149. data/lib/active_record/migration/join_table.rb +0 -1
  150. data/lib/active_record/model_schema.rb +120 -15
  151. data/lib/active_record/nested_attributes.rb +2 -5
  152. data/lib/active_record/no_touching.rb +1 -1
  153. data/lib/active_record/null_relation.rb +0 -1
  154. data/lib/active_record/persistence.rb +50 -46
  155. data/lib/active_record/query_cache.rb +15 -5
  156. data/lib/active_record/querying.rb +12 -7
  157. data/lib/active_record/railtie.rb +65 -45
  158. data/lib/active_record/railties/databases.rake +267 -93
  159. data/lib/active_record/readonly_attributes.rb +4 -0
  160. data/lib/active_record/reflection.rb +77 -63
  161. data/lib/active_record/relation.rb +108 -67
  162. data/lib/active_record/relation/batches.rb +38 -32
  163. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  164. data/lib/active_record/relation/calculations.rb +102 -45
  165. data/lib/active_record/relation/delegation.rb +9 -7
  166. data/lib/active_record/relation/finder_methods.rb +55 -17
  167. data/lib/active_record/relation/from_clause.rb +5 -1
  168. data/lib/active_record/relation/merger.rb +27 -26
  169. data/lib/active_record/relation/predicate_builder.rb +55 -35
  170. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  171. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  173. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  174. data/lib/active_record/relation/query_methods.rb +340 -180
  175. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  176. data/lib/active_record/relation/spawn_methods.rb +8 -8
  177. data/lib/active_record/relation/where_clause.rb +104 -58
  178. data/lib/active_record/result.rb +41 -34
  179. data/lib/active_record/runtime_registry.rb +2 -2
  180. data/lib/active_record/sanitization.rb +6 -17
  181. data/lib/active_record/schema_dumper.rb +34 -4
  182. data/lib/active_record/schema_migration.rb +2 -8
  183. data/lib/active_record/scoping.rb +0 -1
  184. data/lib/active_record/scoping/default.rb +0 -1
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/secure_token.rb +16 -8
  187. data/lib/active_record/serialization.rb +5 -3
  188. data/lib/active_record/signed_id.rb +116 -0
  189. data/lib/active_record/statement_cache.rb +20 -4
  190. data/lib/active_record/store.rb +3 -3
  191. data/lib/active_record/suppressor.rb +2 -2
  192. data/lib/active_record/table_metadata.rb +39 -36
  193. data/lib/active_record/tasks/database_tasks.rb +139 -113
  194. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  195. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  196. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  197. data/lib/active_record/test_databases.rb +5 -4
  198. data/lib/active_record/test_fixtures.rb +38 -16
  199. data/lib/active_record/timestamp.rb +4 -7
  200. data/lib/active_record/touch_later.rb +20 -21
  201. data/lib/active_record/transactions.rb +22 -71
  202. data/lib/active_record/type.rb +8 -2
  203. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  204. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  205. data/lib/active_record/type/serialized.rb +6 -3
  206. data/lib/active_record/type/time.rb +10 -0
  207. data/lib/active_record/type/type_map.rb +0 -1
  208. data/lib/active_record/type/unsigned_integer.rb +0 -1
  209. data/lib/active_record/type_caster/connection.rb +0 -1
  210. data/lib/active_record/type_caster/map.rb +8 -5
  211. data/lib/active_record/validations.rb +3 -3
  212. data/lib/active_record/validations/associated.rb +1 -2
  213. data/lib/active_record/validations/numericality.rb +35 -0
  214. data/lib/active_record/validations/uniqueness.rb +24 -4
  215. data/lib/arel.rb +15 -12
  216. data/lib/arel/attributes/attribute.rb +4 -0
  217. data/lib/arel/collectors/bind.rb +5 -0
  218. data/lib/arel/collectors/composite.rb +8 -0
  219. data/lib/arel/collectors/sql_string.rb +7 -0
  220. data/lib/arel/collectors/substitute_binds.rb +7 -0
  221. data/lib/arel/nodes.rb +3 -1
  222. data/lib/arel/nodes/binary.rb +82 -8
  223. data/lib/arel/nodes/bind_param.rb +8 -0
  224. data/lib/arel/nodes/casted.rb +21 -9
  225. data/lib/arel/nodes/equality.rb +6 -9
  226. data/lib/arel/nodes/grouping.rb +3 -0
  227. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  228. data/lib/arel/nodes/in.rb +8 -1
  229. data/lib/arel/nodes/infix_operation.rb +13 -1
  230. data/lib/arel/nodes/join_source.rb +1 -1
  231. data/lib/arel/nodes/node.rb +7 -6
  232. data/lib/arel/nodes/ordering.rb +27 -0
  233. data/lib/arel/nodes/sql_literal.rb +3 -0
  234. data/lib/arel/nodes/table_alias.rb +7 -3
  235. data/lib/arel/nodes/unary.rb +0 -1
  236. data/lib/arel/predications.rb +17 -24
  237. data/lib/arel/select_manager.rb +1 -2
  238. data/lib/arel/table.rb +13 -5
  239. data/lib/arel/visitors.rb +0 -7
  240. data/lib/arel/visitors/dot.rb +14 -3
  241. data/lib/arel/visitors/mysql.rb +11 -1
  242. data/lib/arel/visitors/postgresql.rb +15 -5
  243. data/lib/arel/visitors/sqlite.rb +0 -1
  244. data/lib/arel/visitors/to_sql.rb +89 -79
  245. data/lib/arel/visitors/visitor.rb +0 -1
  246. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  247. data/lib/rails/generators/active_record/migration.rb +6 -2
  248. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  249. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  250. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  251. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  252. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  253. metadata +27 -24
  254. data/lib/active_record/attribute_decorators.rb +0 -90
  255. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  256. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  257. data/lib/active_record/define_callbacks.rb +0 -22
  258. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  259. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  260. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  261. data/lib/arel/attributes.rb +0 -22
  262. data/lib/arel/visitors/depth_first.rb +0 -204
  263. data/lib/arel/visitors/ibm_db.rb +0 -34
  264. data/lib/arel/visitors/informix.rb +0 -62
  265. data/lib/arel/visitors/mssql.rb +0 -157
  266. data/lib/arel/visitors/oracle.rb +0 -159
  267. data/lib/arel/visitors/oracle12.rb +0 -66
  268. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -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.
@@ -4,7 +4,6 @@ module Arel # :nodoc: all
4
4
  module Visitors
5
5
  class PostgreSQL < Arel::Visitors::ToSql
6
6
  private
7
-
8
7
  def visit_Arel_Nodes_Matches(o, collector)
9
8
  op = o.case_sensitive ? " LIKE " : " ILIKE "
10
9
  collector = infix_value o, collector, op
@@ -42,10 +41,6 @@ module Arel # :nodoc: all
42
41
  visit(o.expr, collector) << " )"
43
42
  end
44
43
 
45
- def visit_Arel_Nodes_BindParam(o, collector)
46
- collector.add_bind(o.value) { |i| "$#{i}" }
47
- end
48
-
49
44
  def visit_Arel_Nodes_GroupingElement(o, collector)
50
45
  collector << "( "
51
46
  visit(o.expr, collector) << " )"
@@ -83,6 +78,21 @@ module Arel # :nodoc: all
83
78
  visit o.right, collector
84
79
  end
85
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
+
86
96
  # Used by Lateral visitor to enclose select queries in parentheses
87
97
  def grouping_parentheses(o, collector)
88
98
  if o.expr.is_a? Nodes::SelectStatement
@@ -4,7 +4,6 @@ module Arel # :nodoc: all
4
4
  module Visitors
5
5
  class SQLite < Arel::Visitors::ToSql
6
6
  private
7
-
8
7
  # Locks are not supported in SQLite
9
8
  def visit_Arel_Nodes_Lock(o, collector)
10
9
  collector
@@ -19,7 +19,6 @@ module Arel # :nodoc: all
19
19
  end
20
20
 
21
21
  private
22
-
23
22
  def visit_Arel_Nodes_DeleteStatement(o, collector)
24
23
  o = prepare_delete_statement(o)
25
24
 
@@ -83,12 +82,9 @@ module Arel # :nodoc: all
83
82
  end
84
83
 
85
84
  def visit_Arel_Nodes_Casted(o, collector)
86
- collector << quoted(o.val, o.attribute).to_s
87
- end
88
-
89
- def visit_Arel_Nodes_Quoted(o, collector)
90
- collector << quoted(o.expr, nil).to_s
85
+ collector << quote(o.value_for_database).to_s
91
86
  end
87
+ alias :visit_Arel_Nodes_Quoted :visit_Arel_Nodes_Casted
92
88
 
93
89
  def visit_Arel_Nodes_True(o, collector)
94
90
  collector << "TRUE"
@@ -196,12 +192,12 @@ module Arel # :nodoc: all
196
192
 
197
193
  def visit_Arel_Nodes_With(o, collector)
198
194
  collector << "WITH "
199
- inject_join o.children, collector, ", "
195
+ collect_ctes(o.children, collector)
200
196
  end
201
197
 
202
198
  def visit_Arel_Nodes_WithRecursive(o, collector)
203
199
  collector << "WITH RECURSIVE "
204
- inject_join o.children, collector, ", "
200
+ collect_ctes(o.children, collector)
205
201
  end
206
202
 
207
203
  def visit_Arel_Nodes_Union(o, collector)
@@ -325,6 +321,29 @@ module Arel # :nodoc: all
325
321
  end
326
322
  end
327
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, &bind_block)
341
+ end
342
+
343
+ collector << ")"
344
+ collector
345
+ end
346
+
328
347
  def visit_Arel_SelectManager(o, collector)
329
348
  collector << "("
330
349
  visit(o.ast, collector) << ")"
@@ -514,64 +533,35 @@ module Arel # :nodoc: all
514
533
  end
515
534
 
516
535
  def visit_Arel_Nodes_In(o, collector)
517
- unless Array === o.right
518
- return collect_in_clause(o.left, o.right, collector)
519
- end
520
-
521
- unless o.right.empty?
522
- o.right.delete_if { |value| unboundable?(value) }
523
- end
524
-
525
- return collector << "1=0" if o.right.empty?
526
-
527
- in_clause_length = @connection.in_clause_length
536
+ collector.preparable = false
537
+ attr, values = o.left, o.right
528
538
 
529
- if !in_clause_length || o.right.length <= in_clause_length
530
- collect_in_clause(o.left, o.right, collector)
531
- else
532
- collector << "("
533
- o.right.each_slice(in_clause_length).each_with_index do |right, i|
534
- collector << " OR " unless i == 0
535
- collect_in_clause(o.left, right, collector)
539
+ if Array === values
540
+ unless values.empty?
541
+ values.delete_if { |value| unboundable?(value) }
536
542
  end
537
- collector << ")"
543
+
544
+ return collector << "1=0" if values.empty?
538
545
  end
539
- end
540
546
 
541
- def collect_in_clause(left, right, collector)
542
- collector = visit left, collector
543
- collector << " IN ("
544
- visit(right, collector) << ")"
547
+ visit(attr, collector) << " IN ("
548
+ visit(values, collector) << ")"
545
549
  end
546
550
 
547
551
  def visit_Arel_Nodes_NotIn(o, collector)
548
- unless Array === o.right
549
- return collect_not_in_clause(o.left, o.right, collector)
550
- end
551
-
552
- unless o.right.empty?
553
- o.right.delete_if { |value| unboundable?(value) }
554
- end
555
-
556
- return collector << "1=1" if o.right.empty?
552
+ collector.preparable = false
553
+ attr, values = o.left, o.right
557
554
 
558
- in_clause_length = @connection.in_clause_length
559
-
560
- if !in_clause_length || o.right.length <= in_clause_length
561
- collect_not_in_clause(o.left, o.right, collector)
562
- else
563
- o.right.each_slice(in_clause_length).each_with_index do |right, i|
564
- collector << " AND " unless i == 0
565
- collect_not_in_clause(o.left, right, collector)
555
+ if Array === values
556
+ unless values.empty?
557
+ values.delete_if { |value| unboundable?(value) }
566
558
  end
567
- collector
559
+
560
+ return collector << "1=1" if values.empty?
568
561
  end
569
- end
570
562
 
571
- def collect_not_in_clause(left, right, collector)
572
- collector = visit left, collector
573
- collector << " NOT IN ("
574
- visit(right, collector) << ")"
563
+ visit(attr, collector) << " NOT IN ("
564
+ visit(values, collector) << ")"
575
565
  end
576
566
 
577
567
  def visit_Arel_Nodes_And(o, collector)
@@ -579,9 +569,18 @@ module Arel # :nodoc: all
579
569
  end
580
570
 
581
571
  def visit_Arel_Nodes_Or(o, collector)
582
- collector = visit o.left, collector
583
- collector << " OR "
584
- 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
585
584
  end
586
585
 
587
586
  def visit_Arel_Nodes_Assignment(o, collector)
@@ -690,28 +689,23 @@ module Arel # :nodoc: all
690
689
  join_name = o.relation.table_alias || o.relation.name
691
690
  collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
692
691
  end
693
- alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
694
- alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
695
- alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute
696
- alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute
697
- alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
698
- alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
699
692
 
700
- 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
701
697
 
702
698
  def visit_Arel_Nodes_BindParam(o, collector)
703
- collector.add_bind(o.value) { "?" }
699
+ collector.add_bind(o.value, &bind_block)
704
700
  end
705
701
 
706
- alias :visit_Arel_Nodes_SqlLiteral :literal
707
- alias :visit_Integer :literal
702
+ def visit_Arel_Nodes_SqlLiteral(o, collector)
703
+ collector.preparable = false
704
+ collector << o.to_s
705
+ end
708
706
 
709
- def quoted(o, a)
710
- if a && a.able_to_type_cast?
711
- quote(a.type_cast_for_database(o))
712
- else
713
- quote(o)
714
- end
707
+ def visit_Integer(o, collector)
708
+ collector << o.to_s
715
709
  end
716
710
 
717
711
  def unsupported(o, collector)
@@ -739,11 +733,6 @@ module Arel # :nodoc: all
739
733
  visit o.right, collector
740
734
  end
741
735
 
742
- alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation
743
- alias :visit_Arel_Nodes_Subtraction :visit_Arel_Nodes_InfixOperation
744
- alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation
745
- alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation
746
-
747
736
  def visit_Arel_Nodes_UnaryOperation(o, collector)
748
737
  collector << " #{o.operator} "
749
738
  visit o.expr, collector
@@ -884,6 +873,27 @@ module Arel # :nodoc: all
884
873
  collector << " IS NULL)"
885
874
  collector << " THEN 0 ELSE 1 END"
886
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
887
897
  end
888
898
  end
889
899
  end
@@ -12,7 +12,6 @@ module Arel # :nodoc: all
12
12
  end
13
13
 
14
14
  private
15
-
16
15
  attr_reader :dispatch
17
16
 
18
17
  def self.dispatch_cache
@@ -13,7 +13,6 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  private
16
-
17
16
  def application_record_file_name
18
17
  @application_record_file_name ||=
19
18
  if namespaced?
@@ -17,12 +17,16 @@ module ActiveRecord
17
17
  end
18
18
 
19
19
  private
20
-
21
20
  def primary_key_type
22
21
  key_type = options[:primary_key_type]
23
22
  ", id: :#{key_type}" if key_type
24
23
  end
25
24
 
25
+ def foreign_key_type
26
+ key_type = options[:primary_key_type]
27
+ ", type: :#{key_type}" if key_type
28
+ end
29
+
26
30
  def db_migrate_path
27
31
  if defined?(Rails.application) && Rails.application
28
32
  configured_migrate_path || default_migrate_path
@@ -39,7 +43,7 @@ module ActiveRecord
39
43
  return unless database = options[:database]
40
44
  config = ActiveRecord::Base.configurations.configs_for(
41
45
  env_name: Rails.env,
42
- spec_name: database,
46
+ name: database
43
47
  )
44
48
  config&.migrations_paths
45
49
  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,12 +32,12 @@ 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 %>
39
39
  <%- end -%>
40
- <%- if !attribute.virtual? %>
40
+ <%- if !attribute.virtual? -%>
41
41
  remove_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
42
42
  <%- end -%>
43
43
  <%- end -%>
@@ -18,12 +18,13 @@ module ActiveRecord
18
18
 
19
19
  # creates the migration file for the model.
20
20
  def create_migration_file
21
- return unless options[:migration] && options[:parent].nil?
21
+ return if skip_migration_creation?
22
22
  attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
23
23
  migration_template "../../migration/templates/create_table_migration.rb", File.join(db_migrate_path, "create_#{table_name}.rb")
24
24
  end
25
25
 
26
26
  def create_model_file
27
+ generate_abstract_class if database && !parent
27
28
  template "model.rb", File.join("app/models", class_path, "#{file_name}.rb")
28
29
  end
29
30
 
@@ -35,6 +36,12 @@ module ActiveRecord
35
36
  hook_for :test_framework
36
37
 
37
38
  private
39
+ # Skip creating migration file if:
40
+ # - options parent is present and database option is not present
41
+ # - migrations option is nil or false
42
+ def skip_migration_creation?
43
+ parent && !database || !migration
44
+ end
38
45
 
39
46
  def attributes_with_index
40
47
  attributes.select { |a| !a.reference? && a.has_index? }
@@ -42,7 +49,36 @@ module ActiveRecord
42
49
 
43
50
  # Used by the migration template to determine the parent name of the model
44
51
  def parent_class_name
45
- options[:parent] || "ApplicationRecord"
52
+ if parent
53
+ parent
54
+ elsif database
55
+ abstract_class_name
56
+ else
57
+ "ApplicationRecord"
58
+ end
59
+ end
60
+
61
+ def generate_abstract_class
62
+ path = File.join("app/models", "#{database.underscore}_record.rb")
63
+ return if File.exist?(path)
64
+
65
+ template "abstract_base_class.rb", path
66
+ end
67
+
68
+ def abstract_class_name
69
+ "#{database.camelize}Record"
70
+ end
71
+
72
+ def database
73
+ options[:database]
74
+ end
75
+
76
+ def parent
77
+ options[:parent]
78
+ end
79
+
80
+ def migration
81
+ options[:migration]
46
82
  end
47
83
  end
48
84
  end