activerecord 4.2.11.3 → 6.0.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 (372) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +613 -1643
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +13 -12
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record.rb +41 -22
  8. data/lib/active_record/aggregations.rb +267 -251
  9. data/lib/active_record/association_relation.rb +11 -6
  10. data/lib/active_record/associations.rb +1737 -1597
  11. data/lib/active_record/associations/alias_tracker.rb +29 -35
  12. data/lib/active_record/associations/association.rb +125 -58
  13. data/lib/active_record/associations/association_scope.rb +103 -132
  14. data/lib/active_record/associations/belongs_to_association.rb +65 -60
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -40
  17. data/lib/active_record/associations/builder/belongs_to.rb +69 -55
  18. data/lib/active_record/associations/builder/collection_association.rb +10 -33
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +52 -66
  20. data/lib/active_record/associations/builder/has_many.rb +8 -4
  21. data/lib/active_record/associations/builder/has_one.rb +46 -5
  22. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  23. data/lib/active_record/associations/collection_association.rb +131 -287
  24. data/lib/active_record/associations/collection_proxy.rb +241 -146
  25. data/lib/active_record/associations/foreign_association.rb +10 -1
  26. data/lib/active_record/associations/has_many_association.rb +34 -97
  27. data/lib/active_record/associations/has_many_through_association.rb +60 -87
  28. data/lib/active_record/associations/has_one_association.rb +61 -49
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +137 -167
  31. data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +90 -92
  35. data/lib/active_record/associations/preloader/association.rb +90 -123
  36. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  37. data/lib/active_record/associations/singular_association.rb +18 -39
  38. data/lib/active_record/associations/through_association.rb +38 -18
  39. data/lib/active_record/attribute_assignment.rb +56 -183
  40. data/lib/active_record/attribute_decorators.rb +39 -15
  41. data/lib/active_record/attribute_methods.rb +120 -135
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -8
  43. data/lib/active_record/attribute_methods/dirty.rb +174 -144
  44. data/lib/active_record/attribute_methods/primary_key.rb +91 -83
  45. data/lib/active_record/attribute_methods/query.rb +6 -5
  46. data/lib/active_record/attribute_methods/read.rb +20 -76
  47. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
  49. data/lib/active_record/attribute_methods/write.rb +32 -54
  50. data/lib/active_record/attributes.rb +214 -82
  51. data/lib/active_record/autosave_association.rb +91 -37
  52. data/lib/active_record/base.rb +57 -45
  53. data/lib/active_record/callbacks.rb +100 -74
  54. data/lib/active_record/coders/json.rb +3 -1
  55. data/lib/active_record/coders/yaml_column.rb +24 -12
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +796 -296
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -115
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -23
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +356 -227
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +664 -243
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -83
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +460 -204
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +510 -635
  69. data/lib/active_record/connection_adapters/column.rb +56 -43
  70. data/lib/active_record/connection_adapters/connection_specification.rb +174 -152
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +58 -180
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -114
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  96. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  102. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  103. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +10 -5
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +470 -290
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +551 -356
  117. data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -345
  127. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  128. data/lib/active_record/connection_handling.rb +176 -41
  129. data/lib/active_record/core.rb +251 -231
  130. data/lib/active_record/counter_cache.rb +67 -49
  131. data/lib/active_record/database_configurations.rb +233 -0
  132. data/lib/active_record/database_configurations/database_config.rb +37 -0
  133. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  134. data/lib/active_record/database_configurations/url_config.rb +79 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +87 -105
  137. data/lib/active_record/enum.rb +163 -86
  138. data/lib/active_record/errors.rb +188 -53
  139. data/lib/active_record/explain.rb +23 -11
  140. data/lib/active_record/explain_registry.rb +4 -2
  141. data/lib/active_record/explain_subscriber.rb +10 -5
  142. data/lib/active_record/fixture_set/file.rb +35 -9
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +153 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  147. data/lib/active_record/fixtures.rb +228 -499
  148. data/lib/active_record/gem_version.rb +6 -4
  149. data/lib/active_record/inheritance.rb +158 -112
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +123 -29
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +21 -3
  154. data/lib/active_record/locale/en.yml +3 -2
  155. data/lib/active_record/locking/optimistic.rb +87 -96
  156. data/lib/active_record/locking/pessimistic.rb +18 -6
  157. data/lib/active_record/log_subscriber.rb +76 -33
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +621 -303
  162. data/lib/active_record/migration/command_recorder.rb +177 -90
  163. data/lib/active_record/migration/compatibility.rb +244 -0
  164. data/lib/active_record/migration/join_table.rb +8 -6
  165. data/lib/active_record/model_schema.rb +312 -112
  166. data/lib/active_record/nested_attributes.rb +264 -222
  167. data/lib/active_record/no_touching.rb +14 -1
  168. data/lib/active_record/null_relation.rb +24 -37
  169. data/lib/active_record/persistence.rb +557 -125
  170. data/lib/active_record/query_cache.rb +19 -23
  171. data/lib/active_record/querying.rb +43 -29
  172. data/lib/active_record/railtie.rb +143 -44
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +2 -0
  175. data/lib/active_record/railties/controller_runtime.rb +34 -33
  176. data/lib/active_record/railties/databases.rake +328 -185
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +428 -279
  179. data/lib/active_record/relation.rb +518 -341
  180. data/lib/active_record/relation/batches.rb +207 -55
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  182. data/lib/active_record/relation/calculations.rb +267 -253
  183. data/lib/active_record/relation/delegation.rb +70 -80
  184. data/lib/active_record/relation/finder_methods.rb +277 -241
  185. data/lib/active_record/relation/from_clause.rb +26 -0
  186. data/lib/active_record/relation/merger.rb +78 -87
  187. data/lib/active_record/relation/predicate_builder.rb +114 -119
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  195. data/lib/active_record/relation/query_attribute.rb +50 -0
  196. data/lib/active_record/relation/query_methods.rb +575 -394
  197. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  198. data/lib/active_record/relation/spawn_methods.rb +11 -13
  199. data/lib/active_record/relation/where_clause.rb +190 -0
  200. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  201. data/lib/active_record/result.rb +79 -42
  202. data/lib/active_record/runtime_registry.rb +6 -4
  203. data/lib/active_record/sanitization.rb +144 -121
  204. data/lib/active_record/schema.rb +21 -24
  205. data/lib/active_record/schema_dumper.rb +112 -93
  206. data/lib/active_record/schema_migration.rb +24 -17
  207. data/lib/active_record/scoping.rb +45 -26
  208. data/lib/active_record/scoping/default.rb +101 -85
  209. data/lib/active_record/scoping/named.rb +86 -33
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +5 -5
  212. data/lib/active_record/statement_cache.rb +73 -36
  213. data/lib/active_record/store.rb +127 -42
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +75 -0
  216. data/lib/active_record/tasks/database_tasks.rb +307 -100
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +55 -99
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -41
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +38 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +224 -0
  222. data/lib/active_record/timestamp.rb +86 -40
  223. data/lib/active_record/touch_later.rb +66 -0
  224. data/lib/active_record/transactions.rb +216 -150
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type.rb +78 -23
  227. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  228. data/lib/active_record/type/date.rb +4 -45
  229. data/lib/active_record/type/date_time.rb +4 -49
  230. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  231. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  232. data/lib/active_record/type/internal/timezone.rb +17 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +24 -15
  235. data/lib/active_record/type/text.rb +2 -2
  236. data/lib/active_record/type/time.rb +11 -16
  237. data/lib/active_record/type/type_map.rb +15 -17
  238. data/lib/active_record/type/unsigned_integer.rb +9 -7
  239. data/lib/active_record/type_caster.rb +9 -0
  240. data/lib/active_record/type_caster/connection.rb +34 -0
  241. data/lib/active_record/type_caster/map.rb +20 -0
  242. data/lib/active_record/validations.rb +39 -35
  243. data/lib/active_record/validations/absence.rb +25 -0
  244. data/lib/active_record/validations/associated.rb +13 -4
  245. data/lib/active_record/validations/length.rb +26 -0
  246. data/lib/active_record/validations/presence.rb +14 -13
  247. data/lib/active_record/validations/uniqueness.rb +42 -55
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/arel.rb +51 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +257 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +204 -0
  317. data/lib/arel/visitors/dot.rb +297 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +157 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +159 -0
  323. data/lib/arel/visitors/oracle12.rb +66 -0
  324. data/lib/arel/visitors/postgresql.rb +110 -0
  325. data/lib/arel/visitors/sqlite.rb +39 -0
  326. data/lib/arel/visitors/to_sql.rb +889 -0
  327. data/lib/arel/visitors/visitor.rb +46 -0
  328. data/lib/arel/visitors/where_sql.rb +23 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +7 -5
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration.rb +31 -1
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +42 -37
  335. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  336. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -2
  337. data/lib/rails/generators/active_record/model/model_generator.rb +19 -22
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  340. metadata +164 -59
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -163
  349. data/lib/active_record/attribute_set.rb +0 -81
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  352. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  353. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  354. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  355. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  356. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  359. data/lib/active_record/type/big_integer.rb +0 -13
  360. data/lib/active_record/type/binary.rb +0 -50
  361. data/lib/active_record/type/boolean.rb +0 -31
  362. data/lib/active_record/type/decimal.rb +0 -64
  363. data/lib/active_record/type/decorator.rb +0 -14
  364. data/lib/active_record/type/float.rb +0 -19
  365. data/lib/active_record/type/integer.rb +0 -59
  366. data/lib/active_record/type/mutable.rb +0 -16
  367. data/lib/active_record/type/numeric.rb +0 -36
  368. data/lib/active_record/type/string.rb +0 -40
  369. data/lib/active_record/type/time_value.rb +0 -38
  370. data/lib/active_record/type/value.rb +0 -110
  371. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  372. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,40 +1,61 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
- class StatementPool
5
+ class StatementPool # :nodoc:
4
6
  include Enumerable
5
7
 
6
- def initialize(connection, max = 1000)
7
- @connection = connection
8
- @max = max
8
+ DEFAULT_STATEMENT_LIMIT = 1000
9
+
10
+ def initialize(statement_limit = nil)
11
+ @cache = Hash.new { |h, pid| h[pid] = {} }
12
+ @statement_limit = statement_limit || DEFAULT_STATEMENT_LIMIT
9
13
  end
10
14
 
11
- def each
12
- raise NotImplementedError
15
+ def each(&block)
16
+ cache.each(&block)
13
17
  end
14
18
 
15
19
  def key?(key)
16
- raise NotImplementedError
20
+ cache.key?(key)
17
21
  end
18
22
 
19
23
  def [](key)
20
- raise NotImplementedError
24
+ cache[key]
21
25
  end
22
26
 
23
27
  def length
24
- raise NotImplementedError
28
+ cache.length
25
29
  end
26
30
 
27
- def []=(sql, key)
28
- raise NotImplementedError
31
+ def []=(sql, stmt)
32
+ while @statement_limit <= cache.size
33
+ dealloc(cache.shift.last)
34
+ end
35
+ cache[sql] = stmt
29
36
  end
30
37
 
31
38
  def clear
32
- raise NotImplementedError
39
+ cache.each_value do |stmt|
40
+ dealloc stmt
41
+ end
42
+ cache.clear
33
43
  end
34
44
 
35
45
  def delete(key)
36
- raise NotImplementedError
46
+ dealloc cache[key]
47
+ cache.delete(key)
37
48
  end
49
+
50
+ private
51
+
52
+ def cache
53
+ @cache[Process.pid]
54
+ end
55
+
56
+ def dealloc(stmt)
57
+ raise NotImplementedError
58
+ end
38
59
  end
39
60
  end
40
61
  end
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionHandling
3
- RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
5
+ RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
4
6
  DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
5
7
 
6
8
  # Establishes the connection to the database. Accepts a hash as input where
7
9
  # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
8
- # example for regular databases (MySQL, Postgresql, etc):
10
+ # example for regular databases (MySQL, PostgreSQL, etc):
9
11
  #
10
12
  # ActiveRecord::Base.establish_connection(
11
- # adapter: "mysql",
13
+ # adapter: "mysql2",
12
14
  # host: "localhost",
13
15
  # username: "myuser",
14
16
  # password: "mypass",
@@ -35,49 +37,159 @@ module ActiveRecord
35
37
  # "postgres://myuser:mypass@localhost/somedatabase"
36
38
  # )
37
39
  #
38
- # In case <tt>ActiveRecord::Base.configurations</tt> is set (Rails
39
- # automatically loads the contents of config/database.yml into it),
40
+ # In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
41
+ # is set (Rails automatically loads the contents of config/database.yml into it),
40
42
  # a symbol can also be given as argument, representing a key in the
41
43
  # configuration hash:
42
44
  #
43
45
  # ActiveRecord::Base.establish_connection(:production)
44
46
  #
45
- # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
47
+ # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
46
48
  # may be returned on an error.
47
- def establish_connection(spec = nil)
48
- spec ||= DEFAULT_ENV.call.to_sym
49
- resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations
50
- spec = resolver.spec(spec)
49
+ def establish_connection(config_or_env = nil)
50
+ config_hash = resolve_config_for_connection(config_or_env)
51
+ connection_handler.establish_connection(config_hash)
52
+ end
53
+
54
+ # Connects a model to the databases specified. The +database+ keyword
55
+ # takes a hash consisting of a +role+ and a +database_key+.
56
+ #
57
+ # This will create a connection handler for switching between connections,
58
+ # look up the config hash using the +database_key+ and finally
59
+ # establishes a connection to that config.
60
+ #
61
+ # class AnimalsModel < ApplicationRecord
62
+ # self.abstract_class = true
63
+ #
64
+ # connects_to database: { writing: :primary, reading: :primary_replica }
65
+ # end
66
+ #
67
+ # Returns an array of established connections.
68
+ def connects_to(database: {})
69
+ connections = []
70
+
71
+ database.each do |role, database_key|
72
+ config_hash = resolve_config_for_connection(database_key)
73
+ handler = lookup_connection_handler(role.to_sym)
51
74
 
52
- unless respond_to?(spec.adapter_method)
53
- raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
75
+ connections << handler.establish_connection(config_hash)
54
76
  end
55
77
 
56
- remove_connection
57
- connection_handler.establish_connection self, spec
78
+ connections
58
79
  end
59
80
 
60
- class MergeAndResolveDefaultUrlConfig # :nodoc:
61
- def initialize(raw_configurations)
62
- @raw_config = raw_configurations.dup
63
- @env = DEFAULT_ENV.call.to_s
64
- end
81
+ # Connects to a database or role (ex writing, reading, or another
82
+ # custom role) for the duration of the block.
83
+ #
84
+ # If a role is passed, Active Record will look up the connection
85
+ # based on the requested role:
86
+ #
87
+ # ActiveRecord::Base.connected_to(role: :writing) do
88
+ # Dog.create! # creates dog using dog writing connection
89
+ # end
90
+ #
91
+ # ActiveRecord::Base.connected_to(role: :reading) do
92
+ # Dog.create! # throws exception because we're on a replica
93
+ # end
94
+ #
95
+ # ActiveRecord::Base.connected_to(role: :unknown_role) do
96
+ # # raises exception due to non-existent role
97
+ # end
98
+ #
99
+ # For cases where you may want to connect to a database outside of the model,
100
+ # you can use +connected_to+ with a +database+ argument. The +database+ argument
101
+ # expects a symbol that corresponds to the database key in your config.
102
+ #
103
+ # ActiveRecord::Base.connected_to(database: :animals_slow_replica) do
104
+ # Dog.run_a_long_query # runs a long query while connected to the +animals_slow_replica+
105
+ # end
106
+ #
107
+ # This will connect to a new database for the queries inside the block. By
108
+ # default the `:writing` role will be used since all connections must be assigned
109
+ # a role. If you would like to use a different role you can pass a hash to database:
110
+ #
111
+ # ActiveRecord::Base.connected_to(database: { readonly_slow: :animals_slow_replica }) do
112
+ # # runs a long query while connected to the +animals_slow_replica+ using the readonly_slow role.
113
+ # Dog.run_a_long_query
114
+ # end
115
+ #
116
+ # When using the database key a new connection will be established every time.
117
+ def connected_to(database: nil, role: nil, &blk)
118
+ if database && role
119
+ raise ArgumentError, "connected_to can only accept a `database` or a `role` argument, but not both arguments."
120
+ elsif database
121
+ if database.is_a?(Hash)
122
+ role, database = database.first
123
+ role = role.to_sym
124
+ end
125
+
126
+ config_hash = resolve_config_for_connection(database)
127
+ handler = lookup_connection_handler(role)
128
+
129
+ handler.establish_connection(config_hash)
65
130
 
66
- # Returns fully resolved connection hashes.
67
- # Merges connection information from `ENV['DATABASE_URL']` if available.
68
- def resolve
69
- ConnectionAdapters::ConnectionSpecification::Resolver.new(config).resolve_all
131
+ with_handler(role, &blk)
132
+ elsif role
133
+ with_handler(role.to_sym, &blk)
134
+ else
135
+ raise ArgumentError, "must provide a `database` or a `role`."
70
136
  end
137
+ end
138
+
139
+ # Returns true if role is the current connected role.
140
+ #
141
+ # ActiveRecord::Base.connected_to(role: :writing) do
142
+ # ActiveRecord::Base.connected_to?(role: :writing) #=> true
143
+ # ActiveRecord::Base.connected_to?(role: :reading) #=> false
144
+ # end
145
+ def connected_to?(role:)
146
+ current_role == role.to_sym
147
+ end
148
+
149
+ # Returns the symbol representing the current connected role.
150
+ #
151
+ # ActiveRecord::Base.connected_to(role: :writing) do
152
+ # ActiveRecord::Base.current_role #=> :writing
153
+ # end
154
+ #
155
+ # ActiveRecord::Base.connected_to(role: :reading) do
156
+ # ActiveRecord::Base.current_role #=> :reading
157
+ # end
158
+ def current_role
159
+ connection_handlers.key(connection_handler)
160
+ end
161
+
162
+ def lookup_connection_handler(handler_key) # :nodoc:
163
+ handler_key ||= ActiveRecord::Base.writing_role
164
+ connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
165
+ end
166
+
167
+ def with_handler(handler_key, &blk) # :nodoc:
168
+ handler = lookup_connection_handler(handler_key)
169
+ swap_connection_handler(handler, &blk)
170
+ end
171
+
172
+ def resolve_config_for_connection(config_or_env) # :nodoc:
173
+ raise "Anonymous class is not allowed." unless name
174
+
175
+ config_or_env ||= DEFAULT_ENV.call.to_sym
176
+ pool_name = primary_class? ? "primary" : name
177
+ self.connection_specification_name = pool_name
71
178
 
72
- private
73
- def config
74
- @raw_config.dup.tap do |cfg|
75
- if url = ENV['DATABASE_URL']
76
- cfg[@env] ||= {}
77
- cfg[@env]["url"] ||= url
78
- end
79
- end
179
+ resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations)
180
+ config_hash = resolver.resolve(config_or_env, pool_name).symbolize_keys
181
+ config_hash[:name] = pool_name
182
+
183
+ config_hash
184
+ end
185
+
186
+ # Clears the query cache for all connections associated with the current thread.
187
+ def clear_query_caches_for_current_thread
188
+ ActiveRecord::Base.connection_handlers.each_value do |handler|
189
+ handler.connection_pool_list.each do |pool|
190
+ pool.connection.clear_query_cache if pool.active_connection?
80
191
  end
192
+ end
81
193
  end
82
194
 
83
195
  # Returns the connection currently associated with the class. This can
@@ -87,12 +199,18 @@ module ActiveRecord
87
199
  retrieve_connection
88
200
  end
89
201
 
90
- def connection_id
91
- ActiveRecord::RuntimeRegistry.connection_id
202
+ attr_writer :connection_specification_name
203
+
204
+ # Return the specification name from the current class or its parent.
205
+ def connection_specification_name
206
+ if !defined?(@connection_specification_name) || @connection_specification_name.nil?
207
+ return primary_class? ? "primary" : superclass.connection_specification_name
208
+ end
209
+ @connection_specification_name
92
210
  end
93
211
 
94
- def connection_id=(connection_id)
95
- ActiveRecord::RuntimeRegistry.connection_id = connection_id
212
+ def primary_class? # :nodoc:
213
+ self == Base || defined?(ApplicationRecord) && self == ApplicationRecord
96
214
  end
97
215
 
98
216
  # Returns the configuration of the associated connection as a hash:
@@ -106,20 +224,28 @@ module ActiveRecord
106
224
  end
107
225
 
108
226
  def connection_pool
109
- connection_handler.retrieve_connection_pool(self) or raise ConnectionNotEstablished
227
+ connection_handler.retrieve_connection_pool(connection_specification_name) || raise(ConnectionNotEstablished)
110
228
  end
111
229
 
112
230
  def retrieve_connection
113
- connection_handler.retrieve_connection(self)
231
+ connection_handler.retrieve_connection(connection_specification_name)
114
232
  end
115
233
 
116
234
  # Returns +true+ if Active Record is connected.
117
235
  def connected?
118
- connection_handler.connected?(self)
236
+ connection_handler.connected?(connection_specification_name)
119
237
  end
120
238
 
121
- def remove_connection(klass = self)
122
- connection_handler.remove_connection(klass)
239
+ def remove_connection(name = nil)
240
+ name ||= @connection_specification_name if defined?(@connection_specification_name)
241
+ # if removing a connection that has a pool, we reset the
242
+ # connection_specification_name so it will use the parent
243
+ # pool.
244
+ if connection_handler.retrieve_connection_pool(name)
245
+ self.connection_specification_name = nil
246
+ end
247
+
248
+ connection_handler.remove_connection(name)
123
249
  end
124
250
 
125
251
  def clear_cache! # :nodoc:
@@ -127,6 +253,15 @@ module ActiveRecord
127
253
  end
128
254
 
129
255
  delegate :clear_active_connections!, :clear_reloadable_connections!,
130
- :clear_all_connections!, :to => :connection_handler
256
+ :clear_all_connections!, :flush_idle_connections!, to: :connection_handler
257
+
258
+ private
259
+
260
+ def swap_connection_handler(handler, &blk) # :nodoc:
261
+ old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
262
+ yield
263
+ ensure
264
+ ActiveRecord::Base.connection_handler = old_handler
265
+ end
131
266
  end
132
267
  end
@@ -1,7 +1,9 @@
1
- require 'thread'
2
- require 'active_support/core_ext/hash/indifferent_access'
3
- require 'active_support/core_ext/object/duplicable'
4
- require 'active_support/core_ext/string/filters'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/indifferent_access"
4
+ require "active_support/core_ext/string/filters"
5
+ require "active_support/parameter_filter"
6
+ require "concurrent/map"
5
7
 
6
8
  module ActiveRecord
7
9
  module Core
@@ -16,9 +18,16 @@ module ActiveRecord
16
18
  # retrieved on both a class and instance level by calling +logger+.
17
19
  mattr_accessor :logger, instance_writer: false
18
20
 
21
+ ##
22
+ # :singleton-method:
23
+ #
24
+ # Specifies if the methods calling database queries should be logged below
25
+ # their relevant queries. Defaults to false.
26
+ mattr_accessor :verbose_query_logs, instance_writer: false, default: false
27
+
19
28
  ##
20
29
  # Contains the database configuration - as is typically stored in config/database.yml -
21
- # as a Hash.
30
+ # as an ActiveRecord::DatabaseConfigurations object.
22
31
  #
23
32
  # For example, the following database.yml...
24
33
  #
@@ -32,22 +41,18 @@ module ActiveRecord
32
41
  #
33
42
  # ...would result in ActiveRecord::Base.configurations to look like this:
34
43
  #
35
- # {
36
- # 'development' => {
37
- # 'adapter' => 'sqlite3',
38
- # 'database' => 'db/development.sqlite3'
39
- # },
40
- # 'production' => {
41
- # 'adapter' => 'sqlite3',
42
- # 'database' => 'db/production.sqlite3'
43
- # }
44
- # }
44
+ # #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
45
+ # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
46
+ # @spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>,
47
+ # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
48
+ # @spec_name="primary", @config={"adapter"=>"mysql2", "database"=>"db/production.sqlite3"}>
49
+ # ]>
45
50
  def self.configurations=(config)
46
- @@configurations = ActiveRecord::ConnectionHandling::MergeAndResolveDefaultUrlConfig.new(config).resolve
51
+ @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
47
52
  end
48
53
  self.configurations = {}
49
54
 
50
- # Returns fully resolved configurations hash
55
+ # Returns fully resolved ActiveRecord::DatabaseConfigurations object
51
56
  def self.configurations
52
57
  @@configurations
53
58
  end
@@ -56,8 +61,7 @@ module ActiveRecord
56
61
  # :singleton-method:
57
62
  # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
58
63
  # dates and times from the database. This is set to :utc by default.
59
- mattr_accessor :default_timezone, instance_writer: false
60
- self.default_timezone = :utc
64
+ mattr_accessor :default_timezone, instance_writer: false, default: :utc
61
65
 
62
66
  ##
63
67
  # :singleton-method:
@@ -67,58 +71,85 @@ module ActiveRecord
67
71
  # ActiveRecord::Schema file which can be loaded into any database that
68
72
  # supports migrations. Use :ruby if you want to have different database
69
73
  # adapters for, e.g., your development and test environments.
70
- mattr_accessor :schema_format, instance_writer: false
71
- self.schema_format = :ruby
74
+ mattr_accessor :schema_format, instance_writer: false, default: :ruby
75
+
76
+ ##
77
+ # :singleton-method:
78
+ # Specifies if an error should be raised if the query has an order being
79
+ # ignored when doing batch queries. Useful in applications where the
80
+ # scope being ignored is error-worthy, rather than a warning.
81
+ mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
82
+
83
+ # :singleton-method:
84
+ # Specify the behavior for unsafe raw query methods. Values are as follows
85
+ # deprecated - Warnings are logged when unsafe raw SQL is passed to
86
+ # query methods.
87
+ # disabled - Unsafe raw SQL passed to query methods results in
88
+ # UnknownAttributeReference exception.
89
+ mattr_accessor :allow_unsafe_raw_sql, instance_writer: false, default: :deprecated
72
90
 
73
91
  ##
74
92
  # :singleton-method:
75
93
  # Specify whether or not to use timestamps for migration versions
76
- mattr_accessor :timestamped_migrations, instance_writer: false
77
- self.timestamped_migrations = true
94
+ mattr_accessor :timestamped_migrations, instance_writer: false, default: true
78
95
 
79
96
  ##
80
97
  # :singleton-method:
81
98
  # Specify whether schema dump should happen at the end of the
82
- # db:migrate rake task. This is true by default, which is useful for the
99
+ # db:migrate rails command. This is true by default, which is useful for the
83
100
  # development environment. This should ideally be false in the production
84
101
  # environment where dumping schema is rarely needed.
85
- mattr_accessor :dump_schema_after_migration, instance_writer: false
86
- self.dump_schema_after_migration = true
102
+ mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
103
+
104
+ ##
105
+ # :singleton-method:
106
+ # Specifies which database schemas to dump when calling db:structure:dump.
107
+ # If the value is :schema_search_path (the default), any schemas listed in
108
+ # schema_search_path are dumped. Use :all to dump all schemas regardless
109
+ # of schema_search_path, or a string of comma separated schemas for a
110
+ # custom list.
111
+ mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
112
+
113
+ ##
114
+ # :singleton-method:
115
+ # Specify a threshold for the size of query result sets. If the number of
116
+ # records in the set exceeds the threshold, a warning is logged. This can
117
+ # be used to identify queries which load thousands of records and
118
+ # potentially cause memory bloat.
119
+ mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
87
120
 
88
121
  mattr_accessor :maintain_test_schema, instance_accessor: false
89
122
 
90
- def self.disable_implicit_join_references=(value)
91
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
92
- Implicit join references were removed with Rails 4.1.
93
- Make sure to remove this configuration because it does nothing.
94
- MSG
95
- end
123
+ mattr_accessor :belongs_to_required_by_default, instance_accessor: false
124
+
125
+ mattr_accessor :connection_handlers, instance_accessor: false, default: {}
126
+
127
+ mattr_accessor :writing_role, instance_accessor: false, default: :writing
128
+
129
+ mattr_accessor :reading_role, instance_accessor: false, default: :reading
96
130
 
97
131
  class_attribute :default_connection_handler, instance_writer: false
98
- class_attribute :find_by_statement_cache
132
+
133
+ self.filter_attributes = []
99
134
 
100
135
  def self.connection_handler
101
- ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
136
+ Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
102
137
  end
103
138
 
104
139
  def self.connection_handler=(handler)
105
- ActiveRecord::RuntimeRegistry.connection_handler = handler
140
+ Thread.current.thread_variable_set("ar_connection_handler", handler)
106
141
  end
107
142
 
108
143
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
109
144
  end
110
145
 
111
146
  module ClassMethods
112
- def allocate
113
- define_attribute_methods
114
- super
115
- end
116
-
117
147
  def initialize_find_by_cache # :nodoc:
118
- self.find_by_statement_cache = {}.extend(Mutex_m)
148
+ @find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
119
149
  end
120
150
 
121
151
  def inherited(child_class) # :nodoc:
152
+ # initialize cache at class definition for thread safety
122
153
  child_class.initialize_find_by_cache
123
154
  super
124
155
  end
@@ -126,90 +157,88 @@ module ActiveRecord
126
157
  def find(*ids) # :nodoc:
127
158
  # We don't have cache keys for this stuff yet
128
159
  return super unless ids.length == 1
129
- # Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
130
- return super if ids.first.kind_of?(Symbol)
131
160
  return super if block_given? ||
132
161
  primary_key.nil? ||
133
- default_scopes.any? ||
134
- current_scope ||
135
- columns_hash.include?(inheritance_column) ||
136
- ids.first.kind_of?(Array)
137
-
138
- id = ids.first
139
- if ActiveRecord::Base === id
140
- id = id.id
141
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
142
- You are passing an instance of ActiveRecord::Base to `find`.
143
- Please pass the id of the object by calling `.id`
144
- MSG
145
- end
162
+ scope_attributes? ||
163
+ columns_hash.key?(inheritance_column) && !base_class?
164
+
165
+ id = ids.first
166
+
167
+ return super if StatementCache.unsupported_value?(id)
168
+
146
169
  key = primary_key
147
170
 
148
- s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
149
- find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
150
- where(key => params.bind).limit(1)
151
- }
171
+ statement = cached_find_by_statement(key) { |params|
172
+ where(key => params.bind).limit(1)
152
173
  }
153
- record = s.execute([id], self, connection).first
174
+
175
+ record = statement.execute([id], connection)&.first
154
176
  unless record
155
- raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
177
+ raise RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id)
156
178
  end
157
179
  record
158
- rescue RangeError
159
- raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
160
180
  end
161
181
 
162
182
  def find_by(*args) # :nodoc:
163
- return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
164
- return super if default_scopes.any?
183
+ return super if scope_attributes? || reflect_on_all_aggregations.any? ||
184
+ columns_hash.key?(inheritance_column) && !base_class?
165
185
 
166
186
  hash = args.first
167
187
 
168
- return super if hash.values.any? { |v|
169
- v.nil? || Array === v || Hash === v
188
+ return super if !(Hash === hash) || hash.values.any? { |v|
189
+ StatementCache.unsupported_value?(v)
170
190
  }
171
191
 
172
192
  # We can't cache Post.find_by(author: david) ...yet
173
193
  return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
174
194
 
175
- key = hash.keys
195
+ keys = hash.keys
176
196
 
177
- klass = self
178
- s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
179
- find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
180
- wheres = key.each_with_object({}) { |param,o|
181
- o[param] = params.bind
182
- }
183
- klass.where(wheres).limit(1)
197
+ statement = cached_find_by_statement(keys) { |params|
198
+ wheres = keys.each_with_object({}) { |param, o|
199
+ o[param] = params.bind
184
200
  }
201
+ where(wheres).limit(1)
185
202
  }
186
203
  begin
187
- s.execute(hash.values, self, connection).first
188
- rescue TypeError => e
189
- raise ActiveRecord::StatementInvalid.new(e.message, e)
190
- rescue RangeError
191
- nil
204
+ statement.execute(hash.values, connection)&.first
205
+ rescue TypeError
206
+ raise ActiveRecord::StatementInvalid
192
207
  end
193
208
  end
194
209
 
195
210
  def find_by!(*args) # :nodoc:
196
- find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
211
+ find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
197
212
  end
198
213
 
199
214
  def initialize_generated_modules # :nodoc:
200
215
  generated_association_methods
201
216
  end
202
217
 
203
- def generated_association_methods
218
+ def generated_association_methods # :nodoc:
204
219
  @generated_association_methods ||= begin
205
220
  mod = const_set(:GeneratedAssociationMethods, Module.new)
221
+ private_constant :GeneratedAssociationMethods
206
222
  include mod
223
+
207
224
  mod
208
225
  end
209
226
  end
210
227
 
228
+ # Returns columns which shouldn't be exposed while calling +#inspect+.
229
+ def filter_attributes
230
+ if defined?(@filter_attributes)
231
+ @filter_attributes
232
+ else
233
+ superclass.filter_attributes
234
+ end
235
+ end
236
+
237
+ # Specifies columns which shouldn't be exposed while calling +#inspect+.
238
+ attr_writer :filter_attributes
239
+
211
240
  # Returns a string like 'Post(id:integer, title:string, body:text)'
212
- def inspect
241
+ def inspect # :nodoc:
213
242
  if self == Base
214
243
  super
215
244
  elsif abstract_class?
@@ -217,48 +246,66 @@ module ActiveRecord
217
246
  elsif !connected?
218
247
  "#{super} (call '#{super}.connection' to establish a connection)"
219
248
  elsif table_exists?
220
- attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
249
+ attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
221
250
  "#{super}(#{attr_list})"
222
251
  else
223
252
  "#{super}(Table doesn't exist)"
224
253
  end
225
254
  end
226
255
 
227
- # Overwrite the default class equality method to provide support for association proxies.
228
- def ===(object)
256
+ # Overwrite the default class equality method to provide support for decorated models.
257
+ def ===(object) # :nodoc:
229
258
  object.is_a?(self)
230
259
  end
231
260
 
232
261
  # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
233
262
  #
234
263
  # class Post < ActiveRecord::Base
235
- # scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
264
+ # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
236
265
  # end
237
266
  def arel_table # :nodoc:
238
- @arel_table ||= Arel::Table.new(table_name, arel_engine)
267
+ @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
239
268
  end
240
269
 
241
- # Returns the Arel engine.
242
- def arel_engine # :nodoc:
243
- @arel_engine ||=
244
- if Base == self || connection_handler.retrieve_connection_pool(self)
245
- self
246
- else
247
- superclass.arel_engine
248
- end
270
+ def arel_attribute(name, table = arel_table) # :nodoc:
271
+ name = name.to_s
272
+ name = attribute_aliases[name] || name
273
+ table[name]
274
+ end
275
+
276
+ def predicate_builder # :nodoc:
277
+ @predicate_builder ||= PredicateBuilder.new(table_metadata)
278
+ end
279
+
280
+ def type_caster # :nodoc:
281
+ TypeCaster::Map.new(self)
282
+ end
283
+
284
+ def _internal? # :nodoc:
285
+ false
249
286
  end
250
287
 
251
288
  private
252
289
 
253
- def relation #:nodoc:
254
- relation = Relation.create(self, arel_table)
290
+ def cached_find_by_statement(key, &block)
291
+ cache = @find_by_statement_cache[connection.prepared_statements]
292
+ cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
293
+ end
255
294
 
256
- if finder_needs_type_condition?
257
- relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
258
- else
259
- relation
295
+ def relation
296
+ relation = Relation.create(self)
297
+
298
+ if finder_needs_type_condition? && !ignore_default_scope?
299
+ relation.where!(type_condition)
300
+ relation.create_with!(inheritance_column.to_s => sti_name)
301
+ else
302
+ relation
303
+ end
304
+ end
305
+
306
+ def table_metadata
307
+ TableMetadata.new(self, arel_table)
260
308
  end
261
- end
262
309
  end
263
310
 
264
311
  # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -269,16 +316,14 @@ module ActiveRecord
269
316
  # ==== Example:
270
317
  # # Instantiates a single new object
271
318
  # User.new(first_name: 'Jamie')
272
- def initialize(attributes = nil, options = {})
273
- @attributes = self.class._default_attributes.dup
274
- self.class.define_attribute_methods
319
+ def initialize(attributes = nil)
320
+ @new_record = true
321
+ @attributes = self.class._default_attributes.deep_dup
275
322
 
276
323
  init_internals
277
324
  initialize_internals_callback
278
325
 
279
- # +options+ argument is only needed to make protected_attributes gem easier to hook.
280
- # Remove it when we drop support to this gem.
281
- init_attributes(attributes, options) if attributes
326
+ assign_attributes(attributes) if attributes
282
327
 
283
328
  yield self if block_given?
284
329
  _run_initialize_callbacks
@@ -286,7 +331,7 @@ module ActiveRecord
286
331
 
287
332
  # Initialize an empty model object from +coder+. +coder+ should be
288
333
  # the result of previously encoding an Active Record model, using
289
- # `encode_with`
334
+ # #encode_with.
290
335
  #
291
336
  # class Post < ActiveRecord::Base
292
337
  # end
@@ -298,15 +343,23 @@ module ActiveRecord
298
343
  # post = Post.allocate
299
344
  # post.init_with(coder)
300
345
  # post.title # => 'hello world'
301
- def init_with(coder)
346
+ def init_with(coder, &block)
302
347
  coder = LegacyYamlAdapter.convert(self.class, coder)
303
- @attributes = coder['attributes']
348
+ attributes = self.class.yaml_encoder.decode(coder)
349
+ init_with_attributes(attributes, coder["new_record"], &block)
350
+ end
304
351
 
305
- init_internals
352
+ ##
353
+ # Initialize an empty model object from +attributes+.
354
+ # +attributes+ should be an attributes object, and unlike the
355
+ # `initialize` method, no assignment calls are made per attribute.
356
+ def init_with_attributes(attributes, new_record = false) # :nodoc:
357
+ @new_record = new_record
358
+ @attributes = attributes
306
359
 
307
- @new_record = coder['new_record']
360
+ init_internals
308
361
 
309
- self.class.define_attribute_methods
362
+ yield self if block_given?
310
363
 
311
364
  _run_find_callbacks
312
365
  _run_initialize_callbacks
@@ -342,23 +395,22 @@ module ActiveRecord
342
395
 
343
396
  ##
344
397
  def initialize_dup(other) # :nodoc:
345
- @attributes = @attributes.dup
346
- @attributes.reset(self.class.primary_key)
398
+ @attributes = @attributes.deep_dup
399
+ @attributes.reset(@primary_key)
347
400
 
348
401
  _run_initialize_callbacks
349
402
 
350
- @aggregation_cache = {}
351
- @association_cache = {}
352
-
353
- @new_record = true
354
- @destroyed = false
403
+ @new_record = true
404
+ @destroyed = false
405
+ @_start_transaction_state = nil
406
+ @transaction_state = nil
355
407
 
356
408
  super
357
409
  end
358
410
 
359
411
  # Populate +coder+ with attributes about this record that should be
360
412
  # serialized. The structure of +coder+ defined in this method is
361
- # guaranteed to match the structure of +coder+ passed to the +init_with+
413
+ # guaranteed to match the structure of +coder+ passed to the #init_with
362
414
  # method.
363
415
  #
364
416
  # Example:
@@ -369,11 +421,9 @@ module ActiveRecord
369
421
  # Post.new.encode_with(coder)
370
422
  # coder # => {"attributes" => {"id" => nil, ... }}
371
423
  def encode_with(coder)
372
- # FIXME: Remove this when we better serialize attributes
373
- coder['raw_attributes'] = attributes_before_type_cast
374
- coder['attributes'] = @attributes
375
- coder['new_record'] = new_record?
376
- coder['active_record_yaml_version'] = 0
424
+ self.class.yaml_encoder.encode(@attributes, coder)
425
+ coder["new_record"] = new_record?
426
+ coder["active_record_yaml_version"] = 2
377
427
  end
378
428
 
379
429
  # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
@@ -397,7 +447,7 @@ module ActiveRecord
397
447
  # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
398
448
  def hash
399
449
  if id
400
- id.hash
450
+ self.class.hash ^ id.hash
401
451
  else
402
452
  super
403
453
  end
@@ -413,18 +463,27 @@ module ActiveRecord
413
463
 
414
464
  # Returns +true+ if the attributes hash has been frozen.
415
465
  def frozen?
466
+ sync_with_transaction_state if @transaction_state&.finalized?
416
467
  @attributes.frozen?
417
468
  end
418
469
 
419
470
  # Allows sort on objects
420
471
  def <=>(other_object)
421
472
  if other_object.is_a?(self.class)
422
- self.to_key <=> other_object.to_key
473
+ to_key <=> other_object.to_key
423
474
  else
424
475
  super
425
476
  end
426
477
  end
427
478
 
479
+ def present? # :nodoc:
480
+ true
481
+ end
482
+
483
+ def blank? # :nodoc:
484
+ false
485
+ end
486
+
428
487
  # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
429
488
  # attributes will be marked as read only since they cannot be saved.
430
489
  def readonly?
@@ -445,135 +504,96 @@ module ActiveRecord
445
504
  # We check defined?(@attributes) not to issue warnings if the object is
446
505
  # allocated but not initialized.
447
506
  inspection = if defined?(@attributes) && @attributes
448
- self.class.column_names.collect { |name|
449
- if has_attribute?(name)
450
- "#{name}: #{attribute_for_inspect(name)}"
451
- end
452
- }.compact.join(", ")
453
- else
454
- "not initialized"
455
- end
507
+ self.class.attribute_names.collect do |name|
508
+ if has_attribute?(name)
509
+ attr = _read_attribute(name)
510
+ value = if attr.nil?
511
+ attr.inspect
512
+ else
513
+ attr = format_for_inspect(attr)
514
+ inspection_filter.filter_param(name, attr)
515
+ end
516
+ "#{name}: #{value}"
517
+ end
518
+ end.compact.join(", ")
519
+ else
520
+ "not initialized"
521
+ end
522
+
456
523
  "#<#{self.class} #{inspection}>"
457
524
  end
458
525
 
459
- # Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record`
526
+ # Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
460
527
  # when pp is required.
461
528
  def pretty_print(pp)
462
529
  return super if custom_inspect_method_defined?
463
530
  pp.object_address_group(self) do
464
531
  if defined?(@attributes) && @attributes
465
- column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
466
- pp.seplist(column_names, proc { pp.text ',' }) do |column_name|
467
- column_value = read_attribute(column_name)
468
- pp.breakable ' '
532
+ attr_names = self.class.attribute_names.select { |name| has_attribute?(name) }
533
+ pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
534
+ pp.breakable " "
469
535
  pp.group(1) do
470
- pp.text column_name
471
- pp.text ':'
536
+ pp.text attr_name
537
+ pp.text ":"
472
538
  pp.breakable
473
- pp.pp column_value
539
+ value = _read_attribute(attr_name)
540
+ value = inspection_filter.filter_param(attr_name, value) unless value.nil?
541
+ pp.pp value
474
542
  end
475
543
  end
476
544
  else
477
- pp.breakable ' '
478
- pp.text 'not initialized'
545
+ pp.breakable " "
546
+ pp.text "not initialized"
479
547
  end
480
548
  end
481
549
  end
482
550
 
483
551
  # Returns a hash of the given methods with their names as keys and returned values as values.
484
552
  def slice(*methods)
485
- Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
553
+ Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
486
554
  end
487
555
 
488
556
  private
489
557
 
490
- def set_transaction_state(state) # :nodoc:
491
- @transaction_state = state
492
- end
493
-
494
- def has_transactional_callbacks? # :nodoc:
495
- !_rollback_callbacks.empty? || !_commit_callbacks.empty?
496
- end
497
-
498
- # Updates the attributes on this particular ActiveRecord object so that
499
- # if it is associated with a transaction, then the state of the AR object
500
- # will be updated to reflect the current state of the transaction
501
- #
502
- # The @transaction_state variable stores the states of the associated
503
- # transaction. This relies on the fact that a transaction can only be in
504
- # one rollback or commit (otherwise a list of states would be required)
505
- # Each AR object inside of a transaction carries that transaction's
506
- # TransactionState.
507
- #
508
- # This method checks to see if the ActiveRecord object's state reflects
509
- # the TransactionState, and rolls back or commits the ActiveRecord object
510
- # as appropriate.
511
- #
512
- # Since ActiveRecord objects can be inside multiple transactions, this
513
- # method recursively goes through the parent of the TransactionState and
514
- # checks if the ActiveRecord object reflects the state of the object.
515
- def sync_with_transaction_state
516
- update_attributes_from_transaction_state(@transaction_state, 0)
517
- end
518
-
519
- def update_attributes_from_transaction_state(transaction_state, depth)
520
- @reflects_state = [false] if depth == 0
521
-
522
- if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
523
- unless @reflects_state[depth]
524
- restore_transaction_record_state if transaction_state.rolledback?
525
- clear_transaction_record_state
526
- @reflects_state[depth] = true
527
- end
528
-
529
- if transaction_state.parent && !@reflects_state[depth+1]
530
- update_attributes_from_transaction_state(transaction_state.parent, depth+1)
531
- end
558
+ # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
559
+ # the array, and then rescues from the possible +NoMethodError+. If those elements are
560
+ # +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
561
+ # which significantly impacts upon performance.
562
+ #
563
+ # So we can avoid the +method_missing+ hit by explicitly defining +#to_ary+ as +nil+ here.
564
+ #
565
+ # See also https://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
566
+ def to_ary
567
+ nil
532
568
  end
533
- end
534
569
 
535
- # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
536
- # of the array, and then rescues from the possible NoMethodError. If those elements are
537
- # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
538
- # which significantly impacts upon performance.
539
- #
540
- # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
541
- #
542
- # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
543
- def to_ary # :nodoc:
544
- nil
545
- end
570
+ def init_internals
571
+ @primary_key = self.class.primary_key
572
+ @readonly = false
573
+ @destroyed = false
574
+ @marked_for_destruction = false
575
+ @destroyed_by_association = nil
576
+ @_start_transaction_state = nil
577
+ @transaction_state = nil
546
578
 
547
- def init_internals
548
- @aggregation_cache = {}
549
- @association_cache = {}
550
- @readonly = false
551
- @destroyed = false
552
- @marked_for_destruction = false
553
- @destroyed_by_association = nil
554
- @new_record = true
555
- @txn = nil
556
- @_start_transaction_state = {}
557
- @transaction_state = nil
558
- end
559
-
560
- def initialize_internals_callback
561
- end
579
+ self.class.define_attribute_methods
580
+ end
562
581
 
563
- # This method is needed to make protected_attributes gem easier to hook.
564
- # Remove it when we drop support to this gem.
565
- def init_attributes(attributes, options)
566
- assign_attributes(attributes)
567
- end
582
+ def initialize_internals_callback
583
+ end
568
584
 
569
- def thaw
570
- if frozen?
571
- @attributes = @attributes.dup
585
+ def custom_inspect_method_defined?
586
+ self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
572
587
  end
573
- end
574
588
 
575
- def custom_inspect_method_defined?
576
- self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
577
- end
589
+ def inspection_filter
590
+ @inspection_filter ||= begin
591
+ mask = DelegateClass(::String).new(ActiveSupport::ParameterFilter::FILTERED)
592
+ def mask.pretty_print(pp)
593
+ pp.text __getobj__
594
+ end
595
+ ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
596
+ end
597
+ end
578
598
  end
579
599
  end