activerecord 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 (340) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1013 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +219 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record.rb +195 -0
  8. data/lib/active_record/aggregations.rb +285 -0
  9. data/lib/active_record/association_relation.rb +40 -0
  10. data/lib/active_record/associations.rb +1865 -0
  11. data/lib/active_record/associations/alias_tracker.rb +81 -0
  12. data/lib/active_record/associations/association.rb +332 -0
  13. data/lib/active_record/associations/association_scope.rb +166 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +124 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +36 -0
  16. data/lib/active_record/associations/builder/association.rb +136 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +130 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +72 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +114 -0
  20. data/lib/active_record/associations/builder/has_many.rb +19 -0
  21. data/lib/active_record/associations/builder/has_one.rb +64 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +44 -0
  23. data/lib/active_record/associations/collection_association.rb +498 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1128 -0
  25. data/lib/active_record/associations/foreign_association.rb +20 -0
  26. data/lib/active_record/associations/has_many_association.rb +136 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +220 -0
  28. data/lib/active_record/associations/has_one_association.rb +118 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency.rb +258 -0
  31. data/lib/active_record/associations/join_dependency/join_association.rb +80 -0
  32. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  33. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  34. data/lib/active_record/associations/preloader.rb +201 -0
  35. data/lib/active_record/associations/preloader/association.rb +133 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +116 -0
  37. data/lib/active_record/associations/singular_association.rb +59 -0
  38. data/lib/active_record/associations/through_association.rb +121 -0
  39. data/lib/active_record/attribute_assignment.rb +85 -0
  40. data/lib/active_record/attribute_decorators.rb +90 -0
  41. data/lib/active_record/attribute_methods.rb +420 -0
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +81 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +221 -0
  44. data/lib/active_record/attribute_methods/primary_key.rb +136 -0
  45. data/lib/active_record/attribute_methods/query.rb +41 -0
  46. data/lib/active_record/attribute_methods/read.rb +47 -0
  47. data/lib/active_record/attribute_methods/serialization.rb +90 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
  49. data/lib/active_record/attribute_methods/write.rb +61 -0
  50. data/lib/active_record/attributes.rb +279 -0
  51. data/lib/active_record/autosave_association.rb +508 -0
  52. data/lib/active_record/base.rb +328 -0
  53. data/lib/active_record/callbacks.rb +339 -0
  54. data/lib/active_record/coders/json.rb +15 -0
  55. data/lib/active_record/coders/yaml_column.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1165 -0
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +85 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +512 -0
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +154 -0
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +251 -0
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +713 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1475 -0
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +761 -0
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +821 -0
  69. data/lib/active_record/connection_adapters/column.rb +95 -0
  70. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +146 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +949 -0
  117. data/lib/active_record/connection_adapters/schema_cache.rb +141 -0
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +557 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +267 -0
  129. data/lib/active_record/core.rb +599 -0
  130. data/lib/active_record/counter_cache.rb +193 -0
  131. data/lib/active_record/database_configurations.rb +233 -0
  132. data/lib/active_record/database_configurations/database_config.rb +37 -0
  133. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  134. data/lib/active_record/database_configurations/url_config.rb +79 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +122 -0
  137. data/lib/active_record/enum.rb +274 -0
  138. data/lib/active_record/errors.rb +388 -0
  139. data/lib/active_record/explain.rb +50 -0
  140. data/lib/active_record/explain_registry.rb +32 -0
  141. data/lib/active_record/explain_subscriber.rb +34 -0
  142. data/lib/active_record/fixture_set/file.rb +82 -0
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +153 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  147. data/lib/active_record/fixtures.rb +738 -0
  148. data/lib/active_record/gem_version.rb +17 -0
  149. data/lib/active_record/inheritance.rb +293 -0
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +207 -0
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  154. data/lib/active_record/locale/en.yml +48 -0
  155. data/lib/active_record/locking/optimistic.rb +197 -0
  156. data/lib/active_record/locking/pessimistic.rb +89 -0
  157. data/lib/active_record/log_subscriber.rb +118 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +1397 -0
  162. data/lib/active_record/migration/command_recorder.rb +284 -0
  163. data/lib/active_record/migration/compatibility.rb +244 -0
  164. data/lib/active_record/migration/join_table.rb +17 -0
  165. data/lib/active_record/model_schema.rb +542 -0
  166. data/lib/active_record/nested_attributes.rb +600 -0
  167. data/lib/active_record/no_touching.rb +65 -0
  168. data/lib/active_record/null_relation.rb +68 -0
  169. data/lib/active_record/persistence.rb +967 -0
  170. data/lib/active_record/query_cache.rb +52 -0
  171. data/lib/active_record/querying.rb +82 -0
  172. data/lib/active_record/railtie.rb +263 -0
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +7 -0
  175. data/lib/active_record/railties/controller_runtime.rb +51 -0
  176. data/lib/active_record/railties/databases.rake +527 -0
  177. data/lib/active_record/readonly_attributes.rb +24 -0
  178. data/lib/active_record/reflection.rb +1042 -0
  179. data/lib/active_record/relation.rb +859 -0
  180. data/lib/active_record/relation/batches.rb +290 -0
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  182. data/lib/active_record/relation/calculations.rb +424 -0
  183. data/lib/active_record/relation/delegation.rb +130 -0
  184. data/lib/active_record/relation/finder_methods.rb +552 -0
  185. data/lib/active_record/relation/from_clause.rb +26 -0
  186. data/lib/active_record/relation/merger.rb +184 -0
  187. data/lib/active_record/relation/predicate_builder.rb +150 -0
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  195. data/lib/active_record/relation/query_attribute.rb +50 -0
  196. data/lib/active_record/relation/query_methods.rb +1359 -0
  197. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  198. data/lib/active_record/relation/spawn_methods.rb +77 -0
  199. data/lib/active_record/relation/where_clause.rb +190 -0
  200. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  201. data/lib/active_record/result.rb +168 -0
  202. data/lib/active_record/runtime_registry.rb +24 -0
  203. data/lib/active_record/sanitization.rb +214 -0
  204. data/lib/active_record/schema.rb +61 -0
  205. data/lib/active_record/schema_dumper.rb +270 -0
  206. data/lib/active_record/schema_migration.rb +60 -0
  207. data/lib/active_record/scoping.rb +106 -0
  208. data/lib/active_record/scoping/default.rb +151 -0
  209. data/lib/active_record/scoping/named.rb +217 -0
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +22 -0
  212. data/lib/active_record/statement_cache.rb +148 -0
  213. data/lib/active_record/store.rb +290 -0
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +75 -0
  216. data/lib/active_record/tasks/database_tasks.rb +506 -0
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +224 -0
  222. data/lib/active_record/timestamp.rb +167 -0
  223. data/lib/active_record/touch_later.rb +66 -0
  224. data/lib/active_record/transactions.rb +493 -0
  225. data/lib/active_record/translation.rb +24 -0
  226. data/lib/active_record/type.rb +78 -0
  227. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  228. data/lib/active_record/type/date.rb +9 -0
  229. data/lib/active_record/type/date_time.rb +9 -0
  230. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  231. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  232. data/lib/active_record/type/internal/timezone.rb +17 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +71 -0
  235. data/lib/active_record/type/text.rb +11 -0
  236. data/lib/active_record/type/time.rb +21 -0
  237. data/lib/active_record/type/type_map.rb +62 -0
  238. data/lib/active_record/type/unsigned_integer.rb +17 -0
  239. data/lib/active_record/type_caster.rb +9 -0
  240. data/lib/active_record/type_caster/connection.rb +34 -0
  241. data/lib/active_record/type_caster/map.rb +20 -0
  242. data/lib/active_record/validations.rb +94 -0
  243. data/lib/active_record/validations/absence.rb +25 -0
  244. data/lib/active_record/validations/associated.rb +60 -0
  245. data/lib/active_record/validations/length.rb +26 -0
  246. data/lib/active_record/validations/presence.rb +68 -0
  247. data/lib/active_record/validations/uniqueness.rb +226 -0
  248. data/lib/active_record/version.rb +10 -0
  249. data/lib/arel.rb +51 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +257 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +204 -0
  317. data/lib/arel/visitors/dot.rb +297 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +157 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +159 -0
  323. data/lib/arel/visitors/oracle12.rb +66 -0
  324. data/lib/arel/visitors/postgresql.rb +110 -0
  325. data/lib/arel/visitors/sqlite.rb +39 -0
  326. data/lib/arel/visitors/to_sql.rb +889 -0
  327. data/lib/arel/visitors/visitor.rb +46 -0
  328. data/lib/arel/visitors/where_sql.rb +23 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +19 -0
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration.rb +48 -0
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +75 -0
  335. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  336. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  337. data/lib/rails/generators/active_record/model/model_generator.rb +49 -0
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  340. metadata +415 -0
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
4
+
5
+ module ActiveRecord
6
+ module Associations
7
+ # Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
8
+ class AliasTracker # :nodoc:
9
+ def self.create(connection, initial_table, joins)
10
+ if joins.empty?
11
+ aliases = Hash.new(0)
12
+ else
13
+ aliases = Hash.new { |h, k|
14
+ h[k] = initial_count_for(connection, k, joins)
15
+ }
16
+ end
17
+ aliases[initial_table] = 1
18
+ new(connection, aliases)
19
+ end
20
+
21
+ def self.initial_count_for(connection, name, table_joins)
22
+ quoted_name = nil
23
+
24
+ counts = table_joins.map do |join|
25
+ if join.is_a?(Arel::Nodes::StringJoin)
26
+ # quoted_name should be case ignored as some database adapters (Oracle) return quoted name in uppercase
27
+ quoted_name ||= connection.quote_table_name(name)
28
+
29
+ # Table names + table aliases
30
+ join.left.scan(
31
+ /JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name}|#{name})\sON/i
32
+ ).size
33
+ elsif join.is_a?(Arel::Nodes::Join)
34
+ join.left.name == name ? 1 : 0
35
+ elsif join.is_a?(Hash)
36
+ join[name]
37
+ else
38
+ raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
39
+ end
40
+ end
41
+
42
+ counts.sum
43
+ end
44
+
45
+ # table_joins is an array of arel joins which might conflict with the aliases we assign here
46
+ def initialize(connection, aliases)
47
+ @aliases = aliases
48
+ @connection = connection
49
+ end
50
+
51
+ def aliased_table_for(table_name, aliased_name, type_caster)
52
+ if aliases[table_name].zero?
53
+ # If it's zero, we can have our table_name
54
+ aliases[table_name] = 1
55
+ Arel::Table.new(table_name, type_caster: type_caster)
56
+ else
57
+ # Otherwise, we need to use an alias
58
+ aliased_name = @connection.table_alias_for(aliased_name)
59
+
60
+ # Update the count
61
+ aliases[aliased_name] += 1
62
+
63
+ table_alias = if aliases[aliased_name] > 1
64
+ "#{truncate(aliased_name)}_#{aliases[aliased_name]}"
65
+ else
66
+ aliased_name
67
+ end
68
+ Arel::Table.new(table_name, type_caster: type_caster).alias(table_alias)
69
+ end
70
+ end
71
+
72
+ attr_reader :aliases
73
+
74
+ private
75
+
76
+ def truncate(name)
77
+ name.slice(0, @connection.table_alias_length - 2)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,332 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/wrap"
4
+
5
+ module ActiveRecord
6
+ module Associations
7
+ # = Active Record Associations
8
+ #
9
+ # This is the root class of all associations ('+ Foo' signifies an included module Foo):
10
+ #
11
+ # Association
12
+ # SingularAssociation
13
+ # HasOneAssociation + ForeignAssociation
14
+ # HasOneThroughAssociation + ThroughAssociation
15
+ # BelongsToAssociation
16
+ # BelongsToPolymorphicAssociation
17
+ # CollectionAssociation
18
+ # HasManyAssociation + ForeignAssociation
19
+ # HasManyThroughAssociation + ThroughAssociation
20
+ #
21
+ # Associations in Active Record are middlemen between the object that
22
+ # holds the association, known as the <tt>owner</tt>, and the associated
23
+ # result set, known as the <tt>target</tt>. Association metadata is available in
24
+ # <tt>reflection</tt>, which is an instance of <tt>ActiveRecord::Reflection::AssociationReflection</tt>.
25
+ #
26
+ # For example, given
27
+ #
28
+ # class Blog < ActiveRecord::Base
29
+ # has_many :posts
30
+ # end
31
+ #
32
+ # blog = Blog.first
33
+ #
34
+ # The association of <tt>blog.posts</tt> has the object +blog+ as its
35
+ # <tt>owner</tt>, the collection of its posts as <tt>target</tt>, and
36
+ # the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
37
+ class Association #:nodoc:
38
+ attr_reader :owner, :target, :reflection
39
+
40
+ delegate :options, to: :reflection
41
+
42
+ def initialize(owner, reflection)
43
+ reflection.check_validity!
44
+
45
+ @owner, @reflection = owner, reflection
46
+
47
+ reset
48
+ reset_scope
49
+ end
50
+
51
+ # Resets the \loaded flag to +false+ and sets the \target to +nil+.
52
+ def reset
53
+ @loaded = false
54
+ @target = nil
55
+ @stale_state = nil
56
+ @inversed = false
57
+ end
58
+
59
+ # Reloads the \target and returns +self+ on success.
60
+ # The QueryCache is cleared if +force+ is true.
61
+ def reload(force = false)
62
+ klass.connection.clear_query_cache if force && klass
63
+ reset
64
+ reset_scope
65
+ load_target
66
+ self unless target.nil?
67
+ end
68
+
69
+ # Has the \target been already \loaded?
70
+ def loaded?
71
+ @loaded
72
+ end
73
+
74
+ # Asserts the \target has been loaded setting the \loaded flag to +true+.
75
+ def loaded!
76
+ @loaded = true
77
+ @stale_state = stale_state
78
+ @inversed = false
79
+ end
80
+
81
+ # The target is stale if the target no longer points to the record(s) that the
82
+ # relevant foreign_key(s) refers to. If stale, the association accessor method
83
+ # on the owner will reload the target. It's up to subclasses to implement the
84
+ # stale_state method if relevant.
85
+ #
86
+ # Note that if the target has not been loaded, it is not considered stale.
87
+ def stale_target?
88
+ !@inversed && loaded? && @stale_state != stale_state
89
+ end
90
+
91
+ # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
92
+ def target=(target)
93
+ @target = target
94
+ loaded!
95
+ end
96
+
97
+ def scope
98
+ target_scope.merge!(association_scope)
99
+ end
100
+
101
+ def reset_scope
102
+ @association_scope = nil
103
+ end
104
+
105
+ # Set the inverse association, if possible
106
+ def set_inverse_instance(record)
107
+ if inverse = inverse_association_for(record)
108
+ inverse.inversed_from(owner)
109
+ end
110
+ record
111
+ end
112
+
113
+ def set_inverse_instance_from_queries(record)
114
+ if inverse = inverse_association_for(record)
115
+ inverse.inversed_from_queries(owner)
116
+ end
117
+ record
118
+ end
119
+
120
+ # Remove the inverse association, if possible
121
+ def remove_inverse_instance(record)
122
+ if inverse = inverse_association_for(record)
123
+ inverse.inversed_from(nil)
124
+ end
125
+ end
126
+
127
+ def inversed_from(record)
128
+ self.target = record
129
+ @inversed = !!record
130
+ end
131
+ alias :inversed_from_queries :inversed_from
132
+
133
+ # Returns the class of the target. belongs_to polymorphic overrides this to look at the
134
+ # polymorphic_type field on the owner.
135
+ def klass
136
+ reflection.klass
137
+ end
138
+
139
+ def extensions
140
+ extensions = klass.default_extensions | reflection.extensions
141
+
142
+ if reflection.scope
143
+ extensions |= reflection.scope_for(klass.unscoped, owner).extensions
144
+ end
145
+
146
+ extensions
147
+ end
148
+
149
+ # Loads the \target if needed and returns it.
150
+ #
151
+ # This method is abstract in the sense that it relies on +find_target+,
152
+ # which is expected to be provided by descendants.
153
+ #
154
+ # If the \target is already \loaded it is just returned. Thus, you can call
155
+ # +load_target+ unconditionally to get the \target.
156
+ #
157
+ # ActiveRecord::RecordNotFound is rescued within the method, and it is
158
+ # not reraised. The proxy is \reset and +nil+ is the return value.
159
+ def load_target
160
+ @target = find_target if (@stale_state && stale_target?) || find_target?
161
+
162
+ loaded! unless loaded?
163
+ target
164
+ rescue ActiveRecord::RecordNotFound
165
+ reset
166
+ end
167
+
168
+ # We can't dump @reflection and @through_reflection since it contains the scope proc
169
+ def marshal_dump
170
+ ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
171
+ [@reflection.name, ivars]
172
+ end
173
+
174
+ def marshal_load(data)
175
+ reflection_name, ivars = data
176
+ ivars.each { |name, val| instance_variable_set(name, val) }
177
+ @reflection = @owner.class._reflect_on_association(reflection_name)
178
+ end
179
+
180
+ def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
181
+ except_from_scope_attributes ||= {}
182
+ skip_assign = [reflection.foreign_key, reflection.type].compact
183
+ assigned_keys = record.changed_attribute_names_to_save
184
+ assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
185
+ attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
186
+ record.send(:_assign_attributes, attributes) if attributes.any?
187
+ set_inverse_instance(record)
188
+ end
189
+
190
+ def create(attributes = {}, &block)
191
+ _create_record(attributes, &block)
192
+ end
193
+
194
+ def create!(attributes = {}, &block)
195
+ _create_record(attributes, true, &block)
196
+ end
197
+
198
+ private
199
+ def find_target
200
+ scope = self.scope
201
+ return scope.to_a if skip_statement_cache?(scope)
202
+
203
+ conn = klass.connection
204
+ sc = reflection.association_scope_cache(conn, owner) do |params|
205
+ as = AssociationScope.create { params.bind }
206
+ target_scope.merge!(as.scope(self))
207
+ end
208
+
209
+ binds = AssociationScope.get_bind_values(owner, reflection.chain)
210
+ sc.execute(binds, conn) { |record| set_inverse_instance(record) } || []
211
+ end
212
+
213
+ # The scope for this association.
214
+ #
215
+ # Note that the association_scope is merged into the target_scope only when the
216
+ # scope method is called. This is because at that point the call may be surrounded
217
+ # by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
218
+ # actually gets built.
219
+ def association_scope
220
+ if klass
221
+ @association_scope ||= AssociationScope.scope(self)
222
+ end
223
+ end
224
+
225
+ # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
226
+ # through association's scope)
227
+ def target_scope
228
+ AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
229
+ end
230
+
231
+ def scope_for_create
232
+ scope.scope_for_create
233
+ end
234
+
235
+ def find_target?
236
+ !loaded? && (!owner.new_record? || foreign_key_present?) && klass
237
+ end
238
+
239
+ def creation_attributes
240
+ attributes = {}
241
+
242
+ if (reflection.has_one? || reflection.collection?) && !options[:through]
243
+ attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
244
+
245
+ if reflection.type
246
+ attributes[reflection.type] = owner.class.polymorphic_name
247
+ end
248
+ end
249
+
250
+ attributes
251
+ end
252
+
253
+ # Sets the owner attributes on the given record
254
+ def set_owner_attributes(record)
255
+ creation_attributes.each { |key, value| record[key] = value }
256
+ end
257
+
258
+ # Returns true if there is a foreign key present on the owner which
259
+ # references the target. This is used to determine whether we can load
260
+ # the target if the owner is currently a new record (and therefore
261
+ # without a key). If the owner is a new record then foreign_key must
262
+ # be present in order to load target.
263
+ #
264
+ # Currently implemented by belongs_to (vanilla and polymorphic) and
265
+ # has_one/has_many :through associations which go through a belongs_to.
266
+ def foreign_key_present?
267
+ false
268
+ end
269
+
270
+ # Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
271
+ # the kind of the class of the associated objects. Meant to be used as
272
+ # a sanity check when you are about to assign an associated record.
273
+ def raise_on_type_mismatch!(record)
274
+ unless record.is_a?(reflection.klass)
275
+ fresh_class = reflection.class_name.safe_constantize
276
+ unless fresh_class && record.is_a?(fresh_class)
277
+ message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, "\
278
+ "got #{record.inspect} which is an instance of #{record.class}(##{record.class.object_id})"
279
+ raise ActiveRecord::AssociationTypeMismatch, message
280
+ end
281
+ end
282
+ end
283
+
284
+ def inverse_association_for(record)
285
+ if invertible_for?(record)
286
+ record.association(inverse_reflection_for(record).name)
287
+ end
288
+ end
289
+
290
+ # Can be redefined by subclasses, notably polymorphic belongs_to
291
+ # The record parameter is necessary to support polymorphic inverses as we must check for
292
+ # the association in the specific class of the record.
293
+ def inverse_reflection_for(record)
294
+ reflection.inverse_of
295
+ end
296
+
297
+ # Returns true if inverse association on the given record needs to be set.
298
+ # This method is redefined by subclasses.
299
+ def invertible_for?(record)
300
+ foreign_key_for?(record) && inverse_reflection_for(record)
301
+ end
302
+
303
+ # Returns true if record contains the foreign_key
304
+ def foreign_key_for?(record)
305
+ record.has_attribute?(reflection.foreign_key)
306
+ end
307
+
308
+ # This should be implemented to return the values of the relevant key(s) on the owner,
309
+ # so that when stale_state is different from the value stored on the last find_target,
310
+ # the target is stale.
311
+ #
312
+ # This is only relevant to certain associations, which is why it returns +nil+ by default.
313
+ def stale_state
314
+ end
315
+
316
+ def build_record(attributes)
317
+ reflection.build_association(attributes) do |record|
318
+ initialize_attributes(record, attributes)
319
+ yield(record) if block_given?
320
+ end
321
+ end
322
+
323
+ # Returns true if statement cache should be skipped on the association reader.
324
+ def skip_statement_cache?(scope)
325
+ reflection.has_scope? ||
326
+ scope.eager_loading? ||
327
+ klass.scope_attributes? ||
328
+ reflection.source_reflection.active_record.default_scopes.any?
329
+ end
330
+ end
331
+ end
332
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Associations
5
+ class AssociationScope #:nodoc:
6
+ def self.scope(association)
7
+ INSTANCE.scope(association)
8
+ end
9
+
10
+ def self.create(&block)
11
+ block ||= lambda { |val| val }
12
+ new(block)
13
+ end
14
+
15
+ def initialize(value_transformation)
16
+ @value_transformation = value_transformation
17
+ end
18
+
19
+ INSTANCE = create
20
+
21
+ def scope(association)
22
+ klass = association.klass
23
+ reflection = association.reflection
24
+ scope = klass.unscoped
25
+ owner = association.owner
26
+ chain = get_chain(reflection, association, scope.alias_tracker)
27
+
28
+ scope.extending! reflection.extensions
29
+ scope = add_constraints(scope, owner, chain)
30
+ scope.limit!(1) unless reflection.collection?
31
+ scope
32
+ end
33
+
34
+ def self.get_bind_values(owner, chain)
35
+ binds = []
36
+ last_reflection = chain.last
37
+
38
+ binds << last_reflection.join_id_for(owner)
39
+ if last_reflection.type
40
+ binds << owner.class.polymorphic_name
41
+ end
42
+
43
+ chain.each_cons(2).each do |reflection, next_reflection|
44
+ if reflection.type
45
+ binds << next_reflection.klass.polymorphic_name
46
+ end
47
+ end
48
+ binds
49
+ end
50
+
51
+ private
52
+ attr_reader :value_transformation
53
+
54
+ def join(table, constraint)
55
+ table.create_join(table, table.create_on(constraint))
56
+ end
57
+
58
+ def last_chain_scope(scope, reflection, owner)
59
+ join_keys = reflection.join_keys
60
+ key = join_keys.key
61
+ foreign_key = join_keys.foreign_key
62
+
63
+ table = reflection.aliased_table
64
+ value = transform_value(owner[foreign_key])
65
+ scope = apply_scope(scope, table, key, value)
66
+
67
+ if reflection.type
68
+ polymorphic_type = transform_value(owner.class.polymorphic_name)
69
+ scope = apply_scope(scope, table, reflection.type, polymorphic_type)
70
+ end
71
+
72
+ scope
73
+ end
74
+
75
+ def transform_value(value)
76
+ value_transformation.call(value)
77
+ end
78
+
79
+ def next_chain_scope(scope, reflection, next_reflection)
80
+ join_keys = reflection.join_keys
81
+ key = join_keys.key
82
+ foreign_key = join_keys.foreign_key
83
+
84
+ table = reflection.aliased_table
85
+ foreign_table = next_reflection.aliased_table
86
+ constraint = table[key].eq(foreign_table[foreign_key])
87
+
88
+ if reflection.type
89
+ value = transform_value(next_reflection.klass.polymorphic_name)
90
+ scope = apply_scope(scope, table, reflection.type, value)
91
+ end
92
+
93
+ scope.joins!(join(foreign_table, constraint))
94
+ end
95
+
96
+ class ReflectionProxy < SimpleDelegator # :nodoc:
97
+ attr_reader :aliased_table
98
+
99
+ def initialize(reflection, aliased_table)
100
+ super(reflection)
101
+ @aliased_table = aliased_table
102
+ end
103
+
104
+ def all_includes; nil; end
105
+ end
106
+
107
+ def get_chain(reflection, association, tracker)
108
+ name = reflection.name
109
+ chain = [Reflection::RuntimeReflection.new(reflection, association)]
110
+ reflection.chain.drop(1).each do |refl|
111
+ aliased_table = tracker.aliased_table_for(
112
+ refl.table_name,
113
+ refl.alias_candidate(name),
114
+ refl.klass.type_caster
115
+ )
116
+ chain << ReflectionProxy.new(refl, aliased_table)
117
+ end
118
+ chain
119
+ end
120
+
121
+ def add_constraints(scope, owner, chain)
122
+ scope = last_chain_scope(scope, chain.last, owner)
123
+
124
+ chain.each_cons(2) do |reflection, next_reflection|
125
+ scope = next_chain_scope(scope, reflection, next_reflection)
126
+ end
127
+
128
+ chain_head = chain.first
129
+ chain.reverse_each do |reflection|
130
+ # Exclude the scope of the association itself, because that
131
+ # was already merged in the #scope method.
132
+ reflection.constraints.each do |scope_chain_item|
133
+ item = eval_scope(reflection, scope_chain_item, owner)
134
+
135
+ if scope_chain_item == chain_head.scope
136
+ scope.merge! item.except(:where, :includes, :unscope, :order)
137
+ end
138
+
139
+ reflection.all_includes do
140
+ scope.includes! item.includes_values
141
+ end
142
+
143
+ scope.unscope!(*item.unscope_values)
144
+ scope.where_clause += item.where_clause
145
+ scope.order_values = item.order_values | scope.order_values
146
+ end
147
+ end
148
+
149
+ scope
150
+ end
151
+
152
+ def apply_scope(scope, table, key, value)
153
+ if scope.table == table
154
+ scope.where!(key => value)
155
+ else
156
+ scope.where!(table.name => { key => value })
157
+ end
158
+ end
159
+
160
+ def eval_scope(reflection, scope, owner)
161
+ relation = reflection.build_scope(reflection.aliased_table)
162
+ relation.instance_exec(owner, &scope) || relation
163
+ end
164
+ end
165
+ end
166
+ end