omg-activerecord 8.0.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +355 -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/aggregations.rb +287 -0
  8. data/lib/active_record/association_relation.rb +50 -0
  9. data/lib/active_record/associations/alias_tracker.rb +90 -0
  10. data/lib/active_record/associations/association.rb +417 -0
  11. data/lib/active_record/associations/association_scope.rb +175 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +163 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  14. data/lib/active_record/associations/builder/association.rb +170 -0
  15. data/lib/active_record/associations/builder/belongs_to.rb +160 -0
  16. data/lib/active_record/associations/builder/collection_association.rb +80 -0
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -0
  18. data/lib/active_record/associations/builder/has_many.rb +23 -0
  19. data/lib/active_record/associations/builder/has_one.rb +61 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +48 -0
  21. data/lib/active_record/associations/collection_association.rb +535 -0
  22. data/lib/active_record/associations/collection_proxy.rb +1163 -0
  23. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  24. data/lib/active_record/associations/errors.rb +265 -0
  25. data/lib/active_record/associations/foreign_association.rb +40 -0
  26. data/lib/active_record/associations/has_many_association.rb +167 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +232 -0
  28. data/lib/active_record/associations/has_one_association.rb +142 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +106 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  33. data/lib/active_record/associations/join_dependency.rb +301 -0
  34. data/lib/active_record/associations/nested_error.rb +47 -0
  35. data/lib/active_record/associations/preloader/association.rb +316 -0
  36. data/lib/active_record/associations/preloader/batch.rb +48 -0
  37. data/lib/active_record/associations/preloader/branch.rb +153 -0
  38. data/lib/active_record/associations/preloader/through_association.rb +150 -0
  39. data/lib/active_record/associations/preloader.rb +135 -0
  40. data/lib/active_record/associations/singular_association.rb +76 -0
  41. data/lib/active_record/associations/through_association.rb +132 -0
  42. data/lib/active_record/associations.rb +1897 -0
  43. data/lib/active_record/asynchronous_queries_tracker.rb +64 -0
  44. data/lib/active_record/attribute_assignment.rb +82 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +106 -0
  46. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  47. data/lib/active_record/attribute_methods/dirty.rb +262 -0
  48. data/lib/active_record/attribute_methods/primary_key.rb +158 -0
  49. data/lib/active_record/attribute_methods/query.rb +50 -0
  50. data/lib/active_record/attribute_methods/read.rb +46 -0
  51. data/lib/active_record/attribute_methods/serialization.rb +232 -0
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +94 -0
  53. data/lib/active_record/attribute_methods/write.rb +49 -0
  54. data/lib/active_record/attribute_methods.rb +542 -0
  55. data/lib/active_record/attributes.rb +307 -0
  56. data/lib/active_record/autosave_association.rb +586 -0
  57. data/lib/active_record/base.rb +338 -0
  58. data/lib/active_record/callbacks.rb +452 -0
  59. data/lib/active_record/coders/column_serializer.rb +61 -0
  60. data/lib/active_record/coders/json.rb +15 -0
  61. data/lib/active_record/coders/yaml_column.rb +95 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +290 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +210 -0
  64. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +923 -0
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +31 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +747 -0
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +319 -0
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +239 -0
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +24 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +190 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +961 -0
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +106 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1883 -0
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +676 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +1218 -0
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1016 -0
  78. data/lib/active_record/connection_adapters/column.rb +122 -0
  79. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  80. data/lib/active_record/connection_adapters/mysql/column.rb +28 -0
  81. data/lib/active_record/connection_adapters/mysql/database_statements.rb +95 -0
  82. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  83. data/lib/active_record/connection_adapters/mysql/quoting.rb +114 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +106 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +106 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +97 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +300 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  89. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +96 -0
  90. data/lib/active_record/connection_adapters/mysql2_adapter.rb +196 -0
  91. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  92. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  93. data/lib/active_record/connection_adapters/postgresql/column.rb +82 -0
  94. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +231 -0
  95. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +91 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +54 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +31 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +20 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +109 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +42 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +74 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +124 -0
  115. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  116. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  117. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  118. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +125 -0
  119. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +45 -0
  120. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  121. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  122. data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -0
  123. data/lib/active_record/connection_adapters/postgresql/quoting.rb +238 -0
  124. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +71 -0
  125. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +169 -0
  126. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +392 -0
  127. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +127 -0
  128. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1162 -0
  129. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  130. data/lib/active_record/connection_adapters/postgresql/utils.rb +79 -0
  131. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1182 -0
  132. data/lib/active_record/connection_adapters/schema_cache.rb +478 -0
  133. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  134. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  135. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +145 -0
  136. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  137. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +116 -0
  138. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +37 -0
  139. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +39 -0
  140. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +47 -0
  141. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +221 -0
  142. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +843 -0
  143. data/lib/active_record/connection_adapters/statement_pool.rb +67 -0
  144. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +69 -0
  145. data/lib/active_record/connection_adapters/trilogy_adapter.rb +212 -0
  146. data/lib/active_record/connection_adapters.rb +176 -0
  147. data/lib/active_record/connection_handling.rb +413 -0
  148. data/lib/active_record/core.rb +836 -0
  149. data/lib/active_record/counter_cache.rb +230 -0
  150. data/lib/active_record/database_configurations/connection_url_resolver.rb +105 -0
  151. data/lib/active_record/database_configurations/database_config.rb +104 -0
  152. data/lib/active_record/database_configurations/hash_config.rb +172 -0
  153. data/lib/active_record/database_configurations/url_config.rb +78 -0
  154. data/lib/active_record/database_configurations.rb +309 -0
  155. data/lib/active_record/delegated_type.rb +289 -0
  156. data/lib/active_record/deprecator.rb +7 -0
  157. data/lib/active_record/destroy_association_async_job.rb +38 -0
  158. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  159. data/lib/active_record/dynamic_matchers.rb +121 -0
  160. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  161. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  162. data/lib/active_record/encryption/cipher.rb +53 -0
  163. data/lib/active_record/encryption/config.rb +70 -0
  164. data/lib/active_record/encryption/configurable.rb +60 -0
  165. data/lib/active_record/encryption/context.rb +42 -0
  166. data/lib/active_record/encryption/contexts.rb +76 -0
  167. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  168. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  169. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  170. data/lib/active_record/encryption/encrypted_attribute_type.rb +184 -0
  171. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  172. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  173. data/lib/active_record/encryption/encryptor.rb +177 -0
  174. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  175. data/lib/active_record/encryption/errors.rb +15 -0
  176. data/lib/active_record/encryption/extended_deterministic_queries.rb +159 -0
  177. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  178. data/lib/active_record/encryption/key.rb +28 -0
  179. data/lib/active_record/encryption/key_generator.rb +53 -0
  180. data/lib/active_record/encryption/key_provider.rb +46 -0
  181. data/lib/active_record/encryption/message.rb +33 -0
  182. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  183. data/lib/active_record/encryption/message_serializer.rb +96 -0
  184. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  185. data/lib/active_record/encryption/properties.rb +76 -0
  186. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  187. data/lib/active_record/encryption/scheme.rb +107 -0
  188. data/lib/active_record/encryption.rb +58 -0
  189. data/lib/active_record/enum.rb +424 -0
  190. data/lib/active_record/errors.rb +614 -0
  191. data/lib/active_record/explain.rb +63 -0
  192. data/lib/active_record/explain_registry.rb +37 -0
  193. data/lib/active_record/explain_subscriber.rb +34 -0
  194. data/lib/active_record/fixture_set/file.rb +89 -0
  195. data/lib/active_record/fixture_set/model_metadata.rb +42 -0
  196. data/lib/active_record/fixture_set/render_context.rb +19 -0
  197. data/lib/active_record/fixture_set/table_row.rb +208 -0
  198. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  199. data/lib/active_record/fixtures.rb +850 -0
  200. data/lib/active_record/future_result.rb +182 -0
  201. data/lib/active_record/gem_version.rb +17 -0
  202. data/lib/active_record/inheritance.rb +366 -0
  203. data/lib/active_record/insert_all.rb +328 -0
  204. data/lib/active_record/integration.rb +209 -0
  205. data/lib/active_record/internal_metadata.rb +164 -0
  206. data/lib/active_record/legacy_yaml_adapter.rb +15 -0
  207. data/lib/active_record/locale/en.yml +48 -0
  208. data/lib/active_record/locking/optimistic.rb +228 -0
  209. data/lib/active_record/locking/pessimistic.rb +102 -0
  210. data/lib/active_record/log_subscriber.rb +149 -0
  211. data/lib/active_record/marshalling.rb +56 -0
  212. data/lib/active_record/message_pack.rb +124 -0
  213. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  214. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  215. data/lib/active_record/middleware/database_selector.rb +87 -0
  216. data/lib/active_record/middleware/shard_selector.rb +62 -0
  217. data/lib/active_record/migration/command_recorder.rb +406 -0
  218. data/lib/active_record/migration/compatibility.rb +490 -0
  219. data/lib/active_record/migration/default_strategy.rb +22 -0
  220. data/lib/active_record/migration/execution_strategy.rb +19 -0
  221. data/lib/active_record/migration/join_table.rb +16 -0
  222. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  223. data/lib/active_record/migration.rb +1626 -0
  224. data/lib/active_record/model_schema.rb +635 -0
  225. data/lib/active_record/nested_attributes.rb +633 -0
  226. data/lib/active_record/no_touching.rb +65 -0
  227. data/lib/active_record/normalization.rb +163 -0
  228. data/lib/active_record/persistence.rb +968 -0
  229. data/lib/active_record/promise.rb +84 -0
  230. data/lib/active_record/query_cache.rb +56 -0
  231. data/lib/active_record/query_logs.rb +247 -0
  232. data/lib/active_record/query_logs_formatter.rb +30 -0
  233. data/lib/active_record/querying.rb +122 -0
  234. data/lib/active_record/railtie.rb +440 -0
  235. data/lib/active_record/railties/console_sandbox.rb +5 -0
  236. data/lib/active_record/railties/controller_runtime.rb +65 -0
  237. data/lib/active_record/railties/databases.rake +641 -0
  238. data/lib/active_record/railties/job_runtime.rb +23 -0
  239. data/lib/active_record/readonly_attributes.rb +66 -0
  240. data/lib/active_record/reflection.rb +1287 -0
  241. data/lib/active_record/relation/batches/batch_enumerator.rb +115 -0
  242. data/lib/active_record/relation/batches.rb +491 -0
  243. data/lib/active_record/relation/calculations.rb +679 -0
  244. data/lib/active_record/relation/delegation.rb +154 -0
  245. data/lib/active_record/relation/finder_methods.rb +661 -0
  246. data/lib/active_record/relation/from_clause.rb +30 -0
  247. data/lib/active_record/relation/merger.rb +192 -0
  248. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  249. data/lib/active_record/relation/predicate_builder/association_query_value.rb +76 -0
  250. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  251. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +60 -0
  252. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  253. data/lib/active_record/relation/predicate_builder/relation_handler.rb +24 -0
  254. data/lib/active_record/relation/predicate_builder.rb +181 -0
  255. data/lib/active_record/relation/query_attribute.rb +68 -0
  256. data/lib/active_record/relation/query_methods.rb +2235 -0
  257. data/lib/active_record/relation/record_fetch_warning.rb +52 -0
  258. data/lib/active_record/relation/spawn_methods.rb +78 -0
  259. data/lib/active_record/relation/where_clause.rb +218 -0
  260. data/lib/active_record/relation.rb +1495 -0
  261. data/lib/active_record/result.rb +249 -0
  262. data/lib/active_record/runtime_registry.rb +82 -0
  263. data/lib/active_record/sanitization.rb +254 -0
  264. data/lib/active_record/schema.rb +77 -0
  265. data/lib/active_record/schema_dumper.rb +364 -0
  266. data/lib/active_record/schema_migration.rb +106 -0
  267. data/lib/active_record/scoping/default.rb +205 -0
  268. data/lib/active_record/scoping/named.rb +202 -0
  269. data/lib/active_record/scoping.rb +136 -0
  270. data/lib/active_record/secure_password.rb +60 -0
  271. data/lib/active_record/secure_token.rb +66 -0
  272. data/lib/active_record/serialization.rb +29 -0
  273. data/lib/active_record/signed_id.rb +137 -0
  274. data/lib/active_record/statement_cache.rb +164 -0
  275. data/lib/active_record/store.rb +299 -0
  276. data/lib/active_record/suppressor.rb +59 -0
  277. data/lib/active_record/table_metadata.rb +85 -0
  278. data/lib/active_record/tasks/database_tasks.rb +681 -0
  279. data/lib/active_record/tasks/mysql_database_tasks.rb +120 -0
  280. data/lib/active_record/tasks/postgresql_database_tasks.rb +147 -0
  281. data/lib/active_record/tasks/sqlite_database_tasks.rb +89 -0
  282. data/lib/active_record/test_databases.rb +24 -0
  283. data/lib/active_record/test_fixtures.rb +321 -0
  284. data/lib/active_record/testing/query_assertions.rb +121 -0
  285. data/lib/active_record/timestamp.rb +177 -0
  286. data/lib/active_record/token_for.rb +123 -0
  287. data/lib/active_record/touch_later.rb +70 -0
  288. data/lib/active_record/transaction.rb +132 -0
  289. data/lib/active_record/transactions.rb +523 -0
  290. data/lib/active_record/translation.rb +22 -0
  291. data/lib/active_record/type/adapter_specific_registry.rb +144 -0
  292. data/lib/active_record/type/date.rb +9 -0
  293. data/lib/active_record/type/date_time.rb +9 -0
  294. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  295. data/lib/active_record/type/hash_lookup_type_map.rb +57 -0
  296. data/lib/active_record/type/internal/timezone.rb +22 -0
  297. data/lib/active_record/type/json.rb +30 -0
  298. data/lib/active_record/type/serialized.rb +76 -0
  299. data/lib/active_record/type/text.rb +11 -0
  300. data/lib/active_record/type/time.rb +35 -0
  301. data/lib/active_record/type/type_map.rb +58 -0
  302. data/lib/active_record/type/unsigned_integer.rb +16 -0
  303. data/lib/active_record/type.rb +83 -0
  304. data/lib/active_record/type_caster/connection.rb +33 -0
  305. data/lib/active_record/type_caster/map.rb +23 -0
  306. data/lib/active_record/type_caster.rb +9 -0
  307. data/lib/active_record/validations/absence.rb +25 -0
  308. data/lib/active_record/validations/associated.rb +65 -0
  309. data/lib/active_record/validations/length.rb +26 -0
  310. data/lib/active_record/validations/numericality.rb +36 -0
  311. data/lib/active_record/validations/presence.rb +45 -0
  312. data/lib/active_record/validations/uniqueness.rb +295 -0
  313. data/lib/active_record/validations.rb +101 -0
  314. data/lib/active_record/version.rb +10 -0
  315. data/lib/active_record.rb +616 -0
  316. data/lib/arel/alias_predication.rb +9 -0
  317. data/lib/arel/attributes/attribute.rb +33 -0
  318. data/lib/arel/collectors/bind.rb +31 -0
  319. data/lib/arel/collectors/composite.rb +46 -0
  320. data/lib/arel/collectors/plain_string.rb +20 -0
  321. data/lib/arel/collectors/sql_string.rb +27 -0
  322. data/lib/arel/collectors/substitute_binds.rb +35 -0
  323. data/lib/arel/crud.rb +48 -0
  324. data/lib/arel/delete_manager.rb +32 -0
  325. data/lib/arel/errors.rb +19 -0
  326. data/lib/arel/expressions.rb +29 -0
  327. data/lib/arel/factory_methods.rb +53 -0
  328. data/lib/arel/filter_predications.rb +9 -0
  329. data/lib/arel/insert_manager.rb +48 -0
  330. data/lib/arel/math.rb +45 -0
  331. data/lib/arel/nodes/ascending.rb +23 -0
  332. data/lib/arel/nodes/binary.rb +125 -0
  333. data/lib/arel/nodes/bind_param.rb +44 -0
  334. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  335. data/lib/arel/nodes/case.rb +55 -0
  336. data/lib/arel/nodes/casted.rb +62 -0
  337. data/lib/arel/nodes/comment.rb +29 -0
  338. data/lib/arel/nodes/count.rb +12 -0
  339. data/lib/arel/nodes/cte.rb +36 -0
  340. data/lib/arel/nodes/delete_statement.rb +44 -0
  341. data/lib/arel/nodes/descending.rb +23 -0
  342. data/lib/arel/nodes/equality.rb +15 -0
  343. data/lib/arel/nodes/extract.rb +24 -0
  344. data/lib/arel/nodes/false.rb +16 -0
  345. data/lib/arel/nodes/filter.rb +10 -0
  346. data/lib/arel/nodes/fragments.rb +35 -0
  347. data/lib/arel/nodes/full_outer_join.rb +8 -0
  348. data/lib/arel/nodes/function.rb +45 -0
  349. data/lib/arel/nodes/grouping.rb +11 -0
  350. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  351. data/lib/arel/nodes/in.rb +15 -0
  352. data/lib/arel/nodes/infix_operation.rb +92 -0
  353. data/lib/arel/nodes/inner_join.rb +8 -0
  354. data/lib/arel/nodes/insert_statement.rb +37 -0
  355. data/lib/arel/nodes/join_source.rb +20 -0
  356. data/lib/arel/nodes/leading_join.rb +8 -0
  357. data/lib/arel/nodes/matches.rb +18 -0
  358. data/lib/arel/nodes/named_function.rb +23 -0
  359. data/lib/arel/nodes/nary.rb +39 -0
  360. data/lib/arel/nodes/node.rb +161 -0
  361. data/lib/arel/nodes/node_expression.rb +13 -0
  362. data/lib/arel/nodes/ordering.rb +27 -0
  363. data/lib/arel/nodes/outer_join.rb +8 -0
  364. data/lib/arel/nodes/over.rb +15 -0
  365. data/lib/arel/nodes/regexp.rb +16 -0
  366. data/lib/arel/nodes/right_outer_join.rb +8 -0
  367. data/lib/arel/nodes/select_core.rb +67 -0
  368. data/lib/arel/nodes/select_statement.rb +41 -0
  369. data/lib/arel/nodes/sql_literal.rb +32 -0
  370. data/lib/arel/nodes/string_join.rb +11 -0
  371. data/lib/arel/nodes/table_alias.rb +35 -0
  372. data/lib/arel/nodes/terminal.rb +16 -0
  373. data/lib/arel/nodes/true.rb +16 -0
  374. data/lib/arel/nodes/unary.rb +44 -0
  375. data/lib/arel/nodes/unary_operation.rb +20 -0
  376. data/lib/arel/nodes/unqualified_column.rb +22 -0
  377. data/lib/arel/nodes/update_statement.rb +46 -0
  378. data/lib/arel/nodes/values_list.rb +9 -0
  379. data/lib/arel/nodes/window.rb +126 -0
  380. data/lib/arel/nodes/with.rb +11 -0
  381. data/lib/arel/nodes.rb +75 -0
  382. data/lib/arel/order_predications.rb +13 -0
  383. data/lib/arel/predications.rb +260 -0
  384. data/lib/arel/select_manager.rb +276 -0
  385. data/lib/arel/table.rb +121 -0
  386. data/lib/arel/tree_manager.rb +65 -0
  387. data/lib/arel/update_manager.rb +49 -0
  388. data/lib/arel/visitors/dot.rb +299 -0
  389. data/lib/arel/visitors/mysql.rb +111 -0
  390. data/lib/arel/visitors/postgresql.rb +99 -0
  391. data/lib/arel/visitors/sqlite.rb +38 -0
  392. data/lib/arel/visitors/to_sql.rb +1033 -0
  393. data/lib/arel/visitors/visitor.rb +45 -0
  394. data/lib/arel/visitors.rb +13 -0
  395. data/lib/arel/window_predications.rb +9 -0
  396. data/lib/arel.rb +73 -0
  397. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  398. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  399. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  400. data/lib/rails/generators/active_record/migration/migration_generator.rb +76 -0
  401. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +29 -0
  402. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  403. data/lib/rails/generators/active_record/migration.rb +54 -0
  404. data/lib/rails/generators/active_record/model/USAGE +113 -0
  405. data/lib/rails/generators/active_record/model/model_generator.rb +94 -0
  406. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  407. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  408. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  409. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  410. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  411. data/lib/rails/generators/active_record.rb +19 -0
  412. metadata +505 -0
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Associations
5
+ # = Active Record Belongs To Association
6
+ class BelongsToAssociation < SingularAssociation # :nodoc:
7
+ def handle_dependency
8
+ return unless load_target
9
+
10
+ case options[:dependent]
11
+ when :destroy
12
+ raise ActiveRecord::Rollback unless target.destroy
13
+ when :destroy_async
14
+ if reflection.foreign_key.is_a?(Array)
15
+ primary_key_column = reflection.active_record_primary_key
16
+ id = reflection.foreign_key.map { |col| owner.public_send(col) }
17
+ else
18
+ primary_key_column = reflection.active_record_primary_key
19
+ id = owner.public_send(reflection.foreign_key)
20
+ end
21
+
22
+ enqueue_destroy_association(
23
+ owner_model_name: owner.class.to_s,
24
+ owner_id: owner.id,
25
+ association_class: reflection.klass.to_s,
26
+ association_ids: [id],
27
+ association_primary_key_column: primary_key_column,
28
+ ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
29
+ )
30
+ else
31
+ target.public_send(options[:dependent])
32
+ end
33
+ end
34
+
35
+ def inversed_from(record)
36
+ replace_keys(record)
37
+ super
38
+ end
39
+
40
+ def default(&block)
41
+ writer(owner.instance_exec(&block)) if reader.nil?
42
+ end
43
+
44
+ def reset
45
+ super
46
+ @updated = false
47
+ end
48
+
49
+ def updated?
50
+ @updated
51
+ end
52
+
53
+ def decrement_counters
54
+ update_counters(-1)
55
+ end
56
+
57
+ def increment_counters
58
+ update_counters(1)
59
+ end
60
+
61
+ def decrement_counters_before_last_save
62
+ if reflection.polymorphic?
63
+ model_type_was = owner.attribute_before_last_save(reflection.foreign_type)
64
+ model_was = owner.class.polymorphic_class_for(model_type_was) if model_type_was
65
+ else
66
+ model_was = klass
67
+ end
68
+
69
+ foreign_key_was = owner.attribute_before_last_save(reflection.foreign_key)
70
+
71
+ if foreign_key_was && model_was < ActiveRecord::Base
72
+ update_counters_via_scope(model_was, foreign_key_was, -1)
73
+ end
74
+ end
75
+
76
+ def target_changed?
77
+ owner.attribute_changed?(reflection.foreign_key) || (!foreign_key_present? && target&.new_record?)
78
+ end
79
+
80
+ def target_previously_changed?
81
+ owner.attribute_previously_changed?(reflection.foreign_key)
82
+ end
83
+
84
+ def saved_change_to_target?
85
+ owner.saved_change_to_attribute?(reflection.foreign_key)
86
+ end
87
+
88
+ private
89
+ def replace(record)
90
+ if record
91
+ raise_on_type_mismatch!(record)
92
+ set_inverse_instance(record)
93
+ @updated = true
94
+ elsif target
95
+ remove_inverse_instance(target)
96
+ end
97
+
98
+ replace_keys(record, force: true)
99
+
100
+ self.target = record
101
+ end
102
+
103
+ def update_counters(by)
104
+ if require_counter_update? && foreign_key_present?
105
+ if target && !stale_target?
106
+ target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch])
107
+ else
108
+ update_counters_via_scope(klass, owner._read_attribute(reflection.foreign_key), by)
109
+ end
110
+ end
111
+ end
112
+
113
+ def update_counters_via_scope(klass, foreign_key, by)
114
+ scope = klass.unscoped.where!(primary_key(klass) => foreign_key)
115
+ scope.update_counters(reflection.counter_cache_column => by, touch: reflection.options[:touch])
116
+ end
117
+
118
+ def find_target?
119
+ !loaded? && foreign_key_present? && klass
120
+ end
121
+
122
+ def require_counter_update?
123
+ reflection.counter_cache_column && owner.persisted?
124
+ end
125
+
126
+ def replace_keys(record, force: false)
127
+ reflection_fk = reflection.foreign_key
128
+ if reflection_fk.is_a?(Array)
129
+ target_key_values = record ? Array(primary_key(record.class)).map { |key| record._read_attribute(key) } : []
130
+
131
+ if force || reflection_fk.map { |fk| owner._read_attribute(fk) } != target_key_values
132
+ reflection_fk.each_with_index do |key, index|
133
+ owner[key] = target_key_values[index]
134
+ end
135
+ end
136
+ else
137
+ target_key_value = record ? record._read_attribute(primary_key(record.class)) : nil
138
+
139
+ if force || owner._read_attribute(reflection_fk) != target_key_value
140
+ owner[reflection_fk] = target_key_value
141
+ end
142
+ end
143
+ end
144
+
145
+ def primary_key(klass)
146
+ reflection.association_primary_key(klass)
147
+ end
148
+
149
+ def foreign_key_present?
150
+ Array(reflection.foreign_key).all? { |fk| owner._read_attribute(fk) }
151
+ end
152
+
153
+ def invertible_for?(record)
154
+ inverse = inverse_reflection_for(record)
155
+ inverse && (inverse.has_one? || inverse.klass.has_many_inversing)
156
+ end
157
+
158
+ def stale_state
159
+ owner._read_attribute(reflection.foreign_key) { |n| owner.send(:missing_attribute, n, caller) }
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Associations
5
+ # = Active Record Belongs To Polymorphic Association
6
+ class BelongsToPolymorphicAssociation < BelongsToAssociation # :nodoc:
7
+ def klass
8
+ type = owner[reflection.foreign_type]
9
+ type.presence && owner.class.polymorphic_class_for(type)
10
+ end
11
+
12
+ def target_changed?
13
+ super || owner.attribute_changed?(reflection.foreign_type)
14
+ end
15
+
16
+ def target_previously_changed?
17
+ super || owner.attribute_previously_changed?(reflection.foreign_type)
18
+ end
19
+
20
+ def saved_change_to_target?
21
+ super || owner.saved_change_to_attribute?(reflection.foreign_type)
22
+ end
23
+
24
+ private
25
+ def replace_keys(record, force: false)
26
+ super
27
+
28
+ target_type = record ? record.class.polymorphic_name : nil
29
+
30
+ if force || owner._read_attribute(reflection.foreign_type) != target_type
31
+ owner[reflection.foreign_type] = target_type
32
+ end
33
+ end
34
+
35
+ def inverse_reflection_for(record)
36
+ reflection.polymorphic_inverse_of(record.class)
37
+ end
38
+
39
+ def raise_on_type_mismatch!(record)
40
+ # A polymorphic association cannot have a type mismatch, by definition
41
+ end
42
+
43
+ def stale_state
44
+ if foreign_key = super
45
+ [foreign_key, owner[reflection.foreign_type]]
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is the parent Association class which defines the variables
4
+ # used by all associations.
5
+ #
6
+ # The hierarchy is defined as follows:
7
+ # Association
8
+ # - SingularAssociation
9
+ # - BelongsToAssociation
10
+ # - HasOneAssociation
11
+ # - CollectionAssociation
12
+ # - HasManyAssociation
13
+
14
+ module ActiveRecord::Associations::Builder # :nodoc:
15
+ class Association # :nodoc:
16
+ class << self
17
+ attr_accessor :extensions
18
+ end
19
+ self.extensions = []
20
+
21
+ VALID_OPTIONS = [
22
+ :class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading, :query_constraints
23
+ ].freeze # :nodoc:
24
+
25
+ def self.build(model, name, scope, options, &block)
26
+ if model.dangerous_attribute_method?(name)
27
+ raise ArgumentError, "You tried to define an association named #{name} on the model #{model.name}, but " \
28
+ "this will conflict with a method #{name} already defined by Active Record. " \
29
+ "Please choose a different association name."
30
+ end
31
+
32
+ reflection = create_reflection(model, name, scope, options, &block)
33
+ define_accessors(model, reflection)
34
+ define_callbacks(model, reflection)
35
+ define_validations(model, reflection)
36
+ define_change_tracking_methods(model, reflection)
37
+ reflection
38
+ end
39
+
40
+ def self.create_reflection(model, name, scope, options, &block)
41
+ raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
42
+
43
+ validate_options(options)
44
+
45
+ extension = define_extensions(model, name, &block)
46
+ options[:extend] = [*options[:extend], extension] if extension
47
+
48
+ scope = build_scope(scope)
49
+
50
+ ActiveRecord::Reflection.create(macro, name, scope, options, model)
51
+ end
52
+
53
+ def self.build_scope(scope)
54
+ if scope && scope.arity == 0
55
+ proc { instance_exec(&scope) }
56
+ else
57
+ scope
58
+ end
59
+ end
60
+
61
+ def self.macro
62
+ raise NotImplementedError
63
+ end
64
+
65
+ def self.valid_options(options)
66
+ VALID_OPTIONS + Association.extensions.flat_map(&:valid_options)
67
+ end
68
+
69
+ def self.validate_options(options)
70
+ options.assert_valid_keys(valid_options(options))
71
+ end
72
+
73
+ def self.define_extensions(model, name)
74
+ # noop
75
+ end
76
+
77
+ def self.define_callbacks(model, reflection)
78
+ if dependent = reflection.options[:dependent]
79
+ check_dependent_options(dependent, model)
80
+ add_destroy_callbacks(model, reflection)
81
+ add_after_commit_jobs_callback(model, dependent)
82
+ end
83
+
84
+ Association.extensions.each do |extension|
85
+ extension.build(model, reflection)
86
+ end
87
+ end
88
+
89
+ # Defines the setter and getter methods for the association
90
+ # class Post < ActiveRecord::Base
91
+ # has_many :comments
92
+ # end
93
+ #
94
+ # Post.first.comments and Post.first.comments= methods are defined by this method...
95
+ def self.define_accessors(model, reflection)
96
+ mixin = model.generated_association_methods
97
+ name = reflection.name
98
+ define_readers(mixin, name)
99
+ define_writers(mixin, name)
100
+ end
101
+
102
+ def self.define_readers(mixin, name)
103
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
104
+ def #{name}
105
+ association(:#{name}).reader
106
+ end
107
+ CODE
108
+ end
109
+
110
+ def self.define_writers(mixin, name)
111
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
112
+ def #{name}=(value)
113
+ association(:#{name}).writer(value)
114
+ end
115
+ CODE
116
+ end
117
+
118
+ def self.define_validations(model, reflection)
119
+ # noop
120
+ end
121
+
122
+ def self.define_change_tracking_methods(model, reflection)
123
+ # noop
124
+ end
125
+
126
+ def self.valid_dependent_options
127
+ raise NotImplementedError
128
+ end
129
+
130
+ def self.check_dependent_options(dependent, model)
131
+ if dependent == :destroy_async && !model.destroy_association_async_job
132
+ err_message = "A valid destroy_association_async_job is required to use `dependent: :destroy_async` on associations"
133
+ raise ActiveRecord::ConfigurationError, err_message
134
+ end
135
+ unless valid_dependent_options.include?(dependent)
136
+ raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
137
+ end
138
+ end
139
+
140
+ def self.add_destroy_callbacks(model, reflection)
141
+ name = reflection.name
142
+ model.before_destroy(->(o) { o.association(name).handle_dependency })
143
+ end
144
+
145
+ def self.add_after_commit_jobs_callback(model, dependent)
146
+ if dependent == :destroy_async
147
+ mixin = model.generated_association_methods
148
+
149
+ unless mixin.method_defined?(:_after_commit_jobs)
150
+ model.after_commit(-> do
151
+ _after_commit_jobs.each do |job_class, job_arguments|
152
+ job_class.perform_later(**job_arguments)
153
+ end
154
+ end)
155
+
156
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
157
+ def _after_commit_jobs
158
+ @_after_commit_jobs ||= []
159
+ end
160
+ CODE
161
+ end
162
+ end
163
+ end
164
+
165
+ private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
166
+ :define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
167
+ :define_change_tracking_methods, :valid_dependent_options, :check_dependent_options,
168
+ :add_destroy_callbacks, :add_after_commit_jobs_callback
169
+ end
170
+ end
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord::Associations::Builder # :nodoc:
4
+ class BelongsTo < SingularAssociation # :nodoc:
5
+ def self.macro
6
+ :belongs_to
7
+ end
8
+
9
+ def self.valid_options(options)
10
+ valid = super + [:polymorphic, :counter_cache, :optional, :default]
11
+ valid += [:foreign_type] if options[:polymorphic]
12
+ valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
13
+ valid
14
+ end
15
+
16
+ def self.valid_dependent_options
17
+ [:destroy, :delete, :destroy_async]
18
+ end
19
+
20
+ def self.define_callbacks(model, reflection)
21
+ super
22
+ add_counter_cache_callbacks(model, reflection) if reflection.options[:counter_cache]
23
+ add_touch_callbacks(model, reflection) if reflection.options[:touch]
24
+ add_default_callbacks(model, reflection) if reflection.options[:default]
25
+ end
26
+
27
+ def self.add_counter_cache_callbacks(model, reflection)
28
+ cache_column = reflection.counter_cache_column
29
+
30
+ model.after_update lambda { |record|
31
+ association = association(reflection.name)
32
+
33
+ if association.saved_change_to_target?
34
+ association.increment_counters
35
+ association.decrement_counters_before_last_save
36
+ end
37
+ }
38
+
39
+ klass = reflection.class_name.safe_constantize
40
+ klass._counter_cache_columns |= [cache_column] if klass && klass.respond_to?(:_counter_cache_columns)
41
+ model.counter_cached_association_names |= [reflection.name]
42
+ end
43
+
44
+ def self.touch_record(o, changes, foreign_key, name, touch) # :nodoc:
45
+ old_foreign_id = changes[foreign_key] && changes[foreign_key].first
46
+
47
+ if old_foreign_id
48
+ association = o.association(name)
49
+ reflection = association.reflection
50
+ if reflection.polymorphic?
51
+ foreign_type = reflection.foreign_type
52
+ klass = changes[foreign_type] && changes[foreign_type].first || o.public_send(foreign_type)
53
+ klass = o.class.polymorphic_class_for(klass)
54
+ else
55
+ klass = association.klass
56
+ end
57
+ primary_key = reflection.association_primary_key(klass)
58
+ old_record = klass.find_by(primary_key => old_foreign_id)
59
+
60
+ if old_record
61
+ if touch != true
62
+ old_record.touch_later(touch)
63
+ else
64
+ old_record.touch_later
65
+ end
66
+ end
67
+ end
68
+
69
+ record = o.public_send name
70
+ if record && record.persisted?
71
+ if touch != true
72
+ record.touch_later(touch)
73
+ else
74
+ record.touch_later
75
+ end
76
+ end
77
+ end
78
+
79
+ def self.add_touch_callbacks(model, reflection)
80
+ foreign_key = reflection.foreign_key
81
+ name = reflection.name
82
+ touch = reflection.options[:touch]
83
+
84
+ callback = lambda { |changes_method| lambda { |record|
85
+ BelongsTo.touch_record(record, record.send(changes_method), foreign_key, name, touch)
86
+ }}
87
+
88
+ if reflection.counter_cache_column
89
+ touch_callback = callback.(:saved_changes)
90
+ update_callback = lambda { |record|
91
+ instance_exec(record, &touch_callback) unless association(reflection.name).saved_change_to_target?
92
+ }
93
+ model.after_update update_callback, if: :saved_changes?
94
+ else
95
+ model.after_create callback.(:saved_changes), if: :saved_changes?
96
+ model.after_update callback.(:saved_changes), if: :saved_changes?
97
+ model.after_destroy callback.(:changes_to_save)
98
+ end
99
+
100
+ model.after_touch callback.(:changes_to_save)
101
+ end
102
+
103
+ def self.add_default_callbacks(model, reflection)
104
+ model.before_validation lambda { |o|
105
+ o.association(reflection.name).default(&reflection.options[:default])
106
+ }
107
+ end
108
+
109
+ def self.add_destroy_callbacks(model, reflection)
110
+ model.after_destroy lambda { |o| o.association(reflection.name).handle_dependency }
111
+ end
112
+
113
+ def self.define_validations(model, reflection)
114
+ if reflection.options.key?(:required)
115
+ reflection.options[:optional] = !reflection.options.delete(:required)
116
+ end
117
+
118
+ if reflection.options[:optional].nil?
119
+ required = model.belongs_to_required_by_default
120
+ else
121
+ required = !reflection.options[:optional]
122
+ end
123
+
124
+ super
125
+
126
+ if required
127
+ if ActiveRecord.belongs_to_required_validates_foreign_key
128
+ model.validates_presence_of reflection.name, message: :required
129
+ else
130
+ condition = lambda { |record|
131
+ foreign_key = reflection.foreign_key
132
+ foreign_type = reflection.foreign_type
133
+
134
+ record.read_attribute(foreign_key).nil? ||
135
+ record.attribute_changed?(foreign_key) ||
136
+ (reflection.polymorphic? && (record.read_attribute(foreign_type).nil? || record.attribute_changed?(foreign_type)))
137
+ }
138
+
139
+ model.validates_presence_of reflection.name, message: :required, if: condition
140
+ end
141
+ end
142
+ end
143
+
144
+ def self.define_change_tracking_methods(model, reflection)
145
+ model.generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
146
+ def #{reflection.name}_changed?
147
+ association(:#{reflection.name}).target_changed?
148
+ end
149
+
150
+ def #{reflection.name}_previously_changed?
151
+ association(:#{reflection.name}).target_previously_changed?
152
+ end
153
+ CODE
154
+ end
155
+
156
+ private_class_method :macro, :valid_options, :valid_dependent_options, :define_callbacks,
157
+ :define_validations, :define_change_tracking_methods, :add_counter_cache_callbacks,
158
+ :add_touch_callbacks, :add_default_callbacks, :add_destroy_callbacks
159
+ end
160
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/associations"
4
+
5
+ module ActiveRecord::Associations::Builder # :nodoc:
6
+ class CollectionAssociation < Association # :nodoc:
7
+ CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
8
+
9
+ def self.valid_options(options)
10
+ super + [:before_add, :after_add, :before_remove, :after_remove, :extend]
11
+ end
12
+
13
+ def self.define_callbacks(model, reflection)
14
+ super
15
+ name = reflection.name
16
+ options = reflection.options
17
+ CALLBACKS.each { |callback_name|
18
+ define_callback(model, callback_name, name, options)
19
+ }
20
+ end
21
+
22
+ def self.define_extensions(model, name, &block)
23
+ if block_given?
24
+ extension_module_name = "#{name.to_s.camelize}AssociationExtension"
25
+ extension = Module.new(&block)
26
+ model.const_set(extension_module_name, extension)
27
+ end
28
+ end
29
+
30
+ def self.define_callback(model, callback_name, name, options)
31
+ full_callback_name = "#{callback_name}_for_#{name}"
32
+
33
+ callback_values = Array(options[callback_name.to_sym])
34
+ method_defined = model.respond_to?(full_callback_name)
35
+
36
+ # If there are no callbacks, we must also check if a superclass had
37
+ # previously defined this association
38
+ return if callback_values.empty? && !method_defined
39
+
40
+ unless method_defined
41
+ model.class_attribute(full_callback_name, instance_accessor: false, instance_predicate: false)
42
+ end
43
+
44
+ callbacks = callback_values.map do |callback|
45
+ case callback
46
+ when Symbol
47
+ ->(method, owner, record) { owner.send(callback, record) }
48
+ when Proc
49
+ ->(method, owner, record) { callback.call(owner, record) }
50
+ else
51
+ ->(method, owner, record) { callback.send(method, owner, record) }
52
+ end
53
+ end
54
+ model.send "#{full_callback_name}=", callbacks
55
+ end
56
+
57
+ # Defines the setter and getter methods for the collection_singular_ids.
58
+ def self.define_readers(mixin, name)
59
+ super
60
+
61
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
62
+ def #{name.to_s.singularize}_ids
63
+ association(:#{name}).ids_reader
64
+ end
65
+ CODE
66
+ end
67
+
68
+ def self.define_writers(mixin, name)
69
+ super
70
+
71
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
72
+ def #{name.to_s.singularize}_ids=(ids)
73
+ association(:#{name}).ids_writer(ids)
74
+ end
75
+ CODE
76
+ end
77
+
78
+ private_class_method :valid_options, :define_callback, :define_extensions, :define_readers, :define_writers
79
+ end
80
+ end