activerecord 6.0.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 (340) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1086 -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 +49 -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 +340 -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 +262 -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 +512 -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 +1175 -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 +516 -0
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +155 -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 +772 -0
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +830 -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 +202 -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 +184 -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 +953 -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 +120 -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 +561 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +274 -0
  129. data/lib/active_record/core.rb +603 -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 +88 -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 +545 -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 +860 -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 +561 -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 +1371 -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 +58 -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 +418 -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,340 @@
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
+ @_scope = nil
47
+
48
+ reset
49
+ reset_scope
50
+ end
51
+
52
+ # Resets the \loaded flag to +false+ and sets the \target to +nil+.
53
+ def reset
54
+ @loaded = false
55
+ @target = nil
56
+ @stale_state = nil
57
+ @inversed = false
58
+ end
59
+
60
+ # Reloads the \target and returns +self+ on success.
61
+ # The QueryCache is cleared if +force+ is true.
62
+ def reload(force = false)
63
+ klass.connection.clear_query_cache if force && klass
64
+ reset
65
+ reset_scope
66
+ load_target
67
+ self unless target.nil?
68
+ end
69
+
70
+ # Has the \target been already \loaded?
71
+ def loaded?
72
+ @loaded
73
+ end
74
+
75
+ # Asserts the \target has been loaded setting the \loaded flag to +true+.
76
+ def loaded!
77
+ @loaded = true
78
+ @stale_state = stale_state
79
+ @inversed = false
80
+ end
81
+
82
+ # The target is stale if the target no longer points to the record(s) that the
83
+ # relevant foreign_key(s) refers to. If stale, the association accessor method
84
+ # on the owner will reload the target. It's up to subclasses to implement the
85
+ # stale_state method if relevant.
86
+ #
87
+ # Note that if the target has not been loaded, it is not considered stale.
88
+ def stale_target?
89
+ !@inversed && loaded? && @stale_state != stale_state
90
+ end
91
+
92
+ # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
93
+ def target=(target)
94
+ @target = target
95
+ loaded!
96
+ end
97
+
98
+ def scope
99
+ @_scope&.spawn || target_scope.merge!(association_scope)
100
+ end
101
+
102
+ def reset_scope
103
+ @association_scope = nil
104
+ end
105
+
106
+ # Set the inverse association, if possible
107
+ def set_inverse_instance(record)
108
+ if inverse = inverse_association_for(record)
109
+ inverse.inversed_from(owner)
110
+ end
111
+ record
112
+ end
113
+
114
+ def set_inverse_instance_from_queries(record)
115
+ if inverse = inverse_association_for(record)
116
+ inverse.inversed_from_queries(owner)
117
+ end
118
+ record
119
+ end
120
+
121
+ # Remove the inverse association, if possible
122
+ def remove_inverse_instance(record)
123
+ if inverse = inverse_association_for(record)
124
+ inverse.inversed_from(nil)
125
+ end
126
+ end
127
+
128
+ def inversed_from(record)
129
+ self.target = record
130
+ @inversed = !!record
131
+ end
132
+ alias :inversed_from_queries :inversed_from
133
+
134
+ # Returns the class of the target. belongs_to polymorphic overrides this to look at the
135
+ # polymorphic_type field on the owner.
136
+ def klass
137
+ reflection.klass
138
+ end
139
+
140
+ def extensions
141
+ extensions = klass.default_extensions | reflection.extensions
142
+
143
+ if reflection.scope
144
+ extensions |= reflection.scope_for(klass.unscoped, owner).extensions
145
+ end
146
+
147
+ extensions
148
+ end
149
+
150
+ # Loads the \target if needed and returns it.
151
+ #
152
+ # This method is abstract in the sense that it relies on +find_target+,
153
+ # which is expected to be provided by descendants.
154
+ #
155
+ # If the \target is already \loaded it is just returned. Thus, you can call
156
+ # +load_target+ unconditionally to get the \target.
157
+ #
158
+ # ActiveRecord::RecordNotFound is rescued within the method, and it is
159
+ # not reraised. The proxy is \reset and +nil+ is the return value.
160
+ def load_target
161
+ @target = find_target if (@stale_state && stale_target?) || find_target?
162
+
163
+ loaded! unless loaded?
164
+ target
165
+ rescue ActiveRecord::RecordNotFound
166
+ reset
167
+ end
168
+
169
+ # We can't dump @reflection and @through_reflection since it contains the scope proc
170
+ def marshal_dump
171
+ ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
172
+ [@reflection.name, ivars]
173
+ end
174
+
175
+ def marshal_load(data)
176
+ reflection_name, ivars = data
177
+ ivars.each { |name, val| instance_variable_set(name, val) }
178
+ @reflection = @owner.class._reflect_on_association(reflection_name)
179
+ end
180
+
181
+ def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
182
+ except_from_scope_attributes ||= {}
183
+ skip_assign = [reflection.foreign_key, reflection.type].compact
184
+ assigned_keys = record.changed_attribute_names_to_save
185
+ assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
186
+ attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
187
+ record.send(:_assign_attributes, attributes) if attributes.any?
188
+ set_inverse_instance(record)
189
+ end
190
+
191
+ def create(attributes = {}, &block)
192
+ _create_record(attributes, &block)
193
+ end
194
+
195
+ def create!(attributes = {}, &block)
196
+ _create_record(attributes, true, &block)
197
+ end
198
+
199
+ def scoping(relation, &block)
200
+ @_scope = relation
201
+ relation.scoping(&block)
202
+ ensure
203
+ @_scope = nil
204
+ end
205
+
206
+ private
207
+ def find_target
208
+ scope = self.scope
209
+ return scope.to_a if skip_statement_cache?(scope)
210
+
211
+ conn = klass.connection
212
+ sc = reflection.association_scope_cache(conn, owner) do |params|
213
+ as = AssociationScope.create { params.bind }
214
+ target_scope.merge!(as.scope(self))
215
+ end
216
+
217
+ binds = AssociationScope.get_bind_values(owner, reflection.chain)
218
+ sc.execute(binds, conn) { |record| set_inverse_instance(record) } || []
219
+ end
220
+
221
+ # The scope for this association.
222
+ #
223
+ # Note that the association_scope is merged into the target_scope only when the
224
+ # scope method is called. This is because at that point the call may be surrounded
225
+ # by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
226
+ # actually gets built.
227
+ def association_scope
228
+ if klass
229
+ @association_scope ||= AssociationScope.scope(self)
230
+ end
231
+ end
232
+
233
+ # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
234
+ # through association's scope)
235
+ def target_scope
236
+ AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
237
+ end
238
+
239
+ def scope_for_create
240
+ scope.scope_for_create
241
+ end
242
+
243
+ def find_target?
244
+ !loaded? && (!owner.new_record? || foreign_key_present?) && klass
245
+ end
246
+
247
+ def creation_attributes
248
+ attributes = {}
249
+
250
+ if (reflection.has_one? || reflection.collection?) && !options[:through]
251
+ attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
252
+
253
+ if reflection.type
254
+ attributes[reflection.type] = owner.class.polymorphic_name
255
+ end
256
+ end
257
+
258
+ attributes
259
+ end
260
+
261
+ # Sets the owner attributes on the given record
262
+ def set_owner_attributes(record)
263
+ creation_attributes.each { |key, value| record[key] = value }
264
+ end
265
+
266
+ # Returns true if there is a foreign key present on the owner which
267
+ # references the target. This is used to determine whether we can load
268
+ # the target if the owner is currently a new record (and therefore
269
+ # without a key). If the owner is a new record then foreign_key must
270
+ # be present in order to load target.
271
+ #
272
+ # Currently implemented by belongs_to (vanilla and polymorphic) and
273
+ # has_one/has_many :through associations which go through a belongs_to.
274
+ def foreign_key_present?
275
+ false
276
+ end
277
+
278
+ # Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
279
+ # the kind of the class of the associated objects. Meant to be used as
280
+ # a sanity check when you are about to assign an associated record.
281
+ def raise_on_type_mismatch!(record)
282
+ unless record.is_a?(reflection.klass)
283
+ fresh_class = reflection.class_name.safe_constantize
284
+ unless fresh_class && record.is_a?(fresh_class)
285
+ message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, "\
286
+ "got #{record.inspect} which is an instance of #{record.class}(##{record.class.object_id})"
287
+ raise ActiveRecord::AssociationTypeMismatch, message
288
+ end
289
+ end
290
+ end
291
+
292
+ def inverse_association_for(record)
293
+ if invertible_for?(record)
294
+ record.association(inverse_reflection_for(record).name)
295
+ end
296
+ end
297
+
298
+ # Can be redefined by subclasses, notably polymorphic belongs_to
299
+ # The record parameter is necessary to support polymorphic inverses as we must check for
300
+ # the association in the specific class of the record.
301
+ def inverse_reflection_for(record)
302
+ reflection.inverse_of
303
+ end
304
+
305
+ # Returns true if inverse association on the given record needs to be set.
306
+ # This method is redefined by subclasses.
307
+ def invertible_for?(record)
308
+ foreign_key_for?(record) && inverse_reflection_for(record)
309
+ end
310
+
311
+ # Returns true if record contains the foreign_key
312
+ def foreign_key_for?(record)
313
+ record.has_attribute?(reflection.foreign_key)
314
+ end
315
+
316
+ # This should be implemented to return the values of the relevant key(s) on the owner,
317
+ # so that when stale_state is different from the value stored on the last find_target,
318
+ # the target is stale.
319
+ #
320
+ # This is only relevant to certain associations, which is why it returns +nil+ by default.
321
+ def stale_state
322
+ end
323
+
324
+ def build_record(attributes)
325
+ reflection.build_association(attributes) do |record|
326
+ initialize_attributes(record, attributes)
327
+ yield(record) if block_given?
328
+ end
329
+ end
330
+
331
+ # Returns true if statement cache should be skipped on the association reader.
332
+ def skip_statement_cache?(scope)
333
+ reflection.has_scope? ||
334
+ scope.eager_loading? ||
335
+ klass.scope_attributes? ||
336
+ reflection.source_reflection.active_record.default_scopes.any?
337
+ end
338
+ end
339
+ end
340
+ 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