activerecord 3.2.6 → 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 (371) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +611 -6417
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +44 -47
  5. data/examples/performance.rb +79 -71
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +268 -238
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +173 -81
  11. data/lib/active_record/associations/association_scope.rb +124 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -38
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +11 -9
  14. data/lib/active_record/associations/builder/association.rb +113 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +105 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +53 -56
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +98 -41
  18. data/lib/active_record/associations/builder/has_many.rb +11 -63
  19. data/lib/active_record/associations/builder/has_one.rb +47 -45
  20. data/lib/active_record/associations/builder/singular_association.rb +30 -18
  21. data/lib/active_record/associations/collection_association.rb +217 -295
  22. data/lib/active_record/associations/collection_proxy.rb +1074 -77
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +78 -50
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -61
  26. data/lib/active_record/associations/has_one_association.rb +75 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +45 -119
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +208 -164
  32. data/lib/active_record/associations/preloader/association.rb +93 -87
  33. data/lib/active_record/associations/preloader/through_association.rb +87 -38
  34. data/lib/active_record/associations/preloader.rb +134 -110
  35. data/lib/active_record/associations/singular_association.rb +19 -24
  36. data/lib/active_record/associations/through_association.rb +61 -27
  37. data/lib/active_record/associations.rb +1766 -1505
  38. data/lib/active_record/attribute_assignment.rb +57 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +58 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +187 -67
  42. data/lib/active_record/attribute_methods/primary_key.rb +100 -78
  43. data/lib/active_record/attribute_methods/query.rb +10 -8
  44. data/lib/active_record/attribute_methods/read.rb +29 -118
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -72
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -42
  47. data/lib/active_record/attribute_methods/write.rb +36 -44
  48. data/lib/active_record/attribute_methods.rb +306 -161
  49. data/lib/active_record/attributes.rb +279 -0
  50. data/lib/active_record/autosave_association.rb +324 -238
  51. data/lib/active_record/base.rb +114 -507
  52. data/lib/active_record/callbacks.rb +147 -83
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +962 -279
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +32 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +331 -209
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -23
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +201 -65
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +510 -289
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1182 -313
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +585 -120
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +610 -463
  68. data/lib/active_record/connection_adapters/column.rb +58 -233
  69. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +75 -207
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +695 -1052
  116. data/lib/active_record/connection_adapters/schema_cache.rb +115 -24
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +528 -26
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +267 -0
  128. data/lib/active_record/core.rb +599 -0
  129. data/lib/active_record/counter_cache.rb +177 -103
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +107 -64
  136. data/lib/active_record/enum.rb +274 -0
  137. data/lib/active_record/errors.rb +254 -61
  138. data/lib/active_record/explain.rb +35 -70
  139. data/lib/active_record/explain_registry.rb +32 -0
  140. data/lib/active_record/explain_subscriber.rb +18 -8
  141. data/lib/active_record/fixture_set/file.rb +82 -0
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +291 -475
  147. data/lib/active_record/gem_version.rb +17 -0
  148. data/lib/active_record/inheritance.rb +219 -100
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +175 -17
  151. data/lib/active_record/internal_metadata.rb +53 -0
  152. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  153. data/lib/active_record/locale/en.yml +9 -1
  154. data/lib/active_record/locking/optimistic.rb +106 -92
  155. data/lib/active_record/locking/pessimistic.rb +23 -11
  156. data/lib/active_record/log_subscriber.rb +80 -30
  157. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  158. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  159. data/lib/active_record/middleware/database_selector.rb +75 -0
  160. data/lib/active_record/migration/command_recorder.rb +235 -56
  161. data/lib/active_record/migration/compatibility.rb +244 -0
  162. data/lib/active_record/migration/join_table.rb +17 -0
  163. data/lib/active_record/migration.rb +917 -301
  164. data/lib/active_record/model_schema.rb +351 -175
  165. data/lib/active_record/nested_attributes.rb +366 -235
  166. data/lib/active_record/no_touching.rb +65 -0
  167. data/lib/active_record/null_relation.rb +68 -0
  168. data/lib/active_record/persistence.rb +761 -166
  169. data/lib/active_record/query_cache.rb +22 -44
  170. data/lib/active_record/querying.rb +55 -31
  171. data/lib/active_record/railtie.rb +185 -47
  172. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  173. data/lib/active_record/railties/console_sandbox.rb +5 -4
  174. data/lib/active_record/railties/controller_runtime.rb +35 -33
  175. data/lib/active_record/railties/databases.rake +366 -463
  176. data/lib/active_record/readonly_attributes.rb +4 -6
  177. data/lib/active_record/reflection.rb +736 -228
  178. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  179. data/lib/active_record/relation/batches.rb +252 -52
  180. data/lib/active_record/relation/calculations.rb +340 -270
  181. data/lib/active_record/relation/delegation.rb +117 -36
  182. data/lib/active_record/relation/finder_methods.rb +439 -286
  183. data/lib/active_record/relation/from_clause.rb +26 -0
  184. data/lib/active_record/relation/merger.rb +184 -0
  185. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  186. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  187. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  188. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  189. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  190. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  191. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder.rb +131 -39
  193. data/lib/active_record/relation/query_attribute.rb +50 -0
  194. data/lib/active_record/relation/query_methods.rb +1163 -221
  195. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  196. data/lib/active_record/relation/spawn_methods.rb +49 -120
  197. data/lib/active_record/relation/where_clause.rb +190 -0
  198. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  199. data/lib/active_record/relation.rb +671 -349
  200. data/lib/active_record/result.rb +149 -15
  201. data/lib/active_record/runtime_registry.rb +24 -0
  202. data/lib/active_record/sanitization.rb +153 -133
  203. data/lib/active_record/schema.rb +22 -19
  204. data/lib/active_record/schema_dumper.rb +178 -112
  205. data/lib/active_record/schema_migration.rb +60 -0
  206. data/lib/active_record/scoping/default.rb +107 -98
  207. data/lib/active_record/scoping/named.rb +130 -115
  208. data/lib/active_record/scoping.rb +77 -123
  209. data/lib/active_record/secure_token.rb +40 -0
  210. data/lib/active_record/serialization.rb +10 -6
  211. data/lib/active_record/statement_cache.rb +148 -0
  212. data/lib/active_record/store.rb +256 -16
  213. data/lib/active_record/suppressor.rb +61 -0
  214. data/lib/active_record/table_metadata.rb +75 -0
  215. data/lib/active_record/tasks/database_tasks.rb +506 -0
  216. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  217. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  218. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  219. data/lib/active_record/test_databases.rb +23 -0
  220. data/lib/active_record/test_fixtures.rb +224 -0
  221. data/lib/active_record/timestamp.rb +93 -39
  222. data/lib/active_record/touch_later.rb +66 -0
  223. data/lib/active_record/transactions.rb +260 -129
  224. data/lib/active_record/translation.rb +3 -1
  225. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  226. data/lib/active_record/type/date.rb +9 -0
  227. data/lib/active_record/type/date_time.rb +9 -0
  228. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  229. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  230. data/lib/active_record/type/internal/timezone.rb +17 -0
  231. data/lib/active_record/type/json.rb +30 -0
  232. data/lib/active_record/type/serialized.rb +71 -0
  233. data/lib/active_record/type/text.rb +11 -0
  234. data/lib/active_record/type/time.rb +21 -0
  235. data/lib/active_record/type/type_map.rb +62 -0
  236. data/lib/active_record/type/unsigned_integer.rb +17 -0
  237. data/lib/active_record/type.rb +78 -0
  238. data/lib/active_record/type_caster/connection.rb +34 -0
  239. data/lib/active_record/type_caster/map.rb +20 -0
  240. data/lib/active_record/type_caster.rb +9 -0
  241. data/lib/active_record/validations/absence.rb +25 -0
  242. data/lib/active_record/validations/associated.rb +35 -18
  243. data/lib/active_record/validations/length.rb +26 -0
  244. data/lib/active_record/validations/presence.rb +68 -0
  245. data/lib/active_record/validations/uniqueness.rb +123 -77
  246. data/lib/active_record/validations.rb +54 -43
  247. data/lib/active_record/version.rb +7 -7
  248. data/lib/active_record.rb +97 -49
  249. data/lib/arel/alias_predication.rb +9 -0
  250. data/lib/arel/attributes/attribute.rb +37 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/collectors/bind.rb +24 -0
  253. data/lib/arel/collectors/composite.rb +31 -0
  254. data/lib/arel/collectors/plain_string.rb +20 -0
  255. data/lib/arel/collectors/sql_string.rb +20 -0
  256. data/lib/arel/collectors/substitute_binds.rb +28 -0
  257. data/lib/arel/crud.rb +42 -0
  258. data/lib/arel/delete_manager.rb +18 -0
  259. data/lib/arel/errors.rb +9 -0
  260. data/lib/arel/expressions.rb +29 -0
  261. data/lib/arel/factory_methods.rb +49 -0
  262. data/lib/arel/insert_manager.rb +49 -0
  263. data/lib/arel/math.rb +45 -0
  264. data/lib/arel/nodes/and.rb +32 -0
  265. data/lib/arel/nodes/ascending.rb +23 -0
  266. data/lib/arel/nodes/binary.rb +52 -0
  267. data/lib/arel/nodes/bind_param.rb +36 -0
  268. data/lib/arel/nodes/case.rb +55 -0
  269. data/lib/arel/nodes/casted.rb +50 -0
  270. data/lib/arel/nodes/comment.rb +29 -0
  271. data/lib/arel/nodes/count.rb +12 -0
  272. data/lib/arel/nodes/delete_statement.rb +45 -0
  273. data/lib/arel/nodes/descending.rb +23 -0
  274. data/lib/arel/nodes/equality.rb +18 -0
  275. data/lib/arel/nodes/extract.rb +24 -0
  276. data/lib/arel/nodes/false.rb +16 -0
  277. data/lib/arel/nodes/full_outer_join.rb +8 -0
  278. data/lib/arel/nodes/function.rb +44 -0
  279. data/lib/arel/nodes/grouping.rb +8 -0
  280. data/lib/arel/nodes/in.rb +8 -0
  281. data/lib/arel/nodes/infix_operation.rb +80 -0
  282. data/lib/arel/nodes/inner_join.rb +8 -0
  283. data/lib/arel/nodes/insert_statement.rb +37 -0
  284. data/lib/arel/nodes/join_source.rb +20 -0
  285. data/lib/arel/nodes/matches.rb +18 -0
  286. data/lib/arel/nodes/named_function.rb +23 -0
  287. data/lib/arel/nodes/node.rb +50 -0
  288. data/lib/arel/nodes/node_expression.rb +13 -0
  289. data/lib/arel/nodes/outer_join.rb +8 -0
  290. data/lib/arel/nodes/over.rb +15 -0
  291. data/lib/arel/nodes/regexp.rb +16 -0
  292. data/lib/arel/nodes/right_outer_join.rb +8 -0
  293. data/lib/arel/nodes/select_core.rb +67 -0
  294. data/lib/arel/nodes/select_statement.rb +41 -0
  295. data/lib/arel/nodes/sql_literal.rb +16 -0
  296. data/lib/arel/nodes/string_join.rb +11 -0
  297. data/lib/arel/nodes/table_alias.rb +27 -0
  298. data/lib/arel/nodes/terminal.rb +16 -0
  299. data/lib/arel/nodes/true.rb +16 -0
  300. data/lib/arel/nodes/unary.rb +45 -0
  301. data/lib/arel/nodes/unary_operation.rb +20 -0
  302. data/lib/arel/nodes/unqualified_column.rb +22 -0
  303. data/lib/arel/nodes/update_statement.rb +41 -0
  304. data/lib/arel/nodes/values_list.rb +9 -0
  305. data/lib/arel/nodes/window.rb +126 -0
  306. data/lib/arel/nodes/with.rb +11 -0
  307. data/lib/arel/nodes.rb +68 -0
  308. data/lib/arel/order_predications.rb +13 -0
  309. data/lib/arel/predications.rb +257 -0
  310. data/lib/arel/select_manager.rb +271 -0
  311. data/lib/arel/table.rb +110 -0
  312. data/lib/arel/tree_manager.rb +72 -0
  313. data/lib/arel/update_manager.rb +34 -0
  314. data/lib/arel/visitors/depth_first.rb +204 -0
  315. data/lib/arel/visitors/dot.rb +297 -0
  316. data/lib/arel/visitors/ibm_db.rb +34 -0
  317. data/lib/arel/visitors/informix.rb +62 -0
  318. data/lib/arel/visitors/mssql.rb +157 -0
  319. data/lib/arel/visitors/mysql.rb +83 -0
  320. data/lib/arel/visitors/oracle.rb +159 -0
  321. data/lib/arel/visitors/oracle12.rb +66 -0
  322. data/lib/arel/visitors/postgresql.rb +110 -0
  323. data/lib/arel/visitors/sqlite.rb +39 -0
  324. data/lib/arel/visitors/to_sql.rb +889 -0
  325. data/lib/arel/visitors/visitor.rb +46 -0
  326. data/lib/arel/visitors/where_sql.rb +23 -0
  327. data/lib/arel/visitors.rb +20 -0
  328. data/lib/arel/window_predications.rb +9 -0
  329. data/lib/arel.rb +51 -0
  330. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  331. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +59 -9
  333. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  334. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  335. data/lib/rails/generators/active_record/migration.rb +41 -8
  336. data/lib/rails/generators/active_record/model/model_generator.rb +24 -22
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  339. data/lib/rails/generators/active_record.rb +10 -16
  340. metadata +285 -149
  341. data/examples/associations.png +0 -0
  342. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  343. data/lib/active_record/associations/join_helper.rb +0 -55
  344. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  345. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  346. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  347. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  348. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  349. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  350. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  351. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  352. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  353. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -188
  354. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -426
  355. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -579
  356. data/lib/active_record/dynamic_finder_match.rb +0 -68
  357. data/lib/active_record/dynamic_scope_match.rb +0 -23
  358. data/lib/active_record/fixtures/file.rb +0 -65
  359. data/lib/active_record/identity_map.rb +0 -162
  360. data/lib/active_record/observer.rb +0 -121
  361. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  362. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  363. data/lib/active_record/session_store.rb +0 -358
  364. data/lib/active_record/test_case.rb +0 -73
  365. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  366. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  367. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  368. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  369. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  370. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  371. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,66 +1,115 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class Preloader
4
- module ThroughAssociation #:nodoc:
6
+ class ThroughAssociation < Association # :nodoc:
7
+ PRELOADER = ActiveRecord::Associations::Preloader.new
5
8
 
6
- def through_reflection
7
- reflection.through_reflection
9
+ def initialize(*)
10
+ super
11
+ @already_loaded = owners.first.association(through_reflection.name).loaded?
8
12
  end
9
13
 
10
- def source_reflection
11
- reflection.source_reflection
14
+ def preloaded_records
15
+ @preloaded_records ||= source_preloaders.flat_map(&:preloaded_records)
12
16
  end
13
17
 
14
- def associated_records_by_owner
15
- through_records = through_records_by_owner
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)
22
+
23
+ @records_by_owner = owners.each_with_object({}) do |owner, result|
24
+ through_records = through_records_by_owner[owner] || []
25
+
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
16
33
 
17
- ActiveRecord::Associations::Preloader.new(
18
- through_records.values.flatten,
19
- source_reflection.name, options
20
- ).run
34
+ records = through_records.flat_map do |record|
35
+ source_records_by_owner[record]
36
+ end
21
37
 
22
- through_records.each do |owner, records|
23
- records.map! { |r| r.send(source_reflection.name) }.flatten!
24
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
25
42
  end
26
43
  end
27
44
 
28
45
  private
46
+ def source_preloaders
47
+ @source_preloaders ||= PRELOADER.preload(middle_records, source_reflection.name, scope)
48
+ end
49
+
50
+ def middle_records
51
+ through_preloaders.flat_map(&:preloaded_records)
52
+ end
53
+
54
+ def through_preloaders
55
+ @through_preloaders ||= PRELOADER.preload(owners, through_reflection.name, through_scope)
56
+ end
57
+
58
+ def through_reflection
59
+ reflection.through_reflection
60
+ end
61
+
62
+ def source_reflection
63
+ reflection.source_reflection
64
+ end
29
65
 
30
- def through_records_by_owner
31
- ActiveRecord::Associations::Preloader.new(
32
- owners, through_reflection.name,
33
- through_options
34
- ).run
66
+ def preload_index
67
+ @preload_index ||= preloaded_records.each_with_object({}).with_index do |(record, result), index|
68
+ result[record] = index
69
+ end
70
+ end
35
71
 
36
- Hash[owners.map do |owner|
37
- through_records = Array.wrap(owner.send(through_reflection.name))
72
+ def through_scope
73
+ scope = through_reflection.klass.unscoped
74
+ options = reflection.options
38
75
 
39
- # Dont cache the association - we would only be caching a subset
40
- if reflection.options[:source_type] && through_reflection.collection?
41
- owner.association(through_reflection.name).reset
76
+ values = reflection_scope.values
77
+ if annotations = values[:annotate]
78
+ scope.annotate!(*annotations)
42
79
  end
43
80
 
44
- [owner, through_records]
45
- end]
46
- end
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
47
85
 
48
- def through_options
49
- through_options = {}
86
+ if includes = values[:includes]
87
+ scope.includes!(source_reflection.name => includes)
88
+ else
89
+ scope.includes!(source_reflection.name)
90
+ end
50
91
 
51
- if options[:source_type]
52
- through_options[:conditions] = { reflection.foreign_type => options[:source_type] }
53
- else
54
- if options[:conditions]
55
- through_options[:include] = options[:include] || options[:source]
56
- through_options[:conditions] = options[:conditions]
92
+ if values[:references] && !values[:references].empty?
93
+ scope.references!(values[:references])
94
+ else
95
+ scope.references!(source_reflection.table_name)
96
+ end
97
+
98
+ if joins = values[:joins]
99
+ scope.joins!(source_reflection.name => joins)
100
+ end
101
+
102
+ if left_outer_joins = values[:left_outer_joins]
103
+ scope.left_outer_joins!(source_reflection.name => left_outer_joins)
104
+ end
105
+
106
+ if scope.eager_loading? && order_values = values[:order]
107
+ scope = scope.order(order_values)
108
+ end
57
109
  end
58
110
 
59
- through_options[:order] = options[:order]
111
+ scope
60
112
  end
61
-
62
- through_options
63
- end
64
113
  end
65
114
  end
66
115
  end
@@ -1,48 +1,52 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  # Implements the details of eager loading of Active Record associations.
4
6
  #
5
- # Note that 'eager loading' and 'preloading' are actually the same thing.
6
- # However, there are two different eager loading strategies.
7
+ # Suppose that you have the following two Active Record models:
8
+ #
9
+ # class Author < ActiveRecord::Base
10
+ # # columns: name, age
11
+ # has_many :books
12
+ # end
13
+ #
14
+ # class Book < ActiveRecord::Base
15
+ # # columns: title, sales, author_id
16
+ # end
17
+ #
18
+ # When you load an author with all associated books Active Record will make
19
+ # multiple queries like this:
20
+ #
21
+ # Author.includes(:books).where(name: ['bell hooks', 'Homer']).to_a
7
22
  #
8
- # The first one is by using table joins. This was only strategy available
9
- # prior to Rails 2.1. Suppose that you have an Author model with columns
10
- # 'name' and 'age', and a Book model with columns 'name' and 'sales'. Using
11
- # this strategy, Active Record would try to retrieve all data for an author
12
- # and all of its books via a single query:
23
+ # => SELECT `authors`.* FROM `authors` WHERE `name` IN ('bell hooks', 'Homer')
24
+ # => SELECT `books`.* FROM `books` WHERE `author_id` IN (2, 5)
13
25
  #
14
- # SELECT * FROM authors
15
- # LEFT OUTER JOIN books ON authors.id = books.id
16
- # WHERE authors.name = 'Ken Akamatsu'
26
+ # Active Record saves the ids of the records from the first query to use in
27
+ # the second. Depending on the number of associations involved there can be
28
+ # arbitrarily many SQL queries made.
17
29
  #
18
- # However, this could result in many rows that contain redundant data. After
19
- # having received the first row, we already have enough data to instantiate
20
- # the Author object. In all subsequent rows, only the data for the joined
21
- # 'books' table is useful; the joined 'authors' data is just redundant, and
22
- # processing this redundant data takes memory and CPU time. The problem
23
- # quickly becomes worse and worse as the level of eager loading increases
24
- # (i.e. if Active Record is to eager load the associations' associations as
25
- # well).
30
+ # However, if there is a WHERE clause that spans across tables Active
31
+ # Record will fall back to a slightly more resource-intensive single query:
32
+ #
33
+ # Author.includes(:books).where(books: {title: 'Illiad'}).to_a
34
+ # => SELECT `authors`.`id` AS t0_r0, `authors`.`name` AS t0_r1, `authors`.`age` AS t0_r2,
35
+ # `books`.`id` AS t1_r0, `books`.`title` AS t1_r1, `books`.`sales` AS t1_r2
36
+ # FROM `authors`
37
+ # LEFT OUTER JOIN `books` ON `authors`.`id` = `books`.`author_id`
38
+ # WHERE `books`.`title` = 'Illiad'
39
+ #
40
+ # This could result in many rows that contain redundant data and it performs poorly at scale
41
+ # and is therefore only used when necessary.
26
42
  #
27
- # The second strategy is to use multiple database queries, one for each
28
- # level of association. Since Rails 2.1, this is the default strategy. In
29
- # situations where a table join is necessary (e.g. when the +:conditions+
30
- # option references an association's column), it will fallback to the table
31
- # join strategy.
32
43
  class Preloader #:nodoc:
33
- autoload :Association, 'active_record/associations/preloader/association'
34
- autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
35
- autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
36
- autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
44
+ extend ActiveSupport::Autoload
37
45
 
38
- autoload :HasMany, 'active_record/associations/preloader/has_many'
39
- autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
40
- autoload :HasOne, 'active_record/associations/preloader/has_one'
41
- autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
42
- autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
43
- autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
44
-
45
- attr_reader :records, :associations, :options, :model
46
+ eager_autoload do
47
+ autoload :Association, "active_record/associations/preloader/association"
48
+ autoload :ThroughAssociation, "active_record/associations/preloader/through_association"
49
+ end
46
50
 
47
51
  # Eager loads the named associations for the given Active Record record(s).
48
52
  #
@@ -68,7 +72,7 @@ module ActiveRecord
68
72
  # books.
69
73
  # - a Hash which specifies multiple association names, as well as
70
74
  # association names for the to-be-preloaded association objects. For
71
- # example, specifying <tt>{ :author => :avatar }</tt> will preload a
75
+ # example, specifying <tt>{ author: :avatar }</tt> will preload a
72
76
  # book's author, as well as that author's avatar.
73
77
  #
74
78
  # +:associations+ has the same format as the +:include+ option for
@@ -76,102 +80,122 @@ module ActiveRecord
76
80
  #
77
81
  # :books
78
82
  # [ :books, :author ]
79
- # { :author => :avatar }
80
- # [ :books, { :author => :avatar } ]
81
- #
82
- # +options+ contains options that will be passed to ActiveRecord::Base#find
83
- # (which is called under the hood for preloading records). But it is passed
84
- # only one level deep in the +associations+ argument, i.e. it's not passed
85
- # to the child associations when +associations+ is a Hash.
86
- def initialize(records, associations, options = {})
87
- @records = Array.wrap(records).compact.uniq
88
- @associations = Array.wrap(associations)
89
- @options = options
90
- end
83
+ # { author: :avatar }
84
+ # [ :books, { author: :avatar } ]
85
+ def preload(records, associations, preload_scope = nil)
86
+ records = Array.wrap(records).compact
91
87
 
92
- def run
93
- unless records.empty?
94
- associations.each { |association| preload(association) }
88
+ if records.empty?
89
+ []
90
+ else
91
+ Array.wrap(associations).flat_map { |association|
92
+ preloaders_on association, records, preload_scope
93
+ }
95
94
  end
96
95
  end
97
96
 
98
97
  private
99
98
 
100
- def preload(association)
101
- case association
102
- when Hash
103
- preload_hash(association)
104
- when String, Symbol
105
- preload_one(association.to_sym)
106
- else
107
- raise ArgumentError, "#{association.inspect} was not recognised for preload"
99
+ # Loads all the given data into +records+ for the +association+.
100
+ def preloaders_on(association, records, scope, polymorphic_parent = false)
101
+ case association
102
+ when Hash
103
+ preloaders_for_hash(association, records, scope, polymorphic_parent)
104
+ when Symbol, String
105
+ preloaders_for_one(association, records, scope, polymorphic_parent)
106
+ else
107
+ raise ArgumentError, "#{association.inspect} was not recognized for preload"
108
+ end
108
109
  end
109
- end
110
110
 
111
- def preload_hash(association)
112
- association.each do |parent, child|
113
- Preloader.new(records, parent, options).run
114
- Preloader.new(records.map { |record| record.send(parent) }.flatten, child).run
111
+ def preloaders_for_hash(association, records, scope, polymorphic_parent)
112
+ association.flat_map { |parent, child|
113
+ grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
114
+ loaders = preloaders_for_reflection(reflection, reflection_records, scope)
115
+ recs = loaders.flat_map(&:preloaded_records)
116
+ child_polymorphic_parent = reflection && reflection.options[:polymorphic]
117
+ loaders.concat Array.wrap(child).flat_map { |assoc|
118
+ preloaders_on assoc, recs, scope, child_polymorphic_parent
119
+ }
120
+ loaders
121
+ end
122
+ }
115
123
  end
116
- end
117
124
 
118
- # Not all records have the same class, so group then preload group on the reflection
119
- # itself so that if various subclass share the same association then we do not split
120
- # them unnecessarily
121
- #
122
- # Additionally, polymorphic belongs_to associations can have multiple associated
123
- # classes, depending on the polymorphic_type field. So we group by the classes as
124
- # well.
125
- def preload_one(association)
126
- grouped_records(association).each do |reflection, klasses|
127
- klasses.each do |klass, records|
128
- preloader_for(reflection).new(klass, records, reflection, options).run
125
+ # Loads all the given data into +records+ for a singular +association+.
126
+ #
127
+ # Functions by instantiating a preloader class such as Preloader::Association and
128
+ # call the +run+ method for each passed in class in the +records+ argument.
129
+ #
130
+ # Not all records have the same class, so group then preload group on the reflection
131
+ # itself so that if various subclass share the same association then we do not split
132
+ # them unnecessarily
133
+ #
134
+ # Additionally, polymorphic belongs_to associations can have multiple associated
135
+ # classes, depending on the polymorphic_type field. So we group by the classes as
136
+ # well.
137
+ def preloaders_for_one(association, records, scope, polymorphic_parent)
138
+ grouped_records(association, records, polymorphic_parent)
139
+ .flat_map do |reflection, reflection_records|
140
+ preloaders_for_reflection reflection, reflection_records, scope
141
+ end
142
+ end
143
+
144
+ def preloaders_for_reflection(reflection, records, scope)
145
+ records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
146
+ preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope).run
129
147
  end
130
148
  end
131
- end
132
149
 
133
- def grouped_records(association)
134
- Hash[
135
- records_by_reflection(association).map do |reflection, records|
136
- [reflection, records.group_by { |record| association_klass(reflection, record) }]
150
+ def grouped_records(association, records, polymorphic_parent)
151
+ h = {}
152
+ records.each do |record|
153
+ reflection = record.class._reflect_on_association(association)
154
+ next if polymorphic_parent && !reflection || !record.association(association).klass
155
+ (h[reflection] ||= []) << record
137
156
  end
138
- ]
139
- end
157
+ h
158
+ end
140
159
 
141
- def records_by_reflection(association)
142
- records.group_by do |record|
143
- reflection = record.class.reflections[association]
160
+ class AlreadyLoaded # :nodoc:
161
+ def initialize(klass, owners, reflection, preload_scope)
162
+ @owners = owners
163
+ @reflection = reflection
164
+ end
144
165
 
145
- unless reflection
146
- raise ActiveRecord::ConfigurationError, "Association named '#{association}' was not found; " \
147
- "perhaps you misspelled it?"
166
+ def run
167
+ self
148
168
  end
149
169
 
150
- reflection
151
- end
152
- end
170
+ def preloaded_records
171
+ @preloaded_records ||= records_by_owner.flat_map(&:last)
172
+ end
153
173
 
154
- def association_klass(reflection, record)
155
- if reflection.macro == :belongs_to && reflection.options[:polymorphic]
156
- klass = record.send(reflection.foreign_type)
157
- klass && klass.constantize
158
- else
159
- reflection.klass
174
+ def records_by_owner
175
+ @records_by_owner ||= owners.each_with_object({}) do |owner, result|
176
+ result[owner] = Array(owner.association(reflection.name).target)
177
+ end
178
+ end
179
+
180
+ private
181
+ attr_reader :owners, :reflection
160
182
  end
161
- end
162
183
 
163
- def preloader_for(reflection)
164
- case reflection.macro
165
- when :has_many
166
- reflection.options[:through] ? HasManyThrough : HasMany
167
- when :has_one
168
- reflection.options[:through] ? HasOneThrough : HasOne
169
- when :has_and_belongs_to_many
170
- HasAndBelongsToMany
171
- when :belongs_to
172
- BelongsTo
184
+ # Returns a class containing the logic needed to load preload the data
185
+ # and attach it to a relation. The class returned implements a `run` method
186
+ # that accepts a preloader.
187
+ def preloader_for(reflection, owners)
188
+ if owners.first.association(reflection.name).loaded?
189
+ return AlreadyLoaded
190
+ end
191
+ reflection.check_preloadable!
192
+
193
+ if reflection.options[:through]
194
+ ThroughAssociation
195
+ else
196
+ Association
197
+ end
173
198
  end
174
- end
175
199
  end
176
200
  end
177
201
  end
@@ -1,48 +1,44 @@
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
7
- klass.uncached { reload }
8
- elsif !loaded? || stale_target?
7
+ def reader
8
+ if !loaded? || stale_target?
9
9
  reload
10
10
  end
11
11
 
12
12
  target
13
13
  end
14
14
 
15
- # Implements the writer method, e.g. foo.items= for Foo.has_many :items
15
+ # Implements the writer method, e.g. foo.bar= for Foo.belongs_to :bar
16
16
  def writer(record)
17
17
  replace(record)
18
18
  end
19
19
 
20
- def create(attributes = {}, options = {}, &block)
21
- create_record(attributes, options, &block)
22
- end
23
-
24
- def create!(attributes = {}, options = {}, &block)
25
- create_record(attributes, options, true, &block)
26
- end
27
-
28
- def build(attributes = {}, options = {})
29
- record = build_record(attributes, options)
30
- yield(record) if block_given?
20
+ def build(attributes = {}, &block)
21
+ record = build_record(attributes, &block)
31
22
  set_new_record(record)
32
23
  record
33
24
  end
34
25
 
35
- private
26
+ # Implements the reload reader method, e.g. foo.reload_bar for
27
+ # Foo.has_one :bar
28
+ def force_reload_reader
29
+ reload(true)
30
+ target
31
+ end
36
32
 
37
- def create_scope
38
- scoped.scope_for_create.stringify_keys.except(klass.primary_key)
33
+ private
34
+ def scope_for_create
35
+ super.except!(klass.primary_key)
39
36
  end
40
37
 
41
38
  def find_target
42
- scoped.first.tap { |record| set_inverse_instance(record) }
39
+ super.first
43
40
  end
44
41
 
45
- # Implemented by subclasses
46
42
  def replace(record)
47
43
  raise NotImplementedError, "Subclasses must implement a replace(record) method"
48
44
  end
@@ -51,9 +47,8 @@ module ActiveRecord
51
47
  replace(record)
52
48
  end
53
49
 
54
- def create_record(attributes, options, raise_error = false)
55
- record = build_record(attributes, options)
56
- yield(record) if block_given?
50
+ def _create_record(attributes, raise_error = false, &block)
51
+ record = build_record(attributes, &block)
57
52
  saved = record.save
58
53
  set_new_record(record)
59
54
  raise RecordInvalid.new(record) if !saved && raise_error