omg-activerecord 8.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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