activerecord 6.0.0 → 6.1.4

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1178 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_record/aggregations.rb +5 -6
  6. data/lib/active_record/association_relation.rb +30 -10
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -29
  9. data/lib/active_record/associations/association_scope.rb +19 -15
  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 -3
  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 +25 -8
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  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 +39 -16
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +77 -42
  28. data/lib/active_record/associations/preloader/association.rb +51 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +13 -8
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +120 -13
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +33 -9
  45. data/lib/active_record/autosave_association.rb +63 -44
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +12 -3
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +141 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +76 -79
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  102. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -65
  104. data/lib/active_record/connection_adapters/schema_cache.rb +106 -15
  105. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  106. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
  107. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  108. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  109. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  110. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
  111. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  112. data/lib/active_record/connection_adapters.rb +52 -0
  113. data/lib/active_record/connection_handling.rb +219 -81
  114. data/lib/active_record/core.rb +268 -71
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  117. data/lib/active_record/database_configurations/database_config.rb +52 -9
  118. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  119. data/lib/active_record/database_configurations/url_config.rb +15 -41
  120. data/lib/active_record/database_configurations.rb +124 -85
  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 +80 -38
  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 +58 -12
  134. data/lib/active_record/gem_version.rb +2 -2
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +43 -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 +33 -18
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +28 -9
  143. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  144. data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
  145. data/lib/active_record/middleware/database_selector.rb +4 -2
  146. data/lib/active_record/migration/command_recorder.rb +53 -45
  147. data/lib/active_record/migration/compatibility.rb +71 -20
  148. data/lib/active_record/migration/join_table.rb +0 -1
  149. data/lib/active_record/migration.rb +115 -85
  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/console_sandbox.rb +2 -4
  159. data/lib/active_record/railties/databases.rake +280 -99
  160. data/lib/active_record/readonly_attributes.rb +4 -0
  161. data/lib/active_record/reflection.rb +77 -63
  162. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  163. data/lib/active_record/relation/batches.rb +38 -32
  164. data/lib/active_record/relation/calculations.rb +106 -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/array_handler.rb +8 -9
  170. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  171. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  172. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  173. data/lib/active_record/relation/predicate_builder.rb +59 -40
  174. data/lib/active_record/relation/query_methods.rb +344 -181
  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 +111 -62
  178. data/lib/active_record/relation.rb +116 -82
  179. data/lib/active_record/result.rb +41 -34
  180. data/lib/active_record/runtime_registry.rb +2 -2
  181. data/lib/active_record/sanitization.rb +6 -17
  182. data/lib/active_record/schema_dumper.rb +34 -4
  183. data/lib/active_record/schema_migration.rb +2 -8
  184. data/lib/active_record/scoping/default.rb +1 -4
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/scoping.rb +0 -1
  187. data/lib/active_record/secure_token.rb +16 -8
  188. data/lib/active_record/serialization.rb +5 -3
  189. data/lib/active_record/signed_id.rb +116 -0
  190. data/lib/active_record/statement_cache.rb +20 -4
  191. data/lib/active_record/store.rb +3 -3
  192. data/lib/active_record/suppressor.rb +2 -2
  193. data/lib/active_record/table_metadata.rb +42 -36
  194. data/lib/active_record/tasks/database_tasks.rb +140 -113
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  197. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  198. data/lib/active_record/test_databases.rb +5 -4
  199. data/lib/active_record/test_fixtures.rb +79 -16
  200. data/lib/active_record/timestamp.rb +4 -7
  201. data/lib/active_record/touch_later.rb +20 -21
  202. data/lib/active_record/transactions.rb +26 -73
  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.rb +8 -2
  210. data/lib/active_record/type_caster/connection.rb +0 -1
  211. data/lib/active_record/type_caster/map.rb +8 -5
  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/active_record/validations.rb +3 -3
  216. data/lib/active_record.rb +7 -13
  217. data/lib/arel/attributes/attribute.rb +4 -0
  218. data/lib/arel/collectors/bind.rb +5 -0
  219. data/lib/arel/collectors/composite.rb +8 -0
  220. data/lib/arel/collectors/sql_string.rb +7 -0
  221. data/lib/arel/collectors/substitute_binds.rb +7 -0
  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 +76 -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/nodes.rb +3 -1
  237. data/lib/arel/predications.rb +17 -24
  238. data/lib/arel/select_manager.rb +1 -2
  239. data/lib/arel/table.rb +13 -5
  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/arel/visitors.rb +0 -7
  247. data/lib/arel.rb +15 -12
  248. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  249. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  250. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  251. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  252. data/lib/rails/generators/active_record/migration.rb +6 -2
  253. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  254. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  255. metadata +27 -24
  256. data/lib/active_record/attribute_decorators.rb +0 -90
  257. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  258. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  259. data/lib/active_record/define_callbacks.rb +0 -22
  260. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  261. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  262. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  263. data/lib/arel/attributes.rb +0 -22
  264. data/lib/arel/visitors/depth_first.rb +0 -204
  265. data/lib/arel/visitors/ibm_db.rb +0 -34
  266. data/lib/arel/visitors/informix.rb +0 -62
  267. data/lib/arel/visitors/mssql.rb +0 -157
  268. data/lib/arel/visitors/oracle.rb +0 -159
  269. data/lib/arel/visitors/oracle12.rb +0 -66
  270. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -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, o.proc_for_binds, &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
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"
@@ -24,28 +24,31 @@ require "arel/update_manager"
24
24
  require "arel/delete_manager"
25
25
  require "arel/nodes"
26
26
 
27
- module Arel # :nodoc: all
27
+ module Arel
28
28
  VERSION = "10.0.0"
29
29
 
30
+ # Wrap a known-safe SQL string for passing to query methods, e.g.
31
+ #
32
+ # Post.order(Arel.sql("length(title)")).last
33
+ #
34
+ # Great caution should be taken to avoid SQL injection vulnerabilities.
35
+ # This method should not be used with unsafe values such as request
36
+ # parameters or model attributes.
30
37
  def self.sql(raw_sql)
31
38
  Arel::Nodes::SqlLiteral.new raw_sql
32
39
  end
33
40
 
34
- def self.star
41
+ def self.star # :nodoc:
35
42
  sql "*"
36
43
  end
37
44
 
38
- def self.arel_node?(value)
39
- value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
45
+ def self.arel_node?(value) # :nodoc:
46
+ value.is_a?(Arel::Nodes::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
40
47
  end
41
48
 
42
- def self.fetch_attribute(value)
43
- case value
44
- 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
45
- yield value.left.is_a?(Arel::Attributes::Attribute) ? value.left : value.right
49
+ def self.fetch_attribute(value, &block) # :nodoc:
50
+ unless String === value
51
+ value.fetch_attribute(&block)
46
52
  end
47
53
  end
48
-
49
- ## Convenience Alias
50
- Node = Arel::Nodes::Node
51
54
  end
@@ -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?
@@ -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 -%>
@@ -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
@@ -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
@@ -0,0 +1,7 @@
1
+ <% module_namespacing do -%>
2
+ class <%= abstract_class_name %> < ApplicationRecord
3
+ self.abstract_class = true
4
+
5
+ connects_to database: { <%= ActiveRecord::Base.writing_role %>: :<%= database -%> }
6
+ end
7
+ <% end -%>