activerecord 5.2.8.1 → 6.1.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1347 -624
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +9 -8
  7. data/lib/active_record/association_relation.rb +30 -10
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +100 -41
  10. data/lib/active_record/associations/association_scope.rb +23 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +55 -48
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  13. data/lib/active_record/associations/builder/association.rb +45 -22
  14. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  15. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -2
  18. data/lib/active_record/associations/builder/has_one.rb +33 -2
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  20. data/lib/active_record/associations/collection_association.rb +44 -34
  21. data/lib/active_record/associations/collection_proxy.rb +25 -21
  22. data/lib/active_record/associations/foreign_association.rb +20 -0
  23. data/lib/active_record/associations/has_many_association.rb +26 -13
  24. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  25. data/lib/active_record/associations/has_one_association.rb +43 -31
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  28. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/preloader/association.rb +69 -43
  31. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/singular_association.rb +3 -17
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/associations.rb +137 -25
  36. data/lib/active_record/attribute_assignment.rb +17 -19
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  38. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  40. data/lib/active_record/attribute_methods/query.rb +4 -8
  41. data/lib/active_record/attribute_methods/read.rb +14 -56
  42. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +18 -34
  45. data/lib/active_record/attribute_methods.rb +81 -143
  46. data/lib/active_record/attributes.rb +46 -9
  47. data/lib/active_record/autosave_association.rb +57 -42
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +16 -7
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +107 -47
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  64. data/lib/active_record/connection_adapters/column.rb +30 -12
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  77. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
  81. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  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 +1 -2
  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 +3 -4
  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 +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  94. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  96. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/quoting.rb +73 -10
  99. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  101. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  102. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  104. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  105. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  106. data/lib/active_record/connection_adapters/postgresql_adapter.rb +225 -121
  107. data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
  108. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  109. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  110. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  111. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  112. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  113. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  114. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  115. data/lib/active_record/connection_adapters.rb +52 -0
  116. data/lib/active_record/connection_handling.rb +293 -33
  117. data/lib/active_record/core.rb +341 -99
  118. data/lib/active_record/counter_cache.rb +8 -30
  119. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  120. data/lib/active_record/database_configurations/database_config.rb +80 -0
  121. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  122. data/lib/active_record/database_configurations/url_config.rb +53 -0
  123. data/lib/active_record/database_configurations.rb +273 -0
  124. data/lib/active_record/delegated_type.rb +209 -0
  125. data/lib/active_record/destroy_association_async_job.rb +36 -0
  126. data/lib/active_record/dynamic_matchers.rb +3 -4
  127. data/lib/active_record/enum.rb +108 -36
  128. data/lib/active_record/errors.rb +62 -19
  129. data/lib/active_record/explain.rb +10 -6
  130. data/lib/active_record/explain_subscriber.rb +1 -1
  131. data/lib/active_record/fixture_set/file.rb +10 -17
  132. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  133. data/lib/active_record/fixture_set/render_context.rb +17 -0
  134. data/lib/active_record/fixture_set/table_row.rb +152 -0
  135. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  136. data/lib/active_record/fixtures.rb +200 -481
  137. data/lib/active_record/gem_version.rb +4 -4
  138. data/lib/active_record/inheritance.rb +53 -24
  139. data/lib/active_record/insert_all.rb +212 -0
  140. data/lib/active_record/integration.rb +67 -17
  141. data/lib/active_record/internal_metadata.rb +28 -9
  142. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  143. data/lib/active_record/locking/optimistic.rb +37 -23
  144. data/lib/active_record/locking/pessimistic.rb +9 -5
  145. data/lib/active_record/log_subscriber.rb +35 -35
  146. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  147. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  148. data/lib/active_record/middleware/database_selector.rb +77 -0
  149. data/lib/active_record/migration/command_recorder.rb +96 -44
  150. data/lib/active_record/migration/compatibility.rb +145 -64
  151. data/lib/active_record/migration/join_table.rb +0 -1
  152. data/lib/active_record/migration.rb +206 -157
  153. data/lib/active_record/model_schema.rb +148 -22
  154. data/lib/active_record/nested_attributes.rb +4 -7
  155. data/lib/active_record/no_touching.rb +8 -1
  156. data/lib/active_record/null_relation.rb +0 -1
  157. data/lib/active_record/persistence.rb +267 -59
  158. data/lib/active_record/query_cache.rb +21 -4
  159. data/lib/active_record/querying.rb +40 -23
  160. data/lib/active_record/railtie.rb +113 -74
  161. data/lib/active_record/railties/console_sandbox.rb +2 -4
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +411 -80
  164. data/lib/active_record/readonly_attributes.rb +4 -0
  165. data/lib/active_record/reflection.rb +109 -93
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  167. data/lib/active_record/relation/batches.rb +44 -35
  168. data/lib/active_record/relation/calculations.rb +157 -90
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +64 -39
  171. data/lib/active_record/relation/from_clause.rb +5 -1
  172. data/lib/active_record/relation/merger.rb +32 -40
  173. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  174. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  179. data/lib/active_record/relation/predicate_builder.rb +62 -45
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +478 -187
  182. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  183. data/lib/active_record/relation/spawn_methods.rb +9 -9
  184. data/lib/active_record/relation/where_clause.rb +115 -62
  185. data/lib/active_record/relation.rb +379 -115
  186. data/lib/active_record/result.rb +64 -38
  187. data/lib/active_record/runtime_registry.rb +2 -2
  188. data/lib/active_record/sanitization.rb +22 -41
  189. data/lib/active_record/schema.rb +2 -11
  190. data/lib/active_record/schema_dumper.rb +54 -9
  191. data/lib/active_record/schema_migration.rb +7 -9
  192. data/lib/active_record/scoping/default.rb +4 -8
  193. data/lib/active_record/scoping/named.rb +17 -24
  194. data/lib/active_record/scoping.rb +8 -9
  195. data/lib/active_record/secure_token.rb +16 -8
  196. data/lib/active_record/serialization.rb +5 -3
  197. data/lib/active_record/signed_id.rb +116 -0
  198. data/lib/active_record/statement_cache.rb +49 -6
  199. data/lib/active_record/store.rb +94 -10
  200. data/lib/active_record/suppressor.rb +2 -2
  201. data/lib/active_record/table_metadata.rb +42 -43
  202. data/lib/active_record/tasks/database_tasks.rb +277 -81
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  206. data/lib/active_record/test_databases.rb +24 -0
  207. data/lib/active_record/test_fixtures.rb +291 -0
  208. data/lib/active_record/timestamp.rb +43 -32
  209. data/lib/active_record/touch_later.rb +23 -22
  210. data/lib/active_record/transactions.rb +62 -118
  211. data/lib/active_record/translation.rb +1 -1
  212. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  213. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  214. data/lib/active_record/type/serialized.rb +6 -3
  215. data/lib/active_record/type/time.rb +10 -0
  216. data/lib/active_record/type/type_map.rb +0 -1
  217. data/lib/active_record/type/unsigned_integer.rb +0 -1
  218. data/lib/active_record/type.rb +10 -5
  219. data/lib/active_record/type_caster/connection.rb +15 -15
  220. data/lib/active_record/type_caster/map.rb +8 -8
  221. data/lib/active_record/validations/associated.rb +1 -2
  222. data/lib/active_record/validations/numericality.rb +35 -0
  223. data/lib/active_record/validations/uniqueness.rb +38 -30
  224. data/lib/active_record/validations.rb +4 -3
  225. data/lib/active_record.rb +13 -12
  226. data/lib/arel/alias_predication.rb +9 -0
  227. data/lib/arel/attributes/attribute.rb +41 -0
  228. data/lib/arel/collectors/bind.rb +29 -0
  229. data/lib/arel/collectors/composite.rb +39 -0
  230. data/lib/arel/collectors/plain_string.rb +20 -0
  231. data/lib/arel/collectors/sql_string.rb +27 -0
  232. data/lib/arel/collectors/substitute_binds.rb +35 -0
  233. data/lib/arel/crud.rb +42 -0
  234. data/lib/arel/delete_manager.rb +18 -0
  235. data/lib/arel/errors.rb +9 -0
  236. data/lib/arel/expressions.rb +29 -0
  237. data/lib/arel/factory_methods.rb +49 -0
  238. data/lib/arel/insert_manager.rb +49 -0
  239. data/lib/arel/math.rb +45 -0
  240. data/lib/arel/nodes/and.rb +32 -0
  241. data/lib/arel/nodes/ascending.rb +23 -0
  242. data/lib/arel/nodes/binary.rb +126 -0
  243. data/lib/arel/nodes/bind_param.rb +44 -0
  244. data/lib/arel/nodes/case.rb +55 -0
  245. data/lib/arel/nodes/casted.rb +62 -0
  246. data/lib/arel/nodes/comment.rb +29 -0
  247. data/lib/arel/nodes/count.rb +12 -0
  248. data/lib/arel/nodes/delete_statement.rb +45 -0
  249. data/lib/arel/nodes/descending.rb +23 -0
  250. data/lib/arel/nodes/equality.rb +15 -0
  251. data/lib/arel/nodes/extract.rb +24 -0
  252. data/lib/arel/nodes/false.rb +16 -0
  253. data/lib/arel/nodes/full_outer_join.rb +8 -0
  254. data/lib/arel/nodes/function.rb +44 -0
  255. data/lib/arel/nodes/grouping.rb +11 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  257. data/lib/arel/nodes/in.rb +15 -0
  258. data/lib/arel/nodes/infix_operation.rb +92 -0
  259. data/lib/arel/nodes/inner_join.rb +8 -0
  260. data/lib/arel/nodes/insert_statement.rb +37 -0
  261. data/lib/arel/nodes/join_source.rb +20 -0
  262. data/lib/arel/nodes/matches.rb +18 -0
  263. data/lib/arel/nodes/named_function.rb +23 -0
  264. data/lib/arel/nodes/node.rb +51 -0
  265. data/lib/arel/nodes/node_expression.rb +13 -0
  266. data/lib/arel/nodes/ordering.rb +27 -0
  267. data/lib/arel/nodes/outer_join.rb +8 -0
  268. data/lib/arel/nodes/over.rb +15 -0
  269. data/lib/arel/nodes/regexp.rb +16 -0
  270. data/lib/arel/nodes/right_outer_join.rb +8 -0
  271. data/lib/arel/nodes/select_core.rb +67 -0
  272. data/lib/arel/nodes/select_statement.rb +41 -0
  273. data/lib/arel/nodes/sql_literal.rb +19 -0
  274. data/lib/arel/nodes/string_join.rb +11 -0
  275. data/lib/arel/nodes/table_alias.rb +31 -0
  276. data/lib/arel/nodes/terminal.rb +16 -0
  277. data/lib/arel/nodes/true.rb +16 -0
  278. data/lib/arel/nodes/unary.rb +44 -0
  279. data/lib/arel/nodes/unary_operation.rb +20 -0
  280. data/lib/arel/nodes/unqualified_column.rb +22 -0
  281. data/lib/arel/nodes/update_statement.rb +41 -0
  282. data/lib/arel/nodes/values_list.rb +9 -0
  283. data/lib/arel/nodes/window.rb +126 -0
  284. data/lib/arel/nodes/with.rb +11 -0
  285. data/lib/arel/nodes.rb +70 -0
  286. data/lib/arel/order_predications.rb +13 -0
  287. data/lib/arel/predications.rb +250 -0
  288. data/lib/arel/select_manager.rb +270 -0
  289. data/lib/arel/table.rb +118 -0
  290. data/lib/arel/tree_manager.rb +72 -0
  291. data/lib/arel/update_manager.rb +34 -0
  292. data/lib/arel/visitors/dot.rb +308 -0
  293. data/lib/arel/visitors/mysql.rb +93 -0
  294. data/lib/arel/visitors/postgresql.rb +120 -0
  295. data/lib/arel/visitors/sqlite.rb +38 -0
  296. data/lib/arel/visitors/to_sql.rb +899 -0
  297. data/lib/arel/visitors/visitor.rb +45 -0
  298. data/lib/arel/visitors.rb +13 -0
  299. data/lib/arel/window_predications.rb +9 -0
  300. data/lib/arel.rb +54 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  303. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  304. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  305. data/lib/rails/generators/active_record/migration.rb +19 -2
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +118 -32
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # ]
22
22
  #
23
23
  # # Get an array of hashes representing the result (column => value):
24
- # result.to_hash
24
+ # result.to_a
25
25
  # # => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
26
26
  # {"id" => 2, "title" => "title_2", "body" => "body_2"},
27
27
  # ...
@@ -43,6 +43,11 @@ module ActiveRecord
43
43
  @column_types = column_types
44
44
  end
45
45
 
46
+ # Returns true if this result set includes the column named +name+
47
+ def includes_column?(name)
48
+ @columns.include? name
49
+ end
50
+
46
51
  # Returns the number of elements in the rows array.
47
52
  def length
48
53
  @rows.length
@@ -60,13 +65,10 @@ module ActiveRecord
60
65
  end
61
66
  end
62
67
 
63
- # Returns an array of hashes representing each row record.
64
- def to_hash
65
- hash_rows
66
- end
67
-
68
68
  alias :map! :map
69
69
  alias :collect! :map
70
+ deprecate "map!": :map
71
+ deprecate "collect!": :map
70
72
 
71
73
  # Returns true if there are no records, otherwise false.
72
74
  def empty?
@@ -78,31 +80,41 @@ module ActiveRecord
78
80
  hash_rows
79
81
  end
80
82
 
83
+ alias :to_a :to_ary
84
+
81
85
  def [](idx)
82
86
  hash_rows[idx]
83
87
  end
84
88
 
85
- # Returns the first record from the rows collection.
86
- # If the rows collection is empty, returns +nil+.
87
- def first
88
- return nil if @rows.empty?
89
- Hash[@columns.zip(@rows.first)]
90
- end
91
-
92
89
  # Returns the last record from the rows collection.
93
- # If the rows collection is empty, returns +nil+.
94
- def last
95
- return nil if @rows.empty?
96
- Hash[@columns.zip(@rows.last)]
90
+ def last(n = nil)
91
+ n ? hash_rows.last(n) : hash_rows.last
97
92
  end
98
93
 
99
94
  def cast_values(type_overrides = {}) # :nodoc:
100
- types = columns.map { |name| column_type(name, type_overrides) }
101
- result = rows.map do |values|
102
- types.zip(values).map { |type, value| type.deserialize(value) }
103
- end
95
+ if columns.one?
96
+ # Separated to avoid allocating an array per row
104
97
 
105
- columns.one? ? result.map!(&:first) : result
98
+ type = if type_overrides.is_a?(Array)
99
+ type_overrides.first
100
+ else
101
+ column_type(columns.first, type_overrides)
102
+ end
103
+
104
+ rows.map do |(value)|
105
+ type.deserialize(value)
106
+ end
107
+ else
108
+ types = if type_overrides.is_a?(Array)
109
+ type_overrides
110
+ else
111
+ columns.map { |name| column_type(name, type_overrides) }
112
+ end
113
+
114
+ rows.map do |values|
115
+ Array.new(values.size) { |i| types[i].deserialize(values[i]) }
116
+ end
117
+ end
106
118
  end
107
119
 
108
120
  def initialize_copy(other)
@@ -113,7 +125,6 @@ module ActiveRecord
113
125
  end
114
126
 
115
127
  private
116
-
117
128
  def column_type(name, type_overrides = {})
118
129
  type_overrides.fetch(name) do
119
130
  column_types.fetch(name, Type.default_value)
@@ -125,23 +136,38 @@ module ActiveRecord
125
136
  begin
126
137
  # We freeze the strings to prevent them getting duped when
127
138
  # used as keys in ActiveRecord::Base's @attributes hash
128
- columns = @columns.map { |c| c.dup.freeze }
139
+ columns = @columns.map(&:-@)
140
+ length = columns.length
141
+ template = nil
142
+
129
143
  @rows.map { |row|
130
- # In the past we used Hash[columns.zip(row)]
131
- # though elegant, the verbose way is much more efficient
132
- # both time and memory wise cause it avoids a big array allocation
133
- # this method is called a lot and needs to be micro optimised
134
- hash = {}
135
-
136
- index = 0
137
- length = columns.length
138
-
139
- while index < length
140
- hash[columns[index]] = row[index]
141
- index += 1
144
+ if template
145
+ # We use transform_values to build subsequent rows from the
146
+ # hash of the first row. This is faster because we avoid any
147
+ # reallocs and in Ruby 2.7+ avoid hashing entirely.
148
+ index = -1
149
+ template.transform_values do
150
+ row[index += 1]
151
+ end
152
+ else
153
+ # In the past we used Hash[columns.zip(row)]
154
+ # though elegant, the verbose way is much more efficient
155
+ # both time and memory wise cause it avoids a big array allocation
156
+ # this method is called a lot and needs to be micro optimised
157
+ hash = {}
158
+
159
+ index = 0
160
+ while index < length
161
+ hash[columns[index]] = row[index]
162
+ index += 1
163
+ end
164
+
165
+ # It's possible to select the same column twice, in which case
166
+ # we can't use a template
167
+ template = hash if hash.length == length
168
+
169
+ hash
142
170
  end
143
-
144
- hash
145
171
  }
146
172
  end
147
173
  end
@@ -14,9 +14,9 @@ module ActiveRecord
14
14
  class RuntimeRegistry # :nodoc:
15
15
  extend ActiveSupport::PerThreadRegistry
16
16
 
17
- attr_accessor :connection_handler, :sql_runtime
17
+ attr_accessor :sql_runtime
18
18
 
19
- [:connection_handler, :sql_runtime].each do |val|
19
+ [:sql_runtime].each do |val|
20
20
  class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
21
21
  class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
22
22
  end
@@ -61,12 +61,13 @@ module ActiveRecord
61
61
  # # => "id ASC"
62
62
  def sanitize_sql_for_order(condition)
63
63
  if condition.is_a?(Array) && condition.first.to_s.include?("?")
64
- enforce_raw_sql_whitelist([condition.first],
65
- whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
64
+ disallow_raw_sql!(
65
+ [condition.first],
66
+ permit: connection.column_name_with_order_matcher
66
67
  )
67
68
 
68
69
  # Ensure we aren't dealing with a subclass of String that might
69
- # override methods we use (eg. Arel::Nodes::SqlLiteral).
70
+ # override methods we use (e.g. Arel::Nodes::SqlLiteral).
70
71
  if condition.first.kind_of?(String) && !condition.first.instance_of?(String)
71
72
  condition = [String.new(condition.first), *condition[1..-1]]
72
73
  end
@@ -133,44 +134,22 @@ module ActiveRecord
133
134
  end
134
135
  end
135
136
 
136
- private
137
- # Accepts a hash of SQL conditions and replaces those attributes
138
- # that correspond to a {#composed_of}[rdoc-ref:Aggregations::ClassMethods#composed_of]
139
- # relationship with their expanded aggregate attribute values.
140
- #
141
- # Given:
142
- #
143
- # class Person < ActiveRecord::Base
144
- # composed_of :address, class_name: "Address",
145
- # mapping: [%w(address_street street), %w(address_city city)]
146
- # end
147
- #
148
- # Then:
149
- #
150
- # { address: Address.new("813 abc st.", "chicago") }
151
- # # => { address_street: "813 abc st.", address_city: "chicago" }
152
- def expand_hash_conditions_for_aggregates(attrs) # :doc:
153
- expanded_attrs = {}
154
- attrs.each do |attr, value|
155
- if aggregation = reflect_on_aggregation(attr.to_sym)
156
- mapping = aggregation.mapping
157
- mapping.each do |field_attr, aggregate_attr|
158
- expanded_attrs[field_attr] = if value.is_a?(Array)
159
- value.map { |it| it.send(aggregate_attr) }
160
- elsif mapping.size == 1 && !value.respond_to?(aggregate_attr)
161
- value
162
- else
163
- value.send(aggregate_attr)
164
- end
165
- end
166
- else
167
- expanded_attrs[attr] = value
168
- end
169
- end
170
- expanded_attrs
137
+ def disallow_raw_sql!(args, permit: connection.column_name_matcher) # :nodoc:
138
+ unexpected = nil
139
+ args.each do |arg|
140
+ next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
141
+ (unexpected ||= []) << arg
171
142
  end
172
- deprecate :expand_hash_conditions_for_aggregates
173
143
 
144
+ if unexpected
145
+ raise(ActiveRecord::UnknownAttributeReference,
146
+ "Query method called with non-attribute argument(s): " +
147
+ unexpected.map(&:inspect).join(", ")
148
+ )
149
+ end
150
+ end
151
+
152
+ private
174
153
  def replace_bind_variables(statement, values)
175
154
  raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
176
155
  bound = values.dup
@@ -202,12 +181,14 @@ module ActiveRecord
202
181
 
203
182
  def quote_bound_value(value, c = connection)
204
183
  if value.respond_to?(:map) && !value.acts_like?(:string)
205
- if value.respond_to?(:empty?) && value.empty?
184
+ values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
185
+ if values.empty?
206
186
  c.quote(nil)
207
187
  else
208
- value.map { |v| c.quote(v) }.join(",")
188
+ values.map! { |v| c.quote(v) }.join(",")
209
189
  end
210
190
  else
191
+ value = value.id_for_database if value.respond_to?(:id_for_database)
211
192
  c.quote(value)
212
193
  end
213
194
  end
@@ -50,21 +50,12 @@ module ActiveRecord
50
50
  instance_eval(&block)
51
51
 
52
52
  if info[:version].present?
53
- ActiveRecord::SchemaMigration.create_table
54
- connection.assume_migrated_upto_version(info[:version], migrations_paths)
53
+ connection.schema_migration.create_table
54
+ connection.assume_migrated_upto_version(info[:version])
55
55
  end
56
56
 
57
57
  ActiveRecord::InternalMetadata.create_table
58
58
  ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
59
59
  end
60
-
61
- private
62
- # Returns the migrations paths.
63
- #
64
- # ActiveRecord::Schema.new.migrations_paths
65
- # # => ["db/migrate"] # Rails migration path by default.
66
- def migrations_paths
67
- ActiveRecord::Migrator.migrations_paths
68
- end
69
60
  end
70
61
  end
@@ -17,6 +17,18 @@ module ActiveRecord
17
17
  # Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
18
18
  cattr_accessor :ignore_tables, default: []
19
19
 
20
+ ##
21
+ # :singleton-method:
22
+ # Specify a custom regular expression matching foreign keys which name
23
+ # should not be dumped to db/schema.rb.
24
+ cattr_accessor :fk_ignore_pattern, default: /^fk_rails_[0-9a-f]{10}$/
25
+
26
+ ##
27
+ # :singleton-method:
28
+ # Specify a custom regular expression matching check constraints which name
29
+ # should not be dumped to db/schema.rb.
30
+ cattr_accessor :chk_ignore_pattern, default: /^chk_rails_[0-9a-f]{10}$/
31
+
20
32
  class << self
21
33
  def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
22
34
  connection.create_schema_dumper(generate_options(config)).dump(stream)
@@ -41,6 +53,7 @@ module ActiveRecord
41
53
  end
42
54
 
43
55
  private
56
+ attr_accessor :table_name
44
57
 
45
58
  def initialize(connection, options = {})
46
59
  @connection = connection
@@ -65,11 +78,11 @@ module ActiveRecord
65
78
  # of editing this file, please use the migrations feature of Active Record to
66
79
  # incrementally modify your database, and then regenerate this schema definition.
67
80
  #
68
- # Note that this schema.rb definition is the authoritative source for your
69
- # database schema. If you need to create the application database on another
70
- # system, you should be using db:schema:load, not running all the migrations
71
- # from scratch. The latter is a flawed and unsustainable approach (the more migrations
72
- # you'll amass, the slower it'll run and the greater likelihood for issues).
81
+ # This file is the source Rails uses to define your schema when running `bin/rails
82
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
83
+ # be faster and is potentially less error prone than running all of your
84
+ # migrations from scratch. Old migrations may fail to apply correctly if those
85
+ # migrations use external dependencies or application code.
73
86
  #
74
87
  # It's strongly recommended that you check this file into your version control system.
75
88
 
@@ -104,6 +117,8 @@ HEADER
104
117
  def table(table, stream)
105
118
  columns = @connection.columns(table)
106
119
  begin
120
+ self.table_name = table
121
+
107
122
  tbl = StringIO.new
108
123
 
109
124
  # first dump primary key column
@@ -116,7 +131,10 @@ HEADER
116
131
  tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
117
132
  pkcol = columns.detect { |c| c.name == pk }
118
133
  pkcolspec = column_spec_for_primary_key(pkcol)
119
- if pkcolspec.present?
134
+ unless pkcolspec.empty?
135
+ if pkcolspec != pkcolspec.slice(:id, :default)
136
+ pkcolspec = { id: { type: pkcolspec.delete(:id), **pkcolspec }.compact }
137
+ end
120
138
  tbl.print ", #{format_colspec(pkcolspec)}"
121
139
  end
122
140
  when Array
@@ -137,12 +155,17 @@ HEADER
137
155
  raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
138
156
  next if column.name == pk
139
157
  type, colspec = column_spec(column)
140
- tbl.print " t.#{type} #{column.name.inspect}"
158
+ if type.is_a?(Symbol)
159
+ tbl.print " t.#{type} #{column.name.inspect}"
160
+ else
161
+ tbl.print " t.column #{column.name.inspect}, #{type.inspect}"
162
+ end
141
163
  tbl.print ", #{format_colspec(colspec)}" if colspec.present?
142
164
  tbl.puts
143
165
  end
144
166
 
145
167
  indexes_in_create(table, tbl)
168
+ check_constraints_in_create(table, tbl) if @connection.supports_check_constraints?
146
169
 
147
170
  tbl.puts " end"
148
171
  tbl.puts
@@ -153,6 +176,8 @@ HEADER
153
176
  stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
154
177
  stream.puts "# #{e.message}"
155
178
  stream.puts
179
+ ensure
180
+ self.table_name = nil
156
181
  end
157
182
  end
158
183
 
@@ -194,6 +219,24 @@ HEADER
194
219
  index_parts
195
220
  end
196
221
 
222
+ def check_constraints_in_create(table, stream)
223
+ if (check_constraints = @connection.check_constraints(table)).any?
224
+ add_check_constraint_statements = check_constraints.map do |check_constraint|
225
+ parts = [
226
+ "t.check_constraint #{check_constraint.expression.inspect}"
227
+ ]
228
+
229
+ if check_constraint.export_name_on_schema_dump?
230
+ parts << "name: #{check_constraint.name.inspect}"
231
+ end
232
+
233
+ " #{parts.join(', ')}"
234
+ end
235
+
236
+ stream.puts add_check_constraint_statements.sort.join("\n")
237
+ end
238
+ end
239
+
197
240
  def foreign_keys(table, stream)
198
241
  if (foreign_keys = @connection.foreign_keys(table)).any?
199
242
  add_foreign_key_statements = foreign_keys.map do |foreign_key|
@@ -210,7 +253,7 @@ HEADER
210
253
  parts << "primary_key: #{foreign_key.primary_key.inspect}"
211
254
  end
212
255
 
213
- if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
256
+ if foreign_key.export_name_on_schema_dump?
214
257
  parts << "name: #{foreign_key.name.inspect}"
215
258
  end
216
259
 
@@ -225,7 +268,9 @@ HEADER
225
268
  end
226
269
 
227
270
  def format_colspec(colspec)
228
- colspec.map { |key, value| "#{key}: #{value}" }.join(", ")
271
+ colspec.map do |key, value|
272
+ "#{key}: #{ value.is_a?(Hash) ? "{ #{format_colspec(value)} }" : value }"
273
+ end.join(", ")
229
274
  end
230
275
 
231
276
  def format_options(options)
@@ -10,24 +10,22 @@ module ActiveRecord
10
10
  # to be executed the next time.
11
11
  class SchemaMigration < ActiveRecord::Base # :nodoc:
12
12
  class << self
13
+ def _internal?
14
+ true
15
+ end
16
+
13
17
  def primary_key
14
18
  "version"
15
19
  end
16
20
 
17
21
  def table_name
18
- "#{table_name_prefix}#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
19
- end
20
-
21
- def table_exists?
22
- connection.table_exists?(table_name)
22
+ "#{table_name_prefix}#{schema_migrations_table_name}#{table_name_suffix}"
23
23
  end
24
24
 
25
25
  def create_table
26
- unless table_exists?
27
- version_options = connection.internal_string_options_for_primary_key
28
-
26
+ unless connection.table_exists?(table_name)
29
27
  connection.create_table(table_name, id: false) do |t|
30
- t.string :version, version_options
28
+ t.string :version, **connection.internal_string_options_for_primary_key
31
29
  end
32
30
  end
33
31
  end
@@ -44,7 +44,6 @@ module ActiveRecord
44
44
  end
45
45
 
46
46
  private
47
-
48
47
  # Use this macro in your model to set a default scope for all operations on
49
48
  # the model.
50
49
  #
@@ -100,7 +99,7 @@ module ActiveRecord
100
99
  self.default_scopes += [scope]
101
100
  end
102
101
 
103
- def build_default_scope(base_rel = nil)
102
+ def build_default_scope(relation = relation())
104
103
  return if abstract_class?
105
104
 
106
105
  if default_scope_override.nil?
@@ -110,16 +109,13 @@ module ActiveRecord
110
109
  if default_scope_override
111
110
  # The user has defined their own default scope method, so call that
112
111
  evaluate_default_scope do
113
- if scope = default_scope
114
- (base_rel ||= relation).merge!(scope)
115
- end
112
+ relation.scoping { default_scope }
116
113
  end
117
114
  elsif default_scopes.any?
118
- base_rel ||= relation
119
115
  evaluate_default_scope do
120
- default_scopes.inject(base_rel) do |default_scope, scope|
116
+ default_scopes.inject(relation) do |default_scope, scope|
121
117
  scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
122
- default_scope.merge!(base_rel.instance_exec(&scope))
118
+ default_scope.instance_exec(&scope) || default_scope
123
119
  end
124
120
  end
125
121
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/array"
4
- require "active_support/core_ext/hash/except"
5
- require "active_support/core_ext/kernel/singleton_class"
6
-
7
3
  module ActiveRecord
8
4
  # = Active Record \Named \Scopes
9
5
  module Scoping
@@ -24,13 +20,13 @@ module ActiveRecord
24
20
  # You can define a scope that applies to all finders using
25
21
  # {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
26
22
  def all
27
- current_scope = self.current_scope
23
+ scope = current_scope
28
24
 
29
- if current_scope
30
- if self == current_scope.klass
31
- current_scope.clone
25
+ if scope
26
+ if self == scope.klass
27
+ scope.clone
32
28
  else
33
- relation.merge!(current_scope)
29
+ relation.merge!(scope)
34
30
  end
35
31
  else
36
32
  default_scoped
@@ -38,21 +34,20 @@ module ActiveRecord
38
34
  end
39
35
 
40
36
  def scope_for_association(scope = relation) # :nodoc:
41
- current_scope = self.current_scope
42
-
43
- if current_scope && current_scope.empty_scope?
37
+ if current_scope&.empty_scope?
44
38
  scope
45
39
  else
46
40
  default_scoped(scope)
47
41
  end
48
42
  end
49
43
 
50
- def default_scoped(scope = relation) # :nodoc:
44
+ # Returns a scope for the model with default scopes.
45
+ def default_scoped(scope = relation)
51
46
  build_default_scope(scope) || scope
52
47
  end
53
48
 
54
49
  def default_extensions # :nodoc:
55
- if scope = current_scope || build_default_scope
50
+ if scope = scope_for_association || build_default_scope
56
51
  scope.extensions
57
52
  else
58
53
  []
@@ -77,10 +72,6 @@ module ActiveRecord
77
72
  # <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, in effect,
78
73
  # represents the query <tt>Shirt.where(color: 'red')</tt>.
79
74
  #
80
- # You should always pass a callable object to the scopes defined
81
- # with #scope. This ensures that the scope is re-evaluated each
82
- # time it is called.
83
- #
84
75
  # Note that this is simply 'syntactic sugar' for defining an actual
85
76
  # class method:
86
77
  #
@@ -181,25 +172,27 @@ module ActiveRecord
181
172
  extension = Module.new(&block) if block
182
173
 
183
174
  if body.respond_to?(:to_proc)
184
- singleton_class.send(:define_method, name) do |*args|
185
- scope = all
186
- scope = scope._exec_scope(*args, &body)
175
+ singleton_class.define_method(name) do |*args|
176
+ scope = all._exec_scope(*args, &body)
187
177
  scope = scope.extending(extension) if extension
188
178
  scope
189
179
  end
190
180
  else
191
- singleton_class.send(:define_method, name) do |*args|
192
- scope = all
193
- scope = scope.scoping { body.call(*args) || scope }
181
+ singleton_class.define_method(name) do |*args|
182
+ scope = body.call(*args) || all
194
183
  scope = scope.extending(extension) if extension
195
184
  scope
196
185
  end
197
186
  end
187
+ singleton_class.send(:ruby2_keywords, name) if respond_to?(:ruby2_keywords, true)
198
188
 
199
189
  generate_relation_method(name)
200
190
  end
201
191
 
202
192
  private
193
+ def singleton_method_added(name)
194
+ generate_relation_method(name) if Kernel.respond_to?(name) && !ActiveRecord::Relation.method_defined?(name)
195
+ end
203
196
 
204
197
  def valid_scope_name?(name)
205
198
  if respond_to?(name, true) && logger
@@ -12,14 +12,6 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  module ClassMethods # :nodoc:
15
- def current_scope(skip_inherited_scope = false)
16
- ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
17
- end
18
-
19
- def current_scope=(scope)
20
- ScopeRegistry.set_value_for(:current_scope, self, scope)
21
- end
22
-
23
15
  # Collects attributes from scopes that should be applied when creating
24
16
  # an AR instance for the particular class this is called on.
25
17
  def scope_attributes
@@ -30,6 +22,14 @@ module ActiveRecord
30
22
  def scope_attributes?
31
23
  current_scope
32
24
  end
25
+
26
+ def current_scope(skip_inherited_scope = false)
27
+ ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
28
+ end
29
+
30
+ def current_scope=(scope)
31
+ ScopeRegistry.set_value_for(:current_scope, self, scope)
32
+ end
33
33
  end
34
34
 
35
35
  def populate_with_current_scope_attributes # :nodoc:
@@ -95,7 +95,6 @@ module ActiveRecord
95
95
  end
96
96
 
97
97
  private
98
-
99
98
  def raise_invalid_scope_type!(scope_type)
100
99
  if !VALID_SCOPE_TYPES.include?(scope_type)
101
100
  raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"