activerecord 4.2.0 → 6.1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1221 -796
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +267 -249
  8. data/lib/active_record/association_relation.rb +45 -7
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +172 -67
  11. data/lib/active_record/associations/association_scope.rb +105 -129
  12. data/lib/active_record/associations/belongs_to_association.rb +85 -59
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -33
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +168 -279
  22. data/lib/active_record/associations/collection_proxy.rb +263 -155
  23. data/lib/active_record/associations/foreign_association.rb +33 -0
  24. data/lib/active_record/associations/has_many_association.rb +57 -84
  25. data/lib/active_record/associations/has_many_through_association.rb +70 -82
  26. data/lib/active_record/associations/has_one_association.rb +74 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -73
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +175 -164
  32. data/lib/active_record/associations/preloader/association.rb +107 -112
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +99 -96
  35. data/lib/active_record/associations/singular_association.rb +18 -45
  36. data/lib/active_record/associations/through_association.rb +49 -24
  37. data/lib/active_record/associations.rb +1845 -1597
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -138
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -36
  46. data/lib/active_record/attribute_methods/write.rb +25 -56
  47. data/lib/active_record/attribute_methods.rb +153 -162
  48. data/lib/active_record/attributes.rb +234 -70
  49. data/lib/active_record/autosave_association.rb +157 -69
  50. data/lib/active_record/base.rb +49 -50
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +46 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +271 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +78 -161
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -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 +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +499 -293
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +595 -382
  119. data/lib/active_record/connection_adapters/schema_cache.rb +191 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -389
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +488 -243
  133. data/lib/active_record/counter_cache.rb +71 -50
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +273 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +212 -94
  143. data/lib/active_record/errors.rb +225 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +11 -6
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +273 -496
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +64 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +52 -0
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +103 -95
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +298 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +685 -309
  170. data/lib/active_record/model_schema.rb +420 -113
  171. data/lib/active_record/nested_attributes.rb +265 -216
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +574 -135
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +175 -54
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +533 -216
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +485 -310
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +326 -244
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +318 -256
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +99 -84
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +139 -96
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -409
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +23 -21
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -342
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -26
  209. data/lib/active_record/scoping/default.rb +96 -82
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +133 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +366 -129
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +291 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +181 -152
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -41
  231. data/lib/active_record/type/date_time.rb +4 -38
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +33 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +65 -48
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +44 -28
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -10
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +175 -65
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  347. data/lib/active_record/attribute.rb +0 -149
  348. data/lib/active_record/attribute_decorators.rb +0 -66
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  351. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -30
  363. data/lib/active_record/type/decimal.rb +0 -40
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -55
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -36
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -101
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  374. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record Counter Cache
3
5
  module CounterCache
@@ -12,13 +14,21 @@ module ActiveRecord
12
14
  #
13
15
  # * +id+ - The id of the object you wish to reset a counter on.
14
16
  # * +counters+ - One or more association counters to reset. Association name or counter name can be given.
17
+ # * <tt>:touch</tt> - Touch timestamp columns when updating.
18
+ # Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
19
+ # touch that column or an array of symbols to touch just those ones.
15
20
  #
16
21
  # ==== Examples
17
22
  #
18
- # # For Post with id #1 records reset the comments_count
23
+ # # For the Post with id #1, reset the comments_count
19
24
  # Post.reset_counters(1, :comments)
20
- def reset_counters(id, *counters)
25
+ #
26
+ # # Like above, but also touch the +updated_at+ and/or +updated_on+
27
+ # # attributes.
28
+ # Post.reset_counters(1, :comments, touch: true)
29
+ def reset_counters(id, *counters, touch: nil)
21
30
  object = find(id)
31
+
22
32
  counters.each do |counter_association|
23
33
  has_many_association = _reflect_on_association(counter_association)
24
34
  unless has_many_association
@@ -26,7 +36,7 @@ module ActiveRecord
26
36
  has_many_association = has_many.find { |association| association.counter_cache_column && association.counter_cache_column.to_sym == counter_association.to_sym }
27
37
  counter_association = has_many_association.plural_name if has_many_association
28
38
  end
29
- raise ArgumentError, "'#{self.name}' has no association called '#{counter_association}'" unless has_many_association
39
+ raise ArgumentError, "'#{name}' has no association called '#{counter_association}'" unless has_many_association
30
40
 
31
41
  if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
32
42
  has_many_association = has_many_association.through_reflection
@@ -37,25 +47,36 @@ module ActiveRecord
37
47
  reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
38
48
  counter_name = reflection.counter_cache_column
39
49
 
40
- stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
41
- arel_table[counter_name] => object.send(counter_association).count(:all)
42
- }, primary_key)
43
- connection.update stmt
50
+ updates = { counter_name => object.send(counter_association).count(:all) }
51
+
52
+ if touch
53
+ names = touch if touch != true
54
+ names = Array.wrap(names)
55
+ options = names.extract_options!
56
+ touch_updates = touch_attributes_with_time(*names, **options)
57
+ updates.merge!(touch_updates)
58
+ end
59
+
60
+ unscoped.where(primary_key => object.id).update_all(updates)
44
61
  end
45
- return true
62
+
63
+ true
46
64
  end
47
65
 
48
66
  # A generic "counter updater" implementation, intended primarily to be
49
- # used by increment_counter and decrement_counter, but which may also
67
+ # used by #increment_counter and #decrement_counter, but which may also
50
68
  # be useful on its own. It simply does a direct SQL update for the record
51
69
  # with the given ID, altering the given hash of counters by the amount
52
70
  # given by the corresponding value:
53
71
  #
54
72
  # ==== Parameters
55
73
  #
56
- # * +id+ - The id of the object you wish to update a counter on or an Array of ids.
74
+ # * +id+ - The id of the object you wish to update a counter on or an array of ids.
57
75
  # * +counters+ - A Hash containing the names of the fields
58
76
  # to update as keys and the amount to update the field by as values.
77
+ # * <tt>:touch</tt> option - Touch timestamp columns when updating.
78
+ # If attribute names are passed, they are updated along with updated_at/on
79
+ # attributes.
59
80
  #
60
81
  # ==== Examples
61
82
  #
@@ -74,75 +95,78 @@ module ActiveRecord
74
95
  # # UPDATE posts
75
96
  # # SET comment_count = COALESCE(comment_count, 0) + 1
76
97
  # # WHERE id IN (10, 15)
98
+ #
99
+ # # For the Posts with id of 10 and 15, increment the comment_count by 1
100
+ # # and update the updated_at value for each counter.
101
+ # Post.update_counters [10, 15], comment_count: 1, touch: true
102
+ # # Executes the following SQL:
103
+ # # UPDATE posts
104
+ # # SET comment_count = COALESCE(comment_count, 0) + 1,
105
+ # # `updated_at` = '2016-10-13T09:59:23-05:00'
106
+ # # WHERE id IN (10, 15)
77
107
  def update_counters(id, counters)
78
- updates = counters.map do |counter_name, value|
79
- operator = value < 0 ? '-' : '+'
80
- quoted_column = connection.quote_column_name(counter_name)
81
- "#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
82
- end
83
-
84
- unscoped.where(primary_key => id).update_all updates.join(', ')
108
+ unscoped.where!(primary_key => id).update_counters(counters)
85
109
  end
86
110
 
87
111
  # Increment a numeric field by one, via a direct SQL update.
88
112
  #
89
113
  # This method is used primarily for maintaining counter_cache columns that are
90
- # used to store aggregate values. For example, a DiscussionBoard may cache
114
+ # used to store aggregate values. For example, a +DiscussionBoard+ may cache
91
115
  # posts_count and comments_count to avoid running an SQL query to calculate the
92
116
  # number of posts and comments there are, each time it is displayed.
93
117
  #
94
118
  # ==== Parameters
95
119
  #
96
120
  # * +counter_name+ - The name of the field that should be incremented.
97
- # * +id+ - The id of the object that should be incremented or an Array of ids.
121
+ # * +id+ - The id of the object that should be incremented or an array of ids.
122
+ # * <tt>:touch</tt> - Touch timestamp columns when updating.
123
+ # Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
124
+ # touch that column or an array of symbols to touch just those ones.
98
125
  #
99
126
  # ==== Examples
100
127
  #
101
- # # Increment the post_count column for the record with an id of 5
102
- # DiscussionBoard.increment_counter(:post_count, 5)
103
- def increment_counter(counter_name, id)
104
- update_counters(id, counter_name => 1)
128
+ # # Increment the posts_count column for the record with an id of 5
129
+ # DiscussionBoard.increment_counter(:posts_count, 5)
130
+ #
131
+ # # Increment the posts_count column for the record with an id of 5
132
+ # # and update the updated_at value.
133
+ # DiscussionBoard.increment_counter(:posts_count, 5, touch: true)
134
+ def increment_counter(counter_name, id, touch: nil)
135
+ update_counters(id, counter_name => 1, touch: touch)
105
136
  end
106
137
 
107
138
  # Decrement a numeric field by one, via a direct SQL update.
108
139
  #
109
- # This works the same as increment_counter but reduces the column value by
140
+ # This works the same as #increment_counter but reduces the column value by
110
141
  # 1 instead of increasing it.
111
142
  #
112
143
  # ==== Parameters
113
144
  #
114
145
  # * +counter_name+ - The name of the field that should be decremented.
115
- # * +id+ - The id of the object that should be decremented or an Array of ids.
146
+ # * +id+ - The id of the object that should be decremented or an array of ids.
147
+ # * <tt>:touch</tt> - Touch timestamp columns when updating.
148
+ # Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
149
+ # touch that column or an array of symbols to touch just those ones.
116
150
  #
117
151
  # ==== Examples
118
152
  #
119
- # # Decrement the post_count column for the record with an id of 5
120
- # DiscussionBoard.decrement_counter(:post_count, 5)
121
- def decrement_counter(counter_name, id)
122
- update_counters(id, counter_name => -1)
153
+ # # Decrement the posts_count column for the record with an id of 5
154
+ # DiscussionBoard.decrement_counter(:posts_count, 5)
155
+ #
156
+ # # Decrement the posts_count column for the record with an id of 5
157
+ # # and update the updated_at value.
158
+ # DiscussionBoard.decrement_counter(:posts_count, 5, touch: true)
159
+ def decrement_counter(counter_name, id, touch: nil)
160
+ update_counters(id, counter_name => -1, touch: touch)
123
161
  end
124
162
  end
125
163
 
126
- protected
127
-
128
- def actually_destroyed?
129
- @_actually_destroyed
130
- end
131
-
132
- def clear_destroy_state
133
- @_actually_destroyed = nil
134
- end
135
-
136
164
  private
137
-
138
- def _create_record(*)
165
+ def _create_record(attribute_names = self.attribute_names)
139
166
  id = super
140
167
 
141
168
  each_counter_cached_associations do |association|
142
- if send(association.reflection.name)
143
- association.increment_counters
144
- @_after_create_counter_called = true
145
- end
169
+ association.increment_counters
146
170
  end
147
171
 
148
172
  id
@@ -155,9 +179,7 @@ module ActiveRecord
155
179
  each_counter_cached_associations do |association|
156
180
  foreign_key = association.reflection.foreign_key.to_sym
157
181
  unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
158
- if send(association.reflection.name)
159
- association.decrement_counters
160
- end
182
+ association.decrement_counters
161
183
  end
162
184
  end
163
185
  end
@@ -167,9 +189,8 @@ module ActiveRecord
167
189
 
168
190
  def each_counter_cached_associations
169
191
  _reflections.each do |name, reflection|
170
- yield association(name) if reflection.belongs_to? && reflection.counter_cache_column
192
+ yield association(name.to_sym) if reflection.belongs_to? && reflection.counter_cache_column
171
193
  end
172
194
  end
173
-
174
195
  end
175
196
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "active_support/core_ext/enumerable"
5
+
6
+ module ActiveRecord
7
+ class DatabaseConfigurations
8
+ # Expands a connection string into a hash.
9
+ class ConnectionUrlResolver # :nodoc:
10
+ # == Example
11
+ #
12
+ # url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
13
+ # ConnectionUrlResolver.new(url).to_hash
14
+ # # => {
15
+ # adapter: "postgresql",
16
+ # host: "localhost",
17
+ # port: 9000,
18
+ # database: "foo_test",
19
+ # username: "foo",
20
+ # password: "bar",
21
+ # pool: "5",
22
+ # timeout: "3000"
23
+ # }
24
+ def initialize(url)
25
+ raise "Database URL cannot be empty" if url.blank?
26
+ @uri = uri_parser.parse(url)
27
+ @adapter = @uri.scheme && @uri.scheme.tr("-", "_")
28
+ @adapter = "postgresql" if @adapter == "postgres"
29
+
30
+ if @uri.opaque
31
+ @uri.opaque, @query = @uri.opaque.split("?", 2)
32
+ else
33
+ @query = @uri.query
34
+ end
35
+ end
36
+
37
+ # Converts the given URL to a full connection hash.
38
+ def to_hash
39
+ config = raw_config.compact_blank
40
+ config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
41
+ config
42
+ end
43
+
44
+ private
45
+ attr_reader :uri
46
+
47
+ def uri_parser
48
+ @uri_parser ||= URI::Parser.new
49
+ end
50
+
51
+ # Converts the query parameters of the URI into a hash.
52
+ #
53
+ # "localhost?pool=5&reaping_frequency=2"
54
+ # # => { pool: "5", reaping_frequency: "2" }
55
+ #
56
+ # returns empty hash if no query present.
57
+ #
58
+ # "localhost"
59
+ # # => {}
60
+ def query_hash
61
+ Hash[(@query || "").split("&").map { |pair| pair.split("=", 2) }].symbolize_keys
62
+ end
63
+
64
+ def raw_config
65
+ if uri.opaque
66
+ query_hash.merge(
67
+ adapter: @adapter,
68
+ database: uri.opaque
69
+ )
70
+ else
71
+ query_hash.merge(
72
+ adapter: @adapter,
73
+ username: uri.user,
74
+ password: uri.password,
75
+ port: uri.port,
76
+ database: database_from_path,
77
+ host: uri.hostname
78
+ )
79
+ end
80
+ end
81
+
82
+ # Returns name of the database.
83
+ def database_from_path
84
+ if @adapter == "sqlite3"
85
+ # 'sqlite3:/foo' is absolute, because that makes sense. The
86
+ # corresponding relative version, 'sqlite3:foo', is handled
87
+ # elsewhere, as an "opaque".
88
+
89
+ uri.path
90
+ else
91
+ # Only SQLite uses a filename as the "database" name; for
92
+ # anything else, a leading slash would be silly.
93
+
94
+ uri.path.delete_prefix("/")
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class DatabaseConfigurations
5
+ # ActiveRecord::Base.configurations will return either a HashConfig or
6
+ # UrlConfig respectively. It will never return a DatabaseConfig object,
7
+ # as this is the parent class for the types of database configuration objects.
8
+ class DatabaseConfig # :nodoc:
9
+ attr_reader :env_name, :name
10
+
11
+ attr_accessor :owner_name
12
+
13
+ def initialize(env_name, name)
14
+ @env_name = env_name
15
+ @name = name
16
+ end
17
+
18
+ def spec_name
19
+ @name
20
+ end
21
+ deprecate spec_name: "please use name instead"
22
+
23
+ def config
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def adapter_method
28
+ "#{adapter}_connection"
29
+ end
30
+
31
+ def host
32
+ raise NotImplementedError
33
+ end
34
+
35
+ def database
36
+ raise NotImplementedError
37
+ end
38
+
39
+ def _database=(database)
40
+ raise NotImplementedError
41
+ end
42
+
43
+ def adapter
44
+ raise NotImplementedError
45
+ end
46
+
47
+ def pool
48
+ raise NotImplementedError
49
+ end
50
+
51
+ def checkout_timeout
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def reaping_frequency
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def idle_timeout
60
+ raise NotImplementedError
61
+ end
62
+
63
+ def replica?
64
+ raise NotImplementedError
65
+ end
66
+
67
+ def migrations_paths
68
+ raise NotImplementedError
69
+ end
70
+
71
+ def for_current_env?
72
+ env_name == ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
73
+ end
74
+
75
+ def schema_cache_path
76
+ raise NotImplementedError
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class DatabaseConfigurations
5
+ # A HashConfig object is created for each database configuration entry that
6
+ # is created from a hash.
7
+ #
8
+ # A hash config:
9
+ #
10
+ # { "development" => { "database" => "db_name" } }
11
+ #
12
+ # Becomes:
13
+ #
14
+ # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10
15
+ # @env_name="development", @name="primary", @config={database: "db_name"}>
16
+ #
17
+ # ==== Options
18
+ #
19
+ # * <tt>:env_name</tt> - The Rails environment, i.e. "development".
20
+ # * <tt>:name</tt> - The db config name. In a standard two-tier
21
+ # database configuration this will default to "primary". In a multiple
22
+ # database three-tier database configuration this corresponds to the name
23
+ # used in the second tier, for example "primary_readonly".
24
+ # * <tt>:config</tt> - The config hash. This is the hash that contains the
25
+ # database adapter, name, and other important information for database
26
+ # connections.
27
+ class HashConfig < DatabaseConfig
28
+ attr_reader :configuration_hash
29
+ def initialize(env_name, name, configuration_hash)
30
+ super(env_name, name)
31
+ @configuration_hash = configuration_hash.symbolize_keys.freeze
32
+ end
33
+
34
+ def config
35
+ ActiveSupport::Deprecation.warn("DatabaseConfig#config will be removed in 7.0.0 in favor of DatabaseConfig#configuration_hash which returns a hash with symbol keys")
36
+ configuration_hash.stringify_keys
37
+ end
38
+
39
+ # Determines whether a database configuration is for a replica / readonly
40
+ # connection. If the +replica+ key is present in the config, +replica?+ will
41
+ # return +true+.
42
+ def replica?
43
+ configuration_hash[:replica]
44
+ end
45
+
46
+ # The migrations paths for a database configuration. If the
47
+ # +migrations_paths+ key is present in the config, +migrations_paths+
48
+ # will return its value.
49
+ def migrations_paths
50
+ configuration_hash[:migrations_paths]
51
+ end
52
+
53
+ def host
54
+ configuration_hash[:host]
55
+ end
56
+
57
+ def database
58
+ configuration_hash[:database]
59
+ end
60
+
61
+ def _database=(database) # :nodoc:
62
+ @configuration_hash = configuration_hash.merge(database: database).freeze
63
+ end
64
+
65
+ def pool
66
+ (configuration_hash[:pool] || 5).to_i
67
+ end
68
+
69
+ def checkout_timeout
70
+ (configuration_hash[:checkout_timeout] || 5).to_f
71
+ end
72
+
73
+ # +reaping_frequency+ is configurable mostly for historical reasons, but it could
74
+ # also be useful if someone wants a very low +idle_timeout+.
75
+ def reaping_frequency
76
+ configuration_hash.fetch(:reaping_frequency, 60)&.to_f
77
+ end
78
+
79
+ def idle_timeout
80
+ timeout = configuration_hash.fetch(:idle_timeout, 300).to_f
81
+ timeout if timeout > 0
82
+ end
83
+
84
+ def adapter
85
+ configuration_hash[:adapter]
86
+ end
87
+
88
+ # The path to the schema cache dump file for a database.
89
+ # If omitted, the filename will be read from ENV or a
90
+ # default will be derived.
91
+ def schema_cache_path
92
+ configuration_hash[:schema_cache_path]
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class DatabaseConfigurations
5
+ # A UrlConfig object is created for each database configuration
6
+ # entry that is created from a URL. This can either be a URL string
7
+ # or a hash with a URL in place of the config hash.
8
+ #
9
+ # A URL config:
10
+ #
11
+ # postgres://localhost/foo
12
+ #
13
+ # Becomes:
14
+ #
15
+ # #<ActiveRecord::DatabaseConfigurations::UrlConfig:0x00007fdc3238f340
16
+ # @env_name="default_env", @name="primary",
17
+ # @config={adapter: "postgresql", database: "foo", host: "localhost"},
18
+ # @url="postgres://localhost/foo">
19
+ #
20
+ # ==== Options
21
+ #
22
+ # * <tt>:env_name</tt> - The Rails environment, ie "development".
23
+ # * <tt>:name</tt> - The db config name. In a standard two-tier
24
+ # database configuration this will default to "primary". In a multiple
25
+ # database three-tier database configuration this corresponds to the name
26
+ # used in the second tier, for example "primary_readonly".
27
+ # * <tt>:url</tt> - The database URL.
28
+ # * <tt>:config</tt> - The config hash. This is the hash that contains the
29
+ # database adapter, name, and other important information for database
30
+ # connections.
31
+ class UrlConfig < HashConfig
32
+ attr_reader :url
33
+
34
+ def initialize(env_name, name, url, configuration_hash = {})
35
+ super(env_name, name, configuration_hash)
36
+
37
+ @url = url
38
+ @configuration_hash = @configuration_hash.merge(build_url_hash).freeze
39
+ end
40
+
41
+ private
42
+ # Return a Hash that can be merged into the main config that represents
43
+ # the passed in url
44
+ def build_url_hash
45
+ if url.nil? || %w(jdbc: http: https:).any? { |protocol| url.start_with?(protocol) }
46
+ { url: url }
47
+ else
48
+ ConnectionUrlResolver.new(url).to_hash
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end