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,850 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "yaml"
5
+ require "set"
6
+ require "active_support/dependencies"
7
+ require "active_support/core_ext/digest/uuid"
8
+ require "active_record/test_fixtures"
9
+
10
+ module ActiveRecord
11
+ class FixtureClassNotFound < ActiveRecord::ActiveRecordError # :nodoc:
12
+ end
13
+
14
+ # = Active Record \Fixtures
15
+ #
16
+ # \Fixtures are a way of organizing data that you want to test against; in short, sample data.
17
+ #
18
+ # They are stored in YAML files, one file per model, which are by default placed in either
19
+ # <tt><your-rails-app>/test/fixtures/</tt> or in the <tt>test/fixtures</tt>
20
+ # folder under any of your application's engines.
21
+ #
22
+ # The location can also be changed with ActiveSupport::TestCase.fixture_paths=,
23
+ # once you have <tt>require "rails/test_help"</tt> in your +test_helper.rb+.
24
+ #
25
+ # The fixture file ends with the +.yml+ file extension, for example:
26
+ # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
27
+ #
28
+ # The format of a fixture file looks like this:
29
+ #
30
+ # rubyonrails:
31
+ # id: 1
32
+ # name: Ruby on Rails
33
+ # url: http://www.rubyonrails.org
34
+ #
35
+ # google:
36
+ # id: 2
37
+ # name: Google
38
+ # url: http://www.google.com
39
+ #
40
+ # This fixture file includes two fixtures. Each YAML fixture (i.e. record) is given a name and
41
+ # is followed by an indented list of key/value pairs in the "key: value" format. Records are
42
+ # separated by a blank line for your viewing pleasure.
43
+ #
44
+ # == Ordering
45
+ #
46
+ # Fixtures by default are unordered. This is because the maps in YAML are unordered.
47
+ #
48
+ # If you want ordered fixtures, use the omap YAML type.
49
+ # See https://yaml.org/type/omap.html for the specification.
50
+ #
51
+ # You will need ordered fixtures when you have foreign key constraints
52
+ # on keys in the same table. This is commonly needed for tree structures.
53
+ #
54
+ # For example:
55
+ #
56
+ # --- !omap
57
+ # - parent:
58
+ # id: 1
59
+ # parent_id: NULL
60
+ # title: Parent
61
+ # - child:
62
+ # id: 2
63
+ # parent_id: 1
64
+ # title: Child
65
+ #
66
+ # == Using Fixtures in Test Cases
67
+ #
68
+ # Since fixtures are a testing construct, we use them in our unit and functional tests. There
69
+ # are two ways to use the fixtures, but first let's take a look at a sample unit test:
70
+ #
71
+ # require "test_helper"
72
+ #
73
+ # class WebSiteTest < ActiveSupport::TestCase
74
+ # test "web_site_count" do
75
+ # assert_equal 2, WebSite.count
76
+ # end
77
+ # end
78
+ #
79
+ # By default, +test_helper.rb+ will load all of your fixtures into your test
80
+ # database, so this test will succeed.
81
+ #
82
+ # The testing environment will automatically load all the fixtures into the database before each
83
+ # test. To ensure consistent data, the environment deletes the fixtures before running the load.
84
+ #
85
+ # In addition to being available in the database, the fixture's data may also be accessed by
86
+ # using a special dynamic method, which has the same name as the model.
87
+ #
88
+ # Passing in a fixture name to this dynamic method returns the fixture matching this name:
89
+ #
90
+ # test "find one" do
91
+ # assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
92
+ # end
93
+ #
94
+ # Passing in multiple fixture names returns all fixtures matching these names:
95
+ #
96
+ # test "find all by name" do
97
+ # assert_equal 2, web_sites(:rubyonrails, :google).length
98
+ # end
99
+ #
100
+ # Passing in no arguments returns all fixtures:
101
+ #
102
+ # test "find all" do
103
+ # assert_equal 2, web_sites.length
104
+ # end
105
+ #
106
+ # Passing in any fixture name that does not exist will raise <tt>StandardError</tt>:
107
+ #
108
+ # test "find by name that does not exist" do
109
+ # assert_raise(StandardError) { web_sites(:reddit) }
110
+ # end
111
+ #
112
+ # If the model names conflicts with a +TestCase+ methods, you can use the generic +fixture+ accessor
113
+ #
114
+ # test "generic find" do
115
+ # assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
116
+ # end
117
+ #
118
+ # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
119
+ # following tests:
120
+ #
121
+ # test "find_alt_method_1" do
122
+ # assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name']
123
+ # end
124
+ #
125
+ # test "find_alt_method_2" do
126
+ # assert_equal "Ruby on Rails", @rubyonrails.name
127
+ # end
128
+ #
129
+ # In order to use these methods to access fixtured data within your test cases, you must specify one of the
130
+ # following in your ActiveSupport::TestCase-derived class:
131
+ #
132
+ # - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
133
+ # self.use_instantiated_fixtures = true
134
+ #
135
+ # - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only)
136
+ # self.use_instantiated_fixtures = :no_instances
137
+ #
138
+ # Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully
139
+ # traversed in the database to create the fixture hash and/or instance variables. This is expensive for
140
+ # large sets of fixtured data.
141
+ #
142
+ # == Dynamic fixtures with \ERB
143
+ #
144
+ # Sometimes you don't care about the content of the fixtures as much as you care about the volume.
145
+ # In these cases, you can mix ERB in with your YAML fixtures to create a bunch of fixtures for load
146
+ # testing, like:
147
+ #
148
+ # <% 1.upto(1000) do |i| %>
149
+ # fix_<%= i %>:
150
+ # id: <%= i %>
151
+ # name: guy_<%= i %>
152
+ # <% end %>
153
+ #
154
+ # This will create 1000 very simple fixtures.
155
+ #
156
+ # Using ERB, you can also inject dynamic values into your fixtures with inserts like
157
+ # <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
158
+ # This is however a feature to be used with some caution. The point of fixtures are that they're
159
+ # stable units of predictable sample data. If you feel that you need to inject dynamic values, then
160
+ # perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
161
+ # in fixtures are to be considered a code smell.
162
+ #
163
+ # Helper methods defined in a fixture will not be available in other fixtures, to prevent against
164
+ # unwanted inter-test dependencies. Methods used by multiple fixtures should be defined in a module
165
+ # that is included in ActiveRecord::FixtureSet.context_class.
166
+ #
167
+ # - define a helper method in <tt>test_helper.rb</tt>
168
+ # module FixtureFileHelpers
169
+ # def file_sha(path)
170
+ # OpenSSL::Digest::SHA256.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
171
+ # end
172
+ # end
173
+ # ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers
174
+ #
175
+ # - use the helper method in a fixture
176
+ # photo:
177
+ # name: kitten.png
178
+ # sha: <%= file_sha 'files/kitten.png' %>
179
+ #
180
+ # == Transactional Tests
181
+ #
182
+ # Test cases can use begin+rollback to isolate their changes to the database instead of having to
183
+ # delete+insert for every test case.
184
+ #
185
+ # class FooTest < ActiveSupport::TestCase
186
+ # self.use_transactional_tests = true
187
+ #
188
+ # test "godzilla" do
189
+ # assert_not_empty Foo.all
190
+ # Foo.destroy_all
191
+ # assert_empty Foo.all
192
+ # end
193
+ #
194
+ # test "godzilla aftermath" do
195
+ # assert_not_empty Foo.all
196
+ # end
197
+ # end
198
+ #
199
+ # If you preload your test database with all fixture data (probably by running <tt>bin/rails db:fixtures:load</tt>)
200
+ # and use transactional tests, then you may omit all fixtures declarations in your test cases since
201
+ # all the data's already there and every case rolls back its changes.
202
+ #
203
+ # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
204
+ # true. This will provide access to fixture data for every table that has been loaded through
205
+ # fixtures (depending on the value of +use_instantiated_fixtures+).
206
+ #
207
+ # When *not* to use transactional tests:
208
+ #
209
+ # 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
210
+ # all parent transactions commit, particularly, the fixtures transaction which is begun in setup
211
+ # and rolled back in teardown. Thus, you won't be able to verify
212
+ # the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
213
+ # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
214
+ # Use InnoDB, MaxDB, or NDB instead.
215
+ #
216
+ # == Advanced Fixtures
217
+ #
218
+ # Fixtures that don't specify an ID get some extra features:
219
+ #
220
+ # * Stable, autogenerated IDs
221
+ # * Label references for associations (belongs_to, has_one, has_many)
222
+ # * HABTM associations as inline lists
223
+ #
224
+ # There are some more advanced features available even if the id is specified:
225
+ #
226
+ # * Autofilled timestamp columns
227
+ # * Fixture label interpolation
228
+ # * Support for YAML defaults
229
+ #
230
+ # === Stable, Autogenerated IDs
231
+ #
232
+ # Here, have a monkey fixture:
233
+ #
234
+ # george:
235
+ # id: 1
236
+ # name: George the Monkey
237
+ #
238
+ # reginald:
239
+ # id: 2
240
+ # name: Reginald the Pirate
241
+ #
242
+ # Each of these fixtures has two unique identifiers: one for the database
243
+ # and one for the humans. Why don't we generate the primary key instead?
244
+ # Hashing each fixture's label yields a consistent ID:
245
+ #
246
+ # george: # generated id: 503576764
247
+ # name: George the Monkey
248
+ #
249
+ # reginald: # generated id: 324201669
250
+ # name: Reginald the Pirate
251
+ #
252
+ # Active Record looks at the fixture's model class, discovers the correct
253
+ # primary key, and generates it right before inserting the fixture
254
+ # into the database.
255
+ #
256
+ # The generated ID for a given label is constant, so we can discover
257
+ # any fixture's ID without loading anything, as long as we know the label.
258
+ #
259
+ # === Label references for associations (+belongs_to+, +has_one+, +has_many+)
260
+ #
261
+ # Specifying foreign keys in fixtures can be very fragile, not to
262
+ # mention difficult to read. Since Active Record can figure out the ID of
263
+ # any fixture from its label, you can specify FK's by label instead of ID.
264
+ #
265
+ # ==== +belongs_to+
266
+ #
267
+ # Let's break out some more monkeys and pirates.
268
+ #
269
+ # ### in pirates.yml
270
+ #
271
+ # reginald:
272
+ # id: 1
273
+ # name: Reginald the Pirate
274
+ # monkey_id: 1
275
+ #
276
+ # <code></code>
277
+ #
278
+ # ### in monkeys.yml
279
+ #
280
+ # george:
281
+ # id: 1
282
+ # name: George the Monkey
283
+ # pirate_id: 1
284
+ #
285
+ # Add a few more monkeys and pirates and break this into multiple files,
286
+ # and it gets pretty hard to keep track of what's going on. Let's
287
+ # use labels instead of IDs:
288
+ #
289
+ # ### in pirates.yml
290
+ #
291
+ # reginald:
292
+ # name: Reginald the Pirate
293
+ # monkey: george
294
+ #
295
+ # <code></code>
296
+ #
297
+ # ### in monkeys.yml
298
+ #
299
+ # george:
300
+ # name: George the Monkey
301
+ # pirate: reginald
302
+ #
303
+ # Pow! All is made clear. Active Record reflects on the fixture's model class,
304
+ # finds all the +belongs_to+ associations, and allows you to specify
305
+ # a target *label* for the *association* (monkey: george) rather than
306
+ # a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
307
+ #
308
+ # ==== Polymorphic +belongs_to+
309
+ #
310
+ # Supporting polymorphic relationships is a little bit more complicated, since
311
+ # Active Record needs to know what type your association is pointing at. Something
312
+ # like this should look familiar:
313
+ #
314
+ # ### in fruit.rb
315
+ #
316
+ # belongs_to :eater, polymorphic: true
317
+ #
318
+ # <code></code>
319
+ #
320
+ # ### in fruits.yml
321
+ #
322
+ # apple:
323
+ # id: 1
324
+ # name: apple
325
+ # eater_id: 1
326
+ # eater_type: Monkey
327
+ #
328
+ # Can we do better? You bet!
329
+ #
330
+ # apple:
331
+ # eater: george (Monkey)
332
+ #
333
+ # Just provide the polymorphic target type and Active Record will take care of the rest.
334
+ #
335
+ # ==== +has_and_belongs_to_many+ or <tt>has_many :through</tt>
336
+ #
337
+ # \Time to give our monkey some fruit.
338
+ #
339
+ # ### in monkeys.yml
340
+ #
341
+ # george:
342
+ # id: 1
343
+ # name: George the Monkey
344
+ #
345
+ # <code></code>
346
+ #
347
+ # ### in fruits.yml
348
+ #
349
+ # apple:
350
+ # id: 1
351
+ # name: apple
352
+ #
353
+ # orange:
354
+ # id: 2
355
+ # name: orange
356
+ #
357
+ # grape:
358
+ # id: 3
359
+ # name: grape
360
+ #
361
+ # <code></code>
362
+ #
363
+ # ### in fruits_monkeys.yml
364
+ #
365
+ # apple_george:
366
+ # fruit_id: 1
367
+ # monkey_id: 1
368
+ #
369
+ # orange_george:
370
+ # fruit_id: 2
371
+ # monkey_id: 1
372
+ #
373
+ # grape_george:
374
+ # fruit_id: 3
375
+ # monkey_id: 1
376
+ #
377
+ # Let's make the HABTM fixture go away.
378
+ #
379
+ # ### in monkeys.yml
380
+ #
381
+ # george:
382
+ # id: 1
383
+ # name: George the Monkey
384
+ # fruits: apple, orange, grape
385
+ #
386
+ # <code></code>
387
+ #
388
+ # ### in fruits.yml
389
+ #
390
+ # apple:
391
+ # name: apple
392
+ #
393
+ # orange:
394
+ # name: orange
395
+ #
396
+ # grape:
397
+ # name: grape
398
+ #
399
+ # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
400
+ # on George's fixture, but we could've just as easily specified a list
401
+ # of monkeys on each fruit. As with +belongs_to+, Active Record reflects on
402
+ # the fixture's model class and discovers the +has_and_belongs_to_many+
403
+ # associations.
404
+ #
405
+ # === Autofilled \Timestamp Columns
406
+ #
407
+ # If your table/model specifies any of Active Record's
408
+ # standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
409
+ # they will automatically be set to <tt>Time.now</tt>.
410
+ #
411
+ # If you've set specific values, they'll be left alone.
412
+ #
413
+ # === Fixture label interpolation
414
+ #
415
+ # The label of the current fixture is always available as a column value:
416
+ #
417
+ # geeksomnia:
418
+ # name: Geeksomnia's Account
419
+ # subdomain: $LABEL
420
+ # email: $LABEL@email.com
421
+ #
422
+ # Also, sometimes (like when porting older join table fixtures) you'll need
423
+ # to be able to get a hold of the identifier for a given label. ERB
424
+ # to the rescue:
425
+ #
426
+ # george_reginald:
427
+ # monkey_id: <%= ActiveRecord::FixtureSet.identify(:reginald) %>
428
+ # pirate_id: <%= ActiveRecord::FixtureSet.identify(:george) %>
429
+ #
430
+ # If the model uses UUID values for identifiers, add the +:uuid+ argument:
431
+ #
432
+ # ActiveRecord::FixtureSet.identify(:boaty_mcboatface, :uuid)
433
+ #
434
+ # === Support for YAML defaults
435
+ #
436
+ # You can set and reuse defaults in your fixtures YAML file.
437
+ # This is the same technique used in the +database.yml+ file to specify
438
+ # defaults:
439
+ #
440
+ # DEFAULTS: &DEFAULTS
441
+ # created_on: <%= 3.weeks.ago.to_fs(:db) %>
442
+ #
443
+ # first:
444
+ # name: Smurf
445
+ # <<: *DEFAULTS
446
+ #
447
+ # second:
448
+ # name: Fraggle
449
+ # <<: *DEFAULTS
450
+ #
451
+ # Any fixture labeled "DEFAULTS" is safely ignored.
452
+ #
453
+ # Besides using "DEFAULTS", you can also specify what fixtures will
454
+ # be ignored by setting "ignore" in "_fixture" section.
455
+ #
456
+ # # users.yml
457
+ # _fixture:
458
+ # ignore:
459
+ # - base
460
+ # # or use "ignore: base" when there is only one fixture that needs to be ignored.
461
+ #
462
+ # base: &base
463
+ # admin: false
464
+ # introduction: "This is a default description"
465
+ #
466
+ # admin:
467
+ # <<: *base
468
+ # admin: true
469
+ #
470
+ # visitor:
471
+ # <<: *base
472
+ #
473
+ # In the above example, 'base' will be ignored when creating fixtures.
474
+ # This can be used for common attributes inheriting.
475
+ #
476
+ # == Composite Primary Key Fixtures
477
+ #
478
+ # Fixtures for composite primary key tables are fairly similar to normal tables.
479
+ # When using an id column, the column may be omitted as usual:
480
+ #
481
+ # # app/models/book.rb
482
+ # class Book < ApplicationRecord
483
+ # self.primary_key = [:author_id, :id]
484
+ # belongs_to :author
485
+ # end
486
+ #
487
+ # <code></code>
488
+ #
489
+ # # books.yml
490
+ # alices_adventure_in_wonderland:
491
+ # author_id: <%= ActiveRecord::FixtureSet.identify(:lewis_carroll) %>
492
+ # title: "Alice's Adventures in Wonderland"
493
+ #
494
+ # However, in order to support composite primary key relationships,
495
+ # you must use the `composite_identify` method:
496
+ #
497
+ # # app/models/book_orders.rb
498
+ # class BookOrder < ApplicationRecord
499
+ # self.primary_key = [:shop_id, :id]
500
+ # belongs_to :order, foreign_key: [:shop_id, :order_id]
501
+ # belongs_to :book, foreign_key: [:author_id, :book_id]
502
+ # end
503
+ #
504
+ # <code></code>
505
+ #
506
+ # # book_orders.yml
507
+ # alices_adventure_in_wonderland_in_books:
508
+ # author: lewis_carroll
509
+ # book_id: <%= ActiveRecord::FixtureSet.composite_identify(
510
+ # :alices_adventure_in_wonderland, Book.primary_key)[:id] %>
511
+ # shop: book_store
512
+ # order_id: <%= ActiveRecord::FixtureSet.composite_identify(
513
+ # :books, Order.primary_key)[:id] %>
514
+ #
515
+ # == Configure the fixture model class
516
+ #
517
+ # It's possible to set the fixture's model class directly in the YAML file.
518
+ # This is helpful when fixtures are loaded outside tests and
519
+ # +set_fixture_class+ is not available (e.g.
520
+ # when running <tt>bin/rails db:fixtures:load</tt>).
521
+ #
522
+ # _fixture:
523
+ # model_class: User
524
+ # david:
525
+ # name: David
526
+ #
527
+ # Any fixtures labeled "_fixture" are safely ignored.
528
+ class FixtureSet
529
+ require "active_record/fixture_set/file"
530
+ require "active_record/fixture_set/render_context"
531
+ require "active_record/fixture_set/table_rows"
532
+
533
+ #--
534
+ # An instance of FixtureSet is normally stored in a single YAML file and
535
+ # possibly in a folder with the same name.
536
+ #++
537
+
538
+ MAX_ID = 2**30 - 1
539
+
540
+ @@all_cached_fixtures = Hash.new { |h, k| h[k] = {} }
541
+
542
+ cattr_accessor :all_loaded_fixtures, default: {}
543
+
544
+ class << self
545
+ def default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
546
+ config.pluralize_table_names ?
547
+ fixture_set_name.singularize.camelize :
548
+ fixture_set_name.camelize
549
+ end
550
+
551
+ def default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
552
+ "#{ config.table_name_prefix }"\
553
+ "#{ fixture_set_name.tr('/', '_') }"\
554
+ "#{ config.table_name_suffix }".to_sym
555
+ end
556
+
557
+ def reset_cache
558
+ @@all_cached_fixtures.clear
559
+ end
560
+
561
+ def cache_for_connection_pool(connection_pool)
562
+ @@all_cached_fixtures[connection_pool]
563
+ end
564
+
565
+ def fixture_is_cached?(connection_pool, table_name)
566
+ cache_for_connection_pool(connection_pool)[table_name]
567
+ end
568
+
569
+ def cached_fixtures(connection_pool, keys_to_fetch = nil)
570
+ if keys_to_fetch
571
+ cache_for_connection_pool(connection_pool).values_at(*keys_to_fetch)
572
+ else
573
+ cache_for_connection_pool(connection_pool).values
574
+ end
575
+ end
576
+
577
+ def cache_fixtures(connection_pool, fixtures_map)
578
+ cache_for_connection_pool(connection_pool).update(fixtures_map)
579
+ end
580
+
581
+ def instantiate_fixtures(object, fixture_set, load_instances = true)
582
+ return unless load_instances
583
+ fixture_set.each do |fixture_name, fixture|
584
+ object.instance_variable_set "@#{fixture_name}", fixture.find
585
+ rescue FixtureClassNotFound
586
+ nil
587
+ end
588
+ end
589
+
590
+ def instantiate_all_loaded_fixtures(object, load_instances = true)
591
+ all_loaded_fixtures.each_value do |fixture_set|
592
+ instantiate_fixtures(object, fixture_set, load_instances)
593
+ end
594
+ end
595
+
596
+ def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
597
+ fixture_set_names = Array(fixture_set_names).map(&:to_s)
598
+ class_names.stringify_keys!
599
+
600
+ connection_pool = config.connection_pool
601
+ fixture_files_to_read = fixture_set_names.reject do |fs_name|
602
+ fixture_is_cached?(connection_pool, fs_name)
603
+ end
604
+
605
+ if fixture_files_to_read.any?
606
+ fixtures_map = read_and_insert(
607
+ Array(fixtures_directories),
608
+ fixture_files_to_read,
609
+ class_names,
610
+ connection_pool,
611
+ )
612
+ cache_fixtures(connection_pool, fixtures_map)
613
+ end
614
+ cached_fixtures(connection_pool, fixture_set_names)
615
+ end
616
+
617
+ # Returns a consistent, platform-independent identifier for +label+.
618
+ #
619
+ # \Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
620
+ def identify(label, column_type = :integer)
621
+ if column_type == :uuid
622
+ Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
623
+ else
624
+ Zlib.crc32(label.to_s) % MAX_ID
625
+ end
626
+ end
627
+
628
+ # Returns a consistent, platform-independent hash representing a mapping
629
+ # between the label and the subcomponents of the provided composite key.
630
+ #
631
+ # Example:
632
+ #
633
+ # composite_identify("label", [:a, :b, :c]) # => { a: hash_1, b: hash_2, c: hash_3 }
634
+ def composite_identify(label, key)
635
+ key
636
+ .index_with
637
+ .with_index { |sub_key, index| (identify(label) << index) % MAX_ID }
638
+ .with_indifferent_access
639
+ end
640
+
641
+ # Superclass for the evaluation contexts used by \ERB fixtures.
642
+ def context_class
643
+ @context_class ||= Class.new
644
+ end
645
+
646
+ private
647
+ def read_and_insert(fixtures_directories, fixture_files, class_names, connection_pool) # :nodoc:
648
+ fixtures_map = {}
649
+ directory_glob = "{#{fixtures_directories.join(",")}}"
650
+ fixture_sets = fixture_files.map do |fixture_set_name|
651
+ klass = class_names[fixture_set_name]
652
+ fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new
653
+ nil,
654
+ fixture_set_name,
655
+ klass,
656
+ ::File.join(directory_glob, fixture_set_name)
657
+ )
658
+ end
659
+ update_all_loaded_fixtures(fixtures_map)
660
+
661
+ insert(fixture_sets, connection_pool)
662
+
663
+ fixtures_map
664
+ end
665
+
666
+ def insert(fixture_sets, connection_pool) # :nodoc:
667
+ fixture_sets_by_pool = fixture_sets.group_by do |fixture_set|
668
+ if fixture_set.model_class
669
+ fixture_set.model_class.connection_pool
670
+ else
671
+ connection_pool
672
+ end
673
+ end
674
+
675
+ fixture_sets_by_pool.each do |pool, set|
676
+ table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
677
+
678
+ set.each do |fixture_set|
679
+ fixture_set.table_rows.each do |table, rows|
680
+ table_rows_for_connection[table].unshift(*rows)
681
+ end
682
+ end
683
+
684
+ pool.with_connection do |conn|
685
+ conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
686
+
687
+ check_all_foreign_keys_valid!(conn)
688
+
689
+ # Cap primary key sequences to max(pk).
690
+ if conn.respond_to?(:reset_pk_sequence!)
691
+ set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
692
+ end
693
+ end
694
+ end
695
+ end
696
+
697
+ def check_all_foreign_keys_valid!(conn)
698
+ return unless ActiveRecord.verify_foreign_keys_for_fixtures
699
+
700
+ begin
701
+ conn.check_all_foreign_keys_valid!
702
+ rescue ActiveRecord::StatementInvalid => e
703
+ raise "Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations. Error from database:\n\n#{e.message}"
704
+ end
705
+ end
706
+
707
+ def update_all_loaded_fixtures(fixtures_map) # :nodoc:
708
+ all_loaded_fixtures.update(fixtures_map)
709
+ end
710
+ end
711
+
712
+ attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
713
+
714
+ def initialize(_, name, class_name, path, config = ActiveRecord::Base)
715
+ @name = name
716
+ @path = path
717
+ @config = config
718
+
719
+ self.model_class = class_name
720
+ @fixtures = read_fixture_files(path)
721
+
722
+ @table_name = model_class&.table_name || self.class.default_fixture_table_name(name, config)
723
+ end
724
+
725
+ def [](x)
726
+ fixtures[x]
727
+ end
728
+
729
+ def []=(k, v)
730
+ fixtures[k] = v
731
+ end
732
+
733
+ def each(&block)
734
+ fixtures.each(&block)
735
+ end
736
+
737
+ def size
738
+ fixtures.size
739
+ end
740
+
741
+ # Returns a hash of rows to be inserted. The key is the table, the value is
742
+ # a list of rows to insert to that table.
743
+ def table_rows
744
+ # allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
745
+ fixtures.except!(*ignored_fixtures)
746
+
747
+ TableRows.new(
748
+ table_name,
749
+ model_class: model_class,
750
+ fixtures: fixtures,
751
+ ).to_hash
752
+ end
753
+
754
+ private
755
+ def model_class=(class_name)
756
+ if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
757
+ @model_class = class_name
758
+ else
759
+ @model_class = class_name.safe_constantize if class_name
760
+ end
761
+ end
762
+
763
+ def ignored_fixtures=(base)
764
+ @ignored_fixtures =
765
+ case base
766
+ when Array
767
+ base
768
+ when String
769
+ [base]
770
+ else
771
+ []
772
+ end
773
+
774
+ @ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS")
775
+ @ignored_fixtures.compact
776
+ end
777
+
778
+ # Loads the fixtures from the YAML file at +path+.
779
+ # If the file sets the +model_class+ and current instance value is not set,
780
+ # it uses the file value.
781
+
782
+ def read_fixture_files(path)
783
+ yaml_files = Dir["#{path}{.yml,/{**,*}/*.yml}"].select { |f|
784
+ ::File.file?(f)
785
+ }
786
+
787
+ raise ArgumentError, "No fixture files found for #{@name}" if yaml_files.empty?
788
+
789
+ yaml_files.each_with_object({}) do |file, fixtures|
790
+ FixtureSet::File.open(file) do |fh|
791
+ self.model_class ||= fh.model_class if fh.model_class
792
+ self.model_class ||= default_fixture_model_class
793
+ self.ignored_fixtures ||= fh.ignored_fixtures
794
+ fh.each do |fixture_name, row|
795
+ fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
796
+ end
797
+ end
798
+ end
799
+ end
800
+
801
+ def default_fixture_model_class
802
+ klass = ActiveRecord::FixtureSet.default_fixture_model_name(@name, @config).safe_constantize
803
+ klass if klass && klass < ActiveRecord::Base
804
+ end
805
+ end
806
+
807
+ class Fixture # :nodoc:
808
+ include Enumerable
809
+
810
+ class FixtureError < StandardError # :nodoc:
811
+ end
812
+
813
+ class FormatError < FixtureError # :nodoc:
814
+ end
815
+
816
+ attr_reader :model_class, :fixture
817
+
818
+ def initialize(fixture, model_class)
819
+ @fixture = fixture
820
+ @model_class = model_class
821
+ end
822
+
823
+ def class_name
824
+ model_class.name if model_class
825
+ end
826
+
827
+ def each(&block)
828
+ fixture.each(&block)
829
+ end
830
+
831
+ def [](key)
832
+ fixture[key]
833
+ end
834
+
835
+ alias :to_hash :fixture
836
+
837
+ def find
838
+ raise FixtureClassNotFound, "No class attached to find." unless model_class
839
+ object = model_class.unscoped do
840
+ pk_clauses = fixture.slice(*Array(model_class.primary_key))
841
+ model_class.find_by!(pk_clauses)
842
+ end
843
+ # Fixtures can't be eagerly loaded
844
+ object.instance_variable_set(:@strict_loading, false)
845
+ object
846
+ end
847
+ end
848
+ end
849
+
850
+ ActiveSupport.run_load_hooks :active_record_fixture_set, ActiveRecord::FixtureSet