activerecord 5.0.7.2 → 6.1.1

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 (363) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +829 -2015
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +11 -9
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -29
  8. data/lib/active_record/aggregations.rb +249 -247
  9. data/lib/active_record/association_relation.rb +30 -18
  10. data/lib/active_record/associations.rb +1714 -1596
  11. data/lib/active_record/associations/alias_tracker.rb +36 -42
  12. data/lib/active_record/associations/association.rb +143 -68
  13. data/lib/active_record/associations/association_scope.rb +98 -94
  14. data/lib/active_record/associations/belongs_to_association.rb +76 -46
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -28
  17. data/lib/active_record/associations/builder/belongs_to.rb +52 -60
  18. data/lib/active_record/associations/builder/collection_association.rb +12 -22
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
  20. data/lib/active_record/associations/builder/has_many.rb +10 -2
  21. data/lib/active_record/associations/builder/has_one.rb +35 -2
  22. data/lib/active_record/associations/builder/singular_association.rb +5 -1
  23. data/lib/active_record/associations/collection_association.rb +104 -259
  24. data/lib/active_record/associations/collection_proxy.rb +169 -125
  25. data/lib/active_record/associations/foreign_association.rb +22 -0
  26. data/lib/active_record/associations/has_many_association.rb +46 -31
  27. data/lib/active_record/associations/has_many_through_association.rb +66 -46
  28. data/lib/active_record/associations/has_one_association.rb +71 -52
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +169 -180
  31. data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
  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 +97 -104
  35. data/lib/active_record/associations/preloader/association.rb +109 -97
  36. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  37. data/lib/active_record/associations/singular_association.rb +12 -45
  38. data/lib/active_record/associations/through_association.rb +27 -15
  39. data/lib/active_record/attribute_assignment.rb +55 -60
  40. data/lib/active_record/attribute_methods.rb +111 -141
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
  42. data/lib/active_record/attribute_methods/dirty.rb +172 -112
  43. data/lib/active_record/attribute_methods/primary_key.rb +88 -91
  44. data/lib/active_record/attribute_methods/query.rb +6 -8
  45. data/lib/active_record/attribute_methods/read.rb +18 -50
  46. data/lib/active_record/attribute_methods/serialization.rb +38 -10
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
  48. data/lib/active_record/attribute_methods/write.rb +25 -32
  49. data/lib/active_record/attributes.rb +69 -31
  50. data/lib/active_record/autosave_association.rb +102 -66
  51. data/lib/active_record/base.rb +16 -25
  52. data/lib/active_record/callbacks.rb +202 -43
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -12
  55. data/lib/active_record/connection_adapters.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
  69. data/lib/active_record/connection_adapters/column.rb +55 -13
  70. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  71. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +79 -49
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -56
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +20 -12
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
  82. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  83. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
  85. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
  86. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  90. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -6
  93. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
  95. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  98. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  106. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
  107. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  109. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  110. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +98 -38
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +426 -324
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
  121. data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
  123. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  124. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -6
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +282 -290
  131. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  132. data/lib/active_record/connection_handling.rb +287 -45
  133. data/lib/active_record/core.rb +385 -181
  134. data/lib/active_record/counter_cache.rb +60 -28
  135. data/lib/active_record/database_configurations.rb +272 -0
  136. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  137. data/lib/active_record/database_configurations/database_config.rb +80 -0
  138. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  139. data/lib/active_record/database_configurations/url_config.rb +53 -0
  140. data/lib/active_record/delegated_type.rb +209 -0
  141. data/lib/active_record/destroy_association_async_job.rb +36 -0
  142. data/lib/active_record/dynamic_matchers.rb +87 -87
  143. data/lib/active_record/enum.rb +122 -47
  144. data/lib/active_record/errors.rb +153 -22
  145. data/lib/active_record/explain.rb +13 -8
  146. data/lib/active_record/explain_registry.rb +3 -1
  147. data/lib/active_record/explain_subscriber.rb +9 -4
  148. data/lib/active_record/fixture_set/file.rb +20 -22
  149. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  150. data/lib/active_record/fixture_set/render_context.rb +17 -0
  151. data/lib/active_record/fixture_set/table_row.rb +152 -0
  152. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  153. data/lib/active_record/fixtures.rb +246 -507
  154. data/lib/active_record/gem_version.rb +6 -4
  155. data/lib/active_record/inheritance.rb +168 -95
  156. data/lib/active_record/insert_all.rb +208 -0
  157. data/lib/active_record/integration.rb +114 -25
  158. data/lib/active_record/internal_metadata.rb +30 -24
  159. data/lib/active_record/legacy_yaml_adapter.rb +11 -5
  160. data/lib/active_record/locking/optimistic.rb +81 -85
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +68 -31
  163. data/lib/active_record/middleware/database_selector.rb +77 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  166. data/lib/active_record/migration.rb +439 -342
  167. data/lib/active_record/migration/command_recorder.rb +152 -98
  168. data/lib/active_record/migration/compatibility.rb +229 -60
  169. data/lib/active_record/migration/join_table.rb +8 -7
  170. data/lib/active_record/model_schema.rb +230 -122
  171. data/lib/active_record/nested_attributes.rb +213 -203
  172. data/lib/active_record/no_touching.rb +11 -2
  173. data/lib/active_record/null_relation.rb +12 -34
  174. data/lib/active_record/persistence.rb +471 -97
  175. data/lib/active_record/query_cache.rb +23 -12
  176. data/lib/active_record/querying.rb +43 -25
  177. data/lib/active_record/railtie.rb +155 -43
  178. data/lib/active_record/railties/console_sandbox.rb +2 -0
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +507 -195
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +245 -269
  183. data/lib/active_record/relation.rb +475 -324
  184. data/lib/active_record/relation/batches.rb +125 -72
  185. data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
  186. data/lib/active_record/relation/calculations.rb +267 -171
  187. data/lib/active_record/relation/delegation.rb +73 -69
  188. data/lib/active_record/relation/finder_methods.rb +238 -248
  189. data/lib/active_record/relation/from_clause.rb +7 -9
  190. data/lib/active_record/relation/merger.rb +95 -77
  191. data/lib/active_record/relation/predicate_builder.rb +109 -110
  192. data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
  193. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  194. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  195. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
  196. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  197. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  198. data/lib/active_record/relation/query_attribute.rb +33 -2
  199. data/lib/active_record/relation/query_methods.rb +654 -374
  200. data/lib/active_record/relation/record_fetch_warning.rb +8 -6
  201. data/lib/active_record/relation/spawn_methods.rb +15 -14
  202. data/lib/active_record/relation/where_clause.rb +171 -109
  203. data/lib/active_record/result.rb +88 -51
  204. data/lib/active_record/runtime_registry.rb +5 -3
  205. data/lib/active_record/sanitization.rb +73 -100
  206. data/lib/active_record/schema.rb +7 -14
  207. data/lib/active_record/schema_dumper.rb +101 -69
  208. data/lib/active_record/schema_migration.rb +16 -12
  209. data/lib/active_record/scoping.rb +20 -20
  210. data/lib/active_record/scoping/default.rb +92 -95
  211. data/lib/active_record/scoping/named.rb +39 -30
  212. data/lib/active_record/secure_token.rb +19 -9
  213. data/lib/active_record/serialization.rb +7 -3
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +80 -29
  216. data/lib/active_record/store.rb +122 -42
  217. data/lib/active_record/suppressor.rb +6 -3
  218. data/lib/active_record/table_metadata.rb +51 -39
  219. data/lib/active_record/tasks/database_tasks.rb +332 -115
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +246 -0
  225. data/lib/active_record/timestamp.rb +70 -38
  226. data/lib/active_record/touch_later.rb +26 -24
  227. data/lib/active_record/transactions.rb +121 -184
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type.rb +29 -17
  230. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  231. data/lib/active_record/type/date.rb +2 -0
  232. data/lib/active_record/type/date_time.rb +2 -0
  233. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  234. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  235. data/lib/active_record/type/internal/timezone.rb +2 -0
  236. data/lib/active_record/type/json.rb +30 -0
  237. data/lib/active_record/type/serialized.rb +20 -9
  238. data/lib/active_record/type/text.rb +11 -0
  239. data/lib/active_record/type/time.rb +12 -1
  240. data/lib/active_record/type/type_map.rb +14 -17
  241. data/lib/active_record/type/unsigned_integer.rb +16 -0
  242. data/lib/active_record/type_caster.rb +4 -2
  243. data/lib/active_record/type_caster/connection.rb +17 -13
  244. data/lib/active_record/type_caster/map.rb +10 -6
  245. data/lib/active_record/validations.rb +8 -5
  246. data/lib/active_record/validations/absence.rb +2 -0
  247. data/lib/active_record/validations/associated.rb +4 -3
  248. data/lib/active_record/validations/length.rb +2 -0
  249. data/lib/active_record/validations/numericality.rb +35 -0
  250. data/lib/active_record/validations/presence.rb +4 -2
  251. data/lib/active_record/validations/uniqueness.rb +52 -45
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/arel.rb +54 -0
  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.rb +70 -0
  269. data/lib/arel/nodes/and.rb +32 -0
  270. data/lib/arel/nodes/ascending.rb +23 -0
  271. data/lib/arel/nodes/binary.rb +126 -0
  272. data/lib/arel/nodes/bind_param.rb +44 -0
  273. data/lib/arel/nodes/case.rb +55 -0
  274. data/lib/arel/nodes/casted.rb +62 -0
  275. data/lib/arel/nodes/comment.rb +29 -0
  276. data/lib/arel/nodes/count.rb +12 -0
  277. data/lib/arel/nodes/delete_statement.rb +45 -0
  278. data/lib/arel/nodes/descending.rb +23 -0
  279. data/lib/arel/nodes/equality.rb +15 -0
  280. data/lib/arel/nodes/extract.rb +24 -0
  281. data/lib/arel/nodes/false.rb +16 -0
  282. data/lib/arel/nodes/full_outer_join.rb +8 -0
  283. data/lib/arel/nodes/function.rb +44 -0
  284. data/lib/arel/nodes/grouping.rb +11 -0
  285. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  286. data/lib/arel/nodes/in.rb +15 -0
  287. data/lib/arel/nodes/infix_operation.rb +92 -0
  288. data/lib/arel/nodes/inner_join.rb +8 -0
  289. data/lib/arel/nodes/insert_statement.rb +37 -0
  290. data/lib/arel/nodes/join_source.rb +20 -0
  291. data/lib/arel/nodes/matches.rb +18 -0
  292. data/lib/arel/nodes/named_function.rb +23 -0
  293. data/lib/arel/nodes/node.rb +51 -0
  294. data/lib/arel/nodes/node_expression.rb +13 -0
  295. data/lib/arel/nodes/ordering.rb +27 -0
  296. data/lib/arel/nodes/outer_join.rb +8 -0
  297. data/lib/arel/nodes/over.rb +15 -0
  298. data/lib/arel/nodes/regexp.rb +16 -0
  299. data/lib/arel/nodes/right_outer_join.rb +8 -0
  300. data/lib/arel/nodes/select_core.rb +67 -0
  301. data/lib/arel/nodes/select_statement.rb +41 -0
  302. data/lib/arel/nodes/sql_literal.rb +19 -0
  303. data/lib/arel/nodes/string_join.rb +11 -0
  304. data/lib/arel/nodes/table_alias.rb +31 -0
  305. data/lib/arel/nodes/terminal.rb +16 -0
  306. data/lib/arel/nodes/true.rb +16 -0
  307. data/lib/arel/nodes/unary.rb +44 -0
  308. data/lib/arel/nodes/unary_operation.rb +20 -0
  309. data/lib/arel/nodes/unqualified_column.rb +22 -0
  310. data/lib/arel/nodes/update_statement.rb +41 -0
  311. data/lib/arel/nodes/values_list.rb +9 -0
  312. data/lib/arel/nodes/window.rb +126 -0
  313. data/lib/arel/nodes/with.rb +11 -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.rb +13 -0
  321. data/lib/arel/visitors/dot.rb +308 -0
  322. data/lib/arel/visitors/mysql.rb +93 -0
  323. data/lib/arel/visitors/postgresql.rb +120 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +899 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/rails/generators/active_record.rb +7 -5
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration.rb +22 -3
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
  333. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
  334. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
  335. data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
  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 → model.rb.tt} +10 -1
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. metadata +141 -57
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  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 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute.rb +0 -213
  348. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  349. data/lib/active_record/attribute_decorators.rb +0 -67
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
  355. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
  356. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  359. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -17
  360. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  361. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  362. data/lib/active_record/relation/where_clause_factory.rb +0 -38
  363. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,146 +1,158 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class Preloader
4
6
  class Association #:nodoc:
5
- attr_reader :owners, :reflection, :preload_scope, :model, :klass
6
- attr_reader :preloaded_records
7
-
8
- def initialize(klass, owners, reflection, preload_scope)
7
+ def initialize(klass, owners, reflection, preload_scope, associate_by_default = true)
9
8
  @klass = klass
10
- @owners = owners
9
+ @owners = owners.uniq(&:__id__)
11
10
  @reflection = reflection
12
11
  @preload_scope = preload_scope
12
+ @associate = associate_by_default || !preload_scope || preload_scope.empty_scope?
13
13
  @model = owners.first && owners.first.class
14
- @scope = nil
15
- @preloaded_records = []
16
14
  end
17
15
 
18
- def run(preloader)
19
- preload(preloader)
20
- end
16
+ def run
17
+ records = records_by_owner
21
18
 
22
- def preload(preloader)
23
- raise NotImplementedError
24
- end
19
+ owners.each do |owner|
20
+ associate_records_to_owner(owner, records[owner] || [])
21
+ end if @associate
25
22
 
26
- def scope
27
- @scope ||= build_scope
23
+ self
28
24
  end
29
25
 
30
- def records_for(ids)
31
- query_scope(ids)
32
- end
26
+ def records_by_owner
27
+ load_records unless defined?(@records_by_owner)
33
28
 
34
- def query_scope(ids)
35
- scope.where(association_key_name => ids)
29
+ @records_by_owner
36
30
  end
37
31
 
38
- def table
39
- klass.arel_table
40
- end
32
+ def preloaded_records
33
+ load_records unless defined?(@preloaded_records)
41
34
 
42
- # The name of the key on the associated records
43
- def association_key_name
44
- raise NotImplementedError
35
+ @preloaded_records
45
36
  end
46
37
 
47
- # This is overridden by HABTM as the condition should be on the foreign_key column in
48
- # the join table
49
- def association_key
50
- klass.arel_attribute(association_key_name, table)
51
- end
38
+ private
39
+ attr_reader :owners, :reflection, :preload_scope, :model, :klass
52
40
 
53
- # The name of the key on the model which declares the association
54
- def owner_key_name
55
- raise NotImplementedError
56
- end
41
+ def load_records
42
+ # owners can be duplicated when a relation has a collection association join
43
+ # #compare_by_identity makes such owners different hash keys
44
+ @records_by_owner = {}.compare_by_identity
45
+ raw_records = owner_keys.empty? ? [] : records_for(owner_keys)
57
46
 
58
- def options
59
- reflection.options
60
- end
47
+ @preloaded_records = raw_records.select do |record|
48
+ assignments = false
61
49
 
62
- private
50
+ owners_by_key[convert_key(record[association_key_name])].each do |owner|
51
+ entries = (@records_by_owner[owner] ||= [])
63
52
 
64
- def associated_records_by_owner(preloader)
65
- records = load_records do |record|
66
- owner = owners_by_key[convert_key(record[association_key_name])]
53
+ if reflection.collection? || entries.empty?
54
+ entries << record
55
+ assignments = true
56
+ end
57
+ end
58
+
59
+ assignments
60
+ end
61
+ end
62
+
63
+ # The name of the key on the associated records
64
+ def association_key_name
65
+ reflection.join_primary_key(klass)
66
+ end
67
+
68
+ # The name of the key on the model which declares the association
69
+ def owner_key_name
70
+ reflection.join_foreign_key
71
+ end
72
+
73
+ def associate_records_to_owner(owner, records)
67
74
  association = owner.association(reflection.name)
68
- association.set_inverse_instance(record)
75
+ if reflection.collection?
76
+ association.target = records
77
+ else
78
+ association.target = records.first
79
+ end
69
80
  end
70
81
 
71
- owners.each_with_object({}) do |owner, result|
72
- result[owner] = records[convert_key(owner[owner_key_name])] || []
82
+ def owner_keys
83
+ @owner_keys ||= owners_by_key.keys
73
84
  end
74
- end
75
85
 
76
- def owner_keys
77
- unless defined?(@owner_keys)
78
- @owner_keys = owners.map do |owner|
79
- owner[owner_key_name]
86
+ def owners_by_key
87
+ @owners_by_key ||= owners.each_with_object({}) do |owner, result|
88
+ key = convert_key(owner[owner_key_name])
89
+ (result[key] ||= []) << owner if key
80
90
  end
81
- @owner_keys.uniq!
82
- @owner_keys.compact!
83
91
  end
84
- @owner_keys
85
- end
86
92
 
87
- def owners_by_key
88
- unless defined?(@owners_by_key)
89
- @owners_by_key = owners.each_with_object({}) do |owner, h|
90
- h[convert_key(owner[owner_key_name])] = owner
93
+ def key_conversion_required?
94
+ unless defined?(@key_conversion_required)
95
+ @key_conversion_required = (association_key_type != owner_key_type)
91
96
  end
97
+
98
+ @key_conversion_required
92
99
  end
93
- @owners_by_key
94
- end
95
100
 
96
- def key_conversion_required?
97
- @key_conversion_required ||= association_key_type != owner_key_type
98
- end
101
+ def convert_key(key)
102
+ if key_conversion_required?
103
+ key.to_s
104
+ else
105
+ key
106
+ end
107
+ end
99
108
 
100
- def convert_key(key)
101
- if key_conversion_required?
102
- key.to_s
103
- else
104
- key
109
+ def association_key_type
110
+ @klass.type_for_attribute(association_key_name).type
105
111
  end
106
- end
107
112
 
108
- def association_key_type
109
- @klass.type_for_attribute(association_key_name.to_s).type
110
- end
113
+ def owner_key_type
114
+ @model.type_for_attribute(owner_key_name).type
115
+ end
111
116
 
112
- def owner_key_type
113
- @model.type_for_attribute(owner_key_name.to_s).type
114
- end
117
+ def records_for(ids)
118
+ scope.where(association_key_name => ids).load do |record|
119
+ # Processing only the first owner
120
+ # because the record is modified but not an owner
121
+ owner = owners_by_key[convert_key(record[association_key_name])].first
122
+ association = owner.association(reflection.name)
123
+ association.set_inverse_instance(record)
124
+ end
125
+ end
115
126
 
116
- def load_records(&block)
117
- return {} if owner_keys.empty?
118
- # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
119
- # Make several smaller queries if necessary or make one query if the adapter supports it
120
- slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
121
- @preloaded_records = slices.flat_map do |slice|
122
- records_for(slice).load(&block)
127
+ def scope
128
+ @scope ||= build_scope
123
129
  end
124
- @preloaded_records.group_by do |record|
125
- convert_key(record[association_key_name])
130
+
131
+ def reflection_scope
132
+ @reflection_scope ||= begin
133
+ reflection.join_scopes(klass.arel_table, klass.predicate_builder, klass).inject(&:merge!) || klass.unscoped
134
+ end
126
135
  end
127
- end
128
136
 
129
- def reflection_scope
130
- @reflection_scope ||= reflection.scope_for(klass)
131
- end
137
+ def build_scope
138
+ scope = klass.scope_for_association
132
139
 
133
- def build_scope
134
- scope = klass.scope_for_association
140
+ if reflection.type && !reflection.through_reflection?
141
+ scope.where!(reflection.type => model.polymorphic_name)
142
+ end
135
143
 
136
- if reflection.type
137
- scope.where!(reflection.type => model.base_class.sti_name)
138
- end
144
+ scope.merge!(reflection_scope) unless reflection_scope.empty_scope?
139
145
 
140
- scope.merge!(reflection_scope)
141
- scope.merge!(preload_scope) if preload_scope != NULL_RELATION
142
- scope
143
- end
146
+ if preload_scope && !preload_scope.empty_scope?
147
+ scope.merge!(preload_scope)
148
+ end
149
+
150
+ if preload_scope && preload_scope.strict_loading_value
151
+ scope.strict_loading
152
+ else
153
+ scope
154
+ end
155
+ end
144
156
  end
145
157
  end
146
158
  end
@@ -1,114 +1,115 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class Preloader
4
- module ThroughAssociation #:nodoc:
5
- def through_reflection
6
- reflection.through_reflection
6
+ class ThroughAssociation < Association # :nodoc:
7
+ PRELOADER = ActiveRecord::Associations::Preloader.new(associate_by_default: false)
8
+
9
+ def initialize(*)
10
+ super
11
+ @already_loaded = owners.first.association(through_reflection.name).loaded?
7
12
  end
8
13
 
9
- def source_reflection
10
- reflection.source_reflection
14
+ def preloaded_records
15
+ @preloaded_records ||= source_preloaders.flat_map(&:preloaded_records)
11
16
  end
12
17
 
13
- def associated_records_by_owner(preloader)
14
- preloader.preload(owners,
15
- through_reflection.name,
16
- through_scope)
18
+ def records_by_owner
19
+ return @records_by_owner if defined?(@records_by_owner)
20
+ source_records_by_owner = source_preloaders.map(&:records_by_owner).reduce(:merge)
21
+ through_records_by_owner = through_preloaders.map(&:records_by_owner).reduce(:merge)
17
22
 
18
- through_records = owners.map do |owner|
19
- association = owner.association through_reflection.name
23
+ @records_by_owner = owners.each_with_object({}) do |owner, result|
24
+ through_records = through_records_by_owner[owner] || []
20
25
 
21
- center = target_records_from_association(association)
22
- [owner, Array(center)]
23
- end
24
-
25
- reset_association owners, through_reflection.name
26
+ if @already_loaded
27
+ if source_type = reflection.options[:source_type]
28
+ through_records = through_records.select do |record|
29
+ record[reflection.foreign_type] == source_type
30
+ end
31
+ end
32
+ end
26
33
 
27
- middle_records = through_records.flat_map { |(_,rec)| rec }
34
+ records = through_records.flat_map do |record|
35
+ source_records_by_owner[record]
36
+ end
28
37
 
29
- preloaders = preloader.preload(middle_records,
30
- source_reflection.name,
31
- reflection_scope)
38
+ records.compact!
39
+ records.sort_by! { |rhs| preload_index[rhs] } if scope.order_values.any?
40
+ records.uniq! if scope.distinct_value
41
+ result[owner] = records
42
+ end
43
+ end
32
44
 
33
- @preloaded_records = preloaders.flat_map(&:preloaded_records)
45
+ private
46
+ def source_preloaders
47
+ @source_preloaders ||= PRELOADER.preload(middle_records, source_reflection.name, scope)
48
+ end
34
49
 
35
- middle_to_pl = preloaders.each_with_object({}) do |pl,h|
36
- pl.owners.each { |middle|
37
- h[middle] = pl
38
- }
50
+ def middle_records
51
+ through_preloaders.flat_map(&:preloaded_records)
39
52
  end
40
53
 
41
- through_records.each_with_object({}) do |(lhs,center), records_by_owner|
42
- pl_to_middle = center.group_by { |record| middle_to_pl[record] }
54
+ def through_preloaders
55
+ @through_preloaders ||= PRELOADER.preload(owners, through_reflection.name, through_scope)
56
+ end
43
57
 
44
- records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
45
- rhs_records = middles.flat_map { |r|
46
- association = r.association source_reflection.name
58
+ def through_reflection
59
+ reflection.through_reflection
60
+ end
47
61
 
48
- target_records_from_association(association)
49
- }.compact
62
+ def source_reflection
63
+ reflection.source_reflection
64
+ end
50
65
 
51
- # Respect the order on `reflection_scope` if it exists, else use the natural order.
52
- if reflection_scope.values[:order].present?
53
- @id_map ||= id_to_index_map @preloaded_records
54
- rhs_records.sort_by { |rhs| @id_map[rhs] }
55
- else
56
- rhs_records
57
- end
66
+ def preload_index
67
+ @preload_index ||= preloaded_records.each_with_object({}).with_index do |(record, result), index|
68
+ result[record] = index
58
69
  end
59
70
  end
60
- end
61
71
 
62
- private
72
+ def through_scope
73
+ scope = through_reflection.klass.unscoped
74
+ options = reflection.options
63
75
 
64
- def id_to_index_map(ids)
65
- id_map = {}
66
- ids.each_with_index { |id, index| id_map[id] = index }
67
- id_map
68
- end
76
+ values = reflection_scope.values
77
+ if annotations = values[:annotate]
78
+ scope.annotate!(*annotations)
79
+ end
69
80
 
70
- def reset_association(owners, association_name)
71
- should_reset = (through_scope != through_reflection.klass.unscoped) ||
72
- (reflection.options[:source_type] && through_reflection.collection?)
81
+ if options[:source_type]
82
+ scope.where! reflection.foreign_type => options[:source_type]
83
+ elsif !reflection_scope.where_clause.empty?
84
+ scope.where_clause = reflection_scope.where_clause
73
85
 
74
- # Don't cache the association - we would only be caching a subset
75
- if should_reset
76
- owners.each { |owner|
77
- owner.association(association_name).reset
78
- }
79
- end
80
- end
86
+ if includes = values[:includes]
87
+ scope.includes!(source_reflection.name => includes)
88
+ else
89
+ scope.includes!(source_reflection.name)
90
+ end
81
91
 
82
- def through_scope
83
- scope = through_reflection.klass.unscoped
84
- values = reflection_scope.values
92
+ if values[:references] && !values[:references].empty?
93
+ scope.references_values |= values[:references]
94
+ else
95
+ scope.references!(source_reflection.table_name)
96
+ end
85
97
 
86
- if options[:source_type]
87
- scope.where! reflection.foreign_type => options[:source_type]
88
- else
89
- unless reflection_scope.where_clause.empty?
90
- scope.includes_values = Array(values[:includes] || options[:source])
91
- scope.where_clause = reflection_scope.where_clause
92
98
  if joins = values[:joins]
93
99
  scope.joins!(source_reflection.name => joins)
94
100
  end
101
+
95
102
  if left_outer_joins = values[:left_outer_joins]
96
103
  scope.left_outer_joins!(source_reflection.name => left_outer_joins)
97
104
  end
98
- end
99
105
 
100
- scope.references! values[:references]
101
- if scope.eager_loading? && order_values = values[:order]
102
- scope = scope.order(order_values)
106
+ if scope.eager_loading? && order_values = values[:order]
107
+ scope = scope.order(order_values)
108
+ end
103
109
  end
104
- end
105
110
 
106
- scope
107
- end
108
-
109
- def target_records_from_association(association)
110
- association.loaded? ? association.target : association.reader
111
- end
111
+ scope
112
+ end
112
113
  end
113
114
  end
114
115
  end
@@ -1,16 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class SingularAssociation < Association #:nodoc:
4
6
  # Implements the reader method, e.g. foo.bar for Foo.has_one :bar
5
- def reader(force_reload = false)
6
- if force_reload && klass
7
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
8
- Passing an argument to force an association to reload is now
9
- deprecated and will be removed in Rails 5.1. Please call `reload_#{reflection.name}` instead.
10
- MSG
11
-
12
- klass.uncached { reload }
13
- elsif !loaded? || stale_target?
7
+ def reader
8
+ if !loaded? || stale_target?
14
9
  reload
15
10
  end
16
11
 
@@ -22,17 +17,8 @@ module ActiveRecord
22
17
  replace(record)
23
18
  end
24
19
 
25
- def create(attributes = {}, &block)
26
- _create_record(attributes, &block)
27
- end
28
-
29
- def create!(attributes = {}, &block)
30
- _create_record(attributes, true, &block)
31
- end
32
-
33
- def build(attributes = {})
34
- record = build_record(attributes)
35
- yield(record) if block_given?
20
+ def build(attributes = nil, &block)
21
+ record = build_record(attributes, &block)
36
22
  set_new_record(record)
37
23
  record
38
24
  end
@@ -40,35 +26,17 @@ module ActiveRecord
40
26
  # Implements the reload reader method, e.g. foo.reload_bar for
41
27
  # Foo.has_one :bar
42
28
  def force_reload_reader
43
- klass.uncached { reload }
29
+ reload(true)
44
30
  target
45
31
  end
46
32
 
47
33
  private
48
-
49
- def create_scope
50
- scope.scope_for_create.stringify_keys.except(klass.primary_key)
51
- end
52
-
53
- def get_records
54
- return scope.limit(1).records if skip_statement_cache?
55
-
56
- conn = klass.connection
57
- sc = reflection.association_scope_cache(conn, owner) do
58
- StatementCache.create(conn) { |params|
59
- as = AssociationScope.create { params.bind }
60
- target_scope.merge(as.scope(self, conn)).limit(1)
61
- }
62
- end
63
-
64
- binds = AssociationScope.get_bind_values(owner, reflection.chain)
65
- sc.execute binds, klass, klass.connection
34
+ def scope_for_create
35
+ super.except!(klass.primary_key)
66
36
  end
67
37
 
68
38
  def find_target
69
- if record = get_records.first
70
- set_inverse_instance record
71
- end
39
+ super.first
72
40
  end
73
41
 
74
42
  def replace(record)
@@ -79,9 +47,8 @@ module ActiveRecord
79
47
  replace(record)
80
48
  end
81
49
 
82
- def _create_record(attributes, raise_error = false)
83
- record = build_record(attributes)
84
- yield(record) if block_given?
50
+ def _create_record(attributes, raise_error = false, &block)
51
+ record = build_record(attributes, &block)
85
52
  saved = record.save
86
53
  set_new_record(record)
87
54
  raise RecordInvalid.new(record) if !saved && raise_error