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,961 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ module ActiveRecord
5
+ module ConnectionAdapters # :nodoc:
6
+ # Abstract representation of an index definition on a table. Instances of
7
+ # this type are typically created and returned by methods in database
8
+ # adapters. e.g. ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#indexes
9
+ class IndexDefinition # :nodoc:
10
+ attr_reader :table, :name, :unique, :columns, :lengths, :orders, :opclasses, :where, :type, :using, :include, :nulls_not_distinct, :comment, :valid
11
+
12
+ def initialize(
13
+ table, name,
14
+ unique = false,
15
+ columns = [],
16
+ lengths: {},
17
+ orders: {},
18
+ opclasses: {},
19
+ where: nil,
20
+ type: nil,
21
+ using: nil,
22
+ include: nil,
23
+ nulls_not_distinct: nil,
24
+ comment: nil,
25
+ valid: true
26
+ )
27
+ @table = table
28
+ @name = name
29
+ @unique = unique
30
+ @columns = columns
31
+ @lengths = concise_options(lengths)
32
+ @orders = concise_options(orders)
33
+ @opclasses = concise_options(opclasses)
34
+ @where = where
35
+ @type = type
36
+ @using = using
37
+ @include = include
38
+ @nulls_not_distinct = nulls_not_distinct
39
+ @comment = comment
40
+ @valid = valid
41
+ end
42
+
43
+ def valid?
44
+ @valid
45
+ end
46
+
47
+ def column_options
48
+ {
49
+ length: lengths,
50
+ order: orders,
51
+ opclass: opclasses,
52
+ }
53
+ end
54
+
55
+ def defined_for?(columns = nil, name: nil, unique: nil, valid: nil, include: nil, nulls_not_distinct: nil, **options)
56
+ columns = options[:column] if columns.blank?
57
+ (columns.nil? || Array(self.columns) == Array(columns).map(&:to_s)) &&
58
+ (name.nil? || self.name == name.to_s) &&
59
+ (unique.nil? || self.unique == unique) &&
60
+ (valid.nil? || self.valid == valid) &&
61
+ (include.nil? || Array(self.include) == Array(include).map(&:to_s)) &&
62
+ (nulls_not_distinct.nil? || self.nulls_not_distinct == nulls_not_distinct)
63
+ end
64
+
65
+ private
66
+ def concise_options(options)
67
+ if columns.size == options.size && options.values.uniq.size == 1
68
+ options.values.first
69
+ else
70
+ options
71
+ end
72
+ end
73
+ end
74
+
75
+ # Abstract representation of a column definition. Instances of this type
76
+ # are typically created by methods in TableDefinition, and added to the
77
+ # +columns+ attribute of said TableDefinition object, in order to be used
78
+ # for generating a number of table creation or table changing SQL statements.
79
+ ColumnDefinition = Struct.new(:name, :type, :options, :sql_type) do # :nodoc:
80
+ self::OPTION_NAMES = [
81
+ :limit,
82
+ :precision,
83
+ :scale,
84
+ :default,
85
+ :null,
86
+ :collation,
87
+ :comment,
88
+ :primary_key,
89
+ :if_exists,
90
+ :if_not_exists
91
+ ]
92
+
93
+ def primary_key?
94
+ options[:primary_key]
95
+ end
96
+
97
+ (self::OPTION_NAMES - [:primary_key]).each do |option_name|
98
+ module_eval <<-CODE, __FILE__, __LINE__ + 1
99
+ def #{option_name}
100
+ options[:#{option_name}]
101
+ end
102
+
103
+ def #{option_name}=(value)
104
+ options[:#{option_name}] = value
105
+ end
106
+ CODE
107
+ end
108
+
109
+ def aliased_types(name, fallback)
110
+ "timestamp" == name ? :datetime : fallback
111
+ end
112
+ end
113
+
114
+ AddColumnDefinition = Struct.new(:column) # :nodoc:
115
+
116
+ ChangeColumnDefinition = Struct.new(:column, :name) # :nodoc:
117
+
118
+ ChangeColumnDefaultDefinition = Struct.new(:column, :default) # :nodoc:
119
+
120
+ CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists) # :nodoc:
121
+
122
+ PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
123
+
124
+ ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do # :nodoc:
125
+ def name
126
+ options[:name]
127
+ end
128
+
129
+ def column
130
+ options[:column]
131
+ end
132
+
133
+ def primary_key
134
+ options[:primary_key] || default_primary_key
135
+ end
136
+
137
+ def on_delete
138
+ options[:on_delete]
139
+ end
140
+
141
+ def on_update
142
+ options[:on_update]
143
+ end
144
+
145
+ def deferrable
146
+ options[:deferrable]
147
+ end
148
+
149
+ def custom_primary_key?
150
+ options[:primary_key] != default_primary_key
151
+ end
152
+
153
+ def validate?
154
+ options.fetch(:validate, true)
155
+ end
156
+ alias validated? validate?
157
+
158
+ def export_name_on_schema_dump?
159
+ !ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
160
+ end
161
+
162
+ def defined_for?(to_table: nil, validate: nil, **options)
163
+ (to_table.nil? || to_table.to_s == self.to_table) &&
164
+ (validate.nil? || validate == self.options.fetch(:validate, validate)) &&
165
+ options.all? { |k, v| Array(self.options[k]).map(&:to_s) == Array(v).map(&:to_s) }
166
+ end
167
+
168
+ private
169
+ def default_primary_key
170
+ "id"
171
+ end
172
+ end
173
+
174
+ CheckConstraintDefinition = Struct.new(:table_name, :expression, :options) do
175
+ def name
176
+ options[:name]
177
+ end
178
+
179
+ def validate?
180
+ options.fetch(:validate, true)
181
+ end
182
+ alias validated? validate?
183
+
184
+ def export_name_on_schema_dump?
185
+ !ActiveRecord::SchemaDumper.chk_ignore_pattern.match?(name) if name
186
+ end
187
+
188
+ def defined_for?(name:, expression: nil, validate: nil, **options)
189
+ self.name == name.to_s &&
190
+ (validate.nil? || validate == self.options.fetch(:validate, validate)) &&
191
+ options.all? { |k, v| self.options[k].to_s == v.to_s }
192
+ end
193
+ end
194
+
195
+ class ReferenceDefinition # :nodoc:
196
+ def initialize(
197
+ name,
198
+ polymorphic: false,
199
+ index: true,
200
+ foreign_key: false,
201
+ type: :bigint,
202
+ **options
203
+ )
204
+ @name = name
205
+ @polymorphic = polymorphic
206
+ @index = index
207
+ @foreign_key = foreign_key
208
+ @type = type
209
+ @options = options
210
+
211
+ if polymorphic && foreign_key
212
+ raise ArgumentError, "Cannot add a foreign key to a polymorphic relation"
213
+ end
214
+ end
215
+
216
+ def add(table_name, connection)
217
+ columns.each do |name, type, options|
218
+ connection.add_column(table_name, name, type, **options)
219
+ end
220
+
221
+ if index
222
+ connection.add_index(table_name, column_names, **index_options(table_name))
223
+ end
224
+
225
+ if foreign_key
226
+ connection.add_foreign_key(table_name, foreign_table_name, **foreign_key_options)
227
+ end
228
+ end
229
+
230
+ def add_to(table)
231
+ columns.each do |name, type, options|
232
+ table.column(name, type, **options)
233
+ end
234
+
235
+ if index
236
+ table.index(column_names, **index_options(table.name))
237
+ end
238
+
239
+ if foreign_key
240
+ table.foreign_key(foreign_table_name, **foreign_key_options)
241
+ end
242
+ end
243
+
244
+ private
245
+ attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
246
+
247
+ def as_options(value)
248
+ value.is_a?(Hash) ? value : {}
249
+ end
250
+
251
+ def conditional_options
252
+ options.slice(:if_exists, :if_not_exists)
253
+ end
254
+
255
+ def polymorphic_options
256
+ as_options(polymorphic).merge(conditional_options).merge(options.slice(:null, :first, :after))
257
+ end
258
+
259
+ def polymorphic_index_name(table_name)
260
+ "index_#{table_name}_on_#{name}"
261
+ end
262
+
263
+ def index_options(table_name)
264
+ index_options = as_options(index).merge(conditional_options)
265
+
266
+ # legacy reference index names are used on versions 6.0 and earlier
267
+ return index_options if options[:_uses_legacy_reference_index_name]
268
+
269
+ index_options[:name] ||= polymorphic_index_name(table_name) if polymorphic
270
+ index_options
271
+ end
272
+
273
+ def foreign_key_options
274
+ as_options(foreign_key).merge(column: column_name, **conditional_options)
275
+ end
276
+
277
+ def columns
278
+ result = [[column_name, type, options]]
279
+ if polymorphic
280
+ result.unshift(["#{name}_type", :string, polymorphic_options])
281
+ end
282
+ result
283
+ end
284
+
285
+ def column_name
286
+ "#{name}_id"
287
+ end
288
+
289
+ def column_names
290
+ columns.map(&:first)
291
+ end
292
+
293
+ def foreign_table_name
294
+ foreign_key_options.fetch(:to_table) do
295
+ Base.pluralize_table_names ? name.to_s.pluralize : name
296
+ end
297
+ end
298
+ end
299
+
300
+ module ColumnMethods
301
+ extend ActiveSupport::Concern
302
+
303
+ # Appends a primary key definition to the table definition.
304
+ # Can be called multiple times, but this is probably not a good idea.
305
+ def primary_key(name, type = :primary_key, **options)
306
+ column(name, type, **options.merge(primary_key: true))
307
+ end
308
+
309
+ ##
310
+ # :method: column
311
+ # :call-seq: column(name, type, **options)
312
+ #
313
+ # Appends a column or columns of a specified type.
314
+ #
315
+ # t.string(:goat)
316
+ # t.string(:goat, :sheep)
317
+ #
318
+ # See TableDefinition#column
319
+
320
+ included do
321
+ define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
322
+ :float, :integer, :json, :string, :text, :time, :timestamp, :virtual
323
+
324
+ alias :blob :binary
325
+ alias :numeric :decimal
326
+ end
327
+
328
+ class_methods do
329
+ def define_column_methods(*column_types) # :nodoc:
330
+ column_types.each do |column_type|
331
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
332
+ def #{column_type}(*names, **options)
333
+ raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
334
+ names.each { |name| column(name, :#{column_type}, **options) }
335
+ end
336
+ RUBY
337
+ end
338
+ end
339
+ private :define_column_methods
340
+ end
341
+ end
342
+
343
+ # = Active Record Connection Adapters \Table \Definition
344
+ #
345
+ # Represents the schema of an SQL table in an abstract way. This class
346
+ # provides methods for manipulating the schema representation.
347
+ #
348
+ # Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
349
+ # is actually of this type:
350
+ #
351
+ # class SomeMigration < ActiveRecord::Migration[8.0]
352
+ # def up
353
+ # create_table :foo do |t|
354
+ # puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
355
+ # end
356
+ # end
357
+ #
358
+ # def down
359
+ # ...
360
+ # end
361
+ # end
362
+ #
363
+ class TableDefinition
364
+ include ColumnMethods
365
+
366
+ attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys, :check_constraints
367
+
368
+ def initialize(
369
+ conn,
370
+ name,
371
+ temporary: false,
372
+ if_not_exists: false,
373
+ options: nil,
374
+ as: nil,
375
+ comment: nil,
376
+ **
377
+ )
378
+ @conn = conn
379
+ @columns_hash = {}
380
+ @indexes = []
381
+ @foreign_keys = []
382
+ @primary_keys = nil
383
+ @check_constraints = []
384
+ @temporary = temporary
385
+ @if_not_exists = if_not_exists
386
+ @options = options
387
+ @as = as
388
+ @name = name
389
+ @comment = comment
390
+ end
391
+
392
+ def set_primary_key(table_name, id, primary_key, **options)
393
+ if id && !as
394
+ pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
395
+
396
+ if id.is_a?(Hash)
397
+ options.merge!(id.except(:type))
398
+ id = id.fetch(:type, :primary_key)
399
+ end
400
+
401
+ if pk.is_a?(Array)
402
+ primary_keys(pk)
403
+ else
404
+ primary_key(pk, id, **options)
405
+ end
406
+ end
407
+ end
408
+
409
+ def primary_keys(name = nil) # :nodoc:
410
+ @primary_keys = PrimaryKeyDefinition.new(name) if name
411
+ @primary_keys
412
+ end
413
+
414
+ # Returns an array of ColumnDefinition objects for the columns of the table.
415
+ def columns; @columns_hash.values; end
416
+
417
+ # Returns a ColumnDefinition for the column with name +name+.
418
+ def [](name)
419
+ @columns_hash[name.to_s]
420
+ end
421
+
422
+ # Instantiates a new column for the table.
423
+ # See {connection.add_column}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_column]
424
+ # for available options.
425
+ #
426
+ # Additional options are:
427
+ # * <tt>:index</tt> -
428
+ # Create an index for the column. Can be either <tt>true</tt> or an options hash.
429
+ #
430
+ # This method returns <tt>self</tt>.
431
+ #
432
+ # == Examples
433
+ #
434
+ # # Assuming +td+ is an instance of TableDefinition
435
+ # td.column(:granted, :boolean, index: true)
436
+ #
437
+ # == Short-hand examples
438
+ #
439
+ # Instead of calling #column directly, you can also work with the short-hand definitions for the default types.
440
+ # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined
441
+ # in a single statement.
442
+ #
443
+ # What can be written like this with the regular calls to column:
444
+ #
445
+ # create_table :products do |t|
446
+ # t.column :shop_id, :integer
447
+ # t.column :creator_id, :integer
448
+ # t.column :item_number, :string
449
+ # t.column :name, :string, default: "Untitled"
450
+ # t.column :value, :string, default: "Untitled"
451
+ # t.column :created_at, :datetime
452
+ # t.column :updated_at, :datetime
453
+ # end
454
+ # add_index :products, :item_number
455
+ #
456
+ # can also be written as follows using the short-hand:
457
+ #
458
+ # create_table :products do |t|
459
+ # t.integer :shop_id, :creator_id
460
+ # t.string :item_number, index: true
461
+ # t.string :name, :value, default: "Untitled"
462
+ # t.timestamps null: false
463
+ # end
464
+ #
465
+ # There's a short-hand method for each of the type values declared at the top. And then there's
466
+ # TableDefinition#timestamps that'll add +created_at+ and +updated_at+ as datetimes.
467
+ #
468
+ # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
469
+ # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
470
+ # options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
471
+ # will also create an index, similar to calling {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index].
472
+ # So what can be written like this:
473
+ #
474
+ # create_table :taggings do |t|
475
+ # t.integer :tag_id, :tagger_id, :taggable_id
476
+ # t.string :tagger_type
477
+ # t.string :taggable_type, default: 'Photo'
478
+ # end
479
+ # add_index :taggings, :tag_id, name: 'index_taggings_on_tag_id'
480
+ # add_index :taggings, [:tagger_id, :tagger_type]
481
+ #
482
+ # Can also be written as follows using references:
483
+ #
484
+ # create_table :taggings do |t|
485
+ # t.references :tag, index: { name: 'index_taggings_on_tag_id' }
486
+ # t.references :tagger, polymorphic: true
487
+ # t.references :taggable, polymorphic: { default: 'Photo' }, index: false
488
+ # end
489
+ def column(name, type, index: nil, **options)
490
+ name = name.to_s
491
+ type = type.to_sym if type
492
+
493
+ raise_on_duplicate_column(name)
494
+ @columns_hash[name] = new_column_definition(name, type, **options)
495
+
496
+ if index
497
+ index_options = index.is_a?(Hash) ? index : {}
498
+ index(name, **index_options)
499
+ end
500
+
501
+ self
502
+ end
503
+
504
+ # remove the column +name+ from the table.
505
+ # remove_column(:account_id)
506
+ def remove_column(name)
507
+ @columns_hash.delete name.to_s
508
+ end
509
+
510
+ # Adds index options to the indexes hash, keyed by column name
511
+ # This is primarily used to track indexes that need to be created after the table
512
+ #
513
+ # index(:account_id, name: 'index_projects_on_account_id')
514
+ def index(column_name, **options)
515
+ indexes << [column_name, options]
516
+ end
517
+
518
+ def foreign_key(to_table, **options)
519
+ foreign_keys << new_foreign_key_definition(to_table, options)
520
+ end
521
+
522
+ def check_constraint(expression, **options)
523
+ check_constraints << new_check_constraint_definition(expression, options)
524
+ end
525
+
526
+ # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
527
+ # <tt>:updated_at</tt> to the table. See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
528
+ #
529
+ # t.timestamps null: false
530
+ def timestamps(**options)
531
+ options[:null] = false if options[:null].nil?
532
+
533
+ if !options.key?(:precision) && @conn.supports_datetime_with_precision?
534
+ options[:precision] = 6
535
+ end
536
+
537
+ column(:created_at, :datetime, **options)
538
+ column(:updated_at, :datetime, **options)
539
+ end
540
+
541
+ # Adds a reference.
542
+ #
543
+ # t.references(:user)
544
+ # t.belongs_to(:supplier, foreign_key: true)
545
+ # t.belongs_to(:supplier, foreign_key: true, type: :integer)
546
+ #
547
+ # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
548
+ def references(*args, **options)
549
+ args.each do |ref_name|
550
+ ReferenceDefinition.new(ref_name, **options).add_to(self)
551
+ end
552
+ end
553
+ alias :belongs_to :references
554
+
555
+ def new_column_definition(name, type, **options) # :nodoc:
556
+ if integer_like_primary_key?(type, options)
557
+ type = integer_like_primary_key_type(type, options)
558
+ end
559
+ type = aliased_types(type.to_s, type)
560
+
561
+ if @conn.supports_datetime_with_precision?
562
+ if type == :datetime && !options.key?(:precision)
563
+ options[:precision] = 6
564
+ end
565
+ end
566
+
567
+ options[:primary_key] ||= type == :primary_key
568
+ options[:null] = false if options[:primary_key]
569
+ create_column_definition(name, type, options)
570
+ end
571
+
572
+ def new_foreign_key_definition(to_table, options) # :nodoc:
573
+ prefix = ActiveRecord::Base.table_name_prefix
574
+ suffix = ActiveRecord::Base.table_name_suffix
575
+ to_table = "#{prefix}#{to_table}#{suffix}"
576
+ options = @conn.foreign_key_options(name, to_table, options)
577
+ ForeignKeyDefinition.new(name, to_table, options)
578
+ end
579
+
580
+ def new_check_constraint_definition(expression, options) # :nodoc:
581
+ options = @conn.check_constraint_options(name, expression, options)
582
+ CheckConstraintDefinition.new(name, expression, options)
583
+ end
584
+
585
+ private
586
+ def valid_column_definition_options
587
+ @conn.valid_column_definition_options
588
+ end
589
+
590
+ def create_column_definition(name, type, options)
591
+ unless options[:_skip_validate_options]
592
+ options.except(:_uses_legacy_reference_index_name, :_skip_validate_options).assert_valid_keys(valid_column_definition_options)
593
+ end
594
+
595
+ ColumnDefinition.new(name, type, options)
596
+ end
597
+
598
+ def aliased_types(name, fallback)
599
+ "timestamp" == name ? :datetime : fallback
600
+ end
601
+
602
+ def integer_like_primary_key?(type, options)
603
+ options[:primary_key] && [:integer, :bigint].include?(type) && !options.key?(:default)
604
+ end
605
+
606
+ def integer_like_primary_key_type(type, options)
607
+ type
608
+ end
609
+
610
+ def raise_on_duplicate_column(name)
611
+ if @columns_hash[name]
612
+ if @columns_hash[name].primary_key?
613
+ raise ArgumentError, "you can't redefine the primary key column '#{name}' on '#{@name}'. To define a custom primary key, pass { id: false } to create_table."
614
+ else
615
+ raise ArgumentError, "you can't define an already defined column '#{name}' on '#{@name}'."
616
+ end
617
+ end
618
+ end
619
+ end
620
+
621
+ class AlterTable # :nodoc:
622
+ attr_reader :adds
623
+ attr_reader :foreign_key_adds, :foreign_key_drops
624
+ attr_reader :check_constraint_adds, :check_constraint_drops
625
+
626
+ def initialize(td)
627
+ @td = td
628
+ @adds = []
629
+ @foreign_key_adds = []
630
+ @foreign_key_drops = []
631
+ @check_constraint_adds = []
632
+ @check_constraint_drops = []
633
+ end
634
+
635
+ def name; @td.name; end
636
+
637
+ def add_foreign_key(to_table, options)
638
+ @foreign_key_adds << @td.new_foreign_key_definition(to_table, options)
639
+ end
640
+
641
+ def drop_foreign_key(name)
642
+ @foreign_key_drops << name
643
+ end
644
+
645
+ def add_check_constraint(expression, options)
646
+ @check_constraint_adds << @td.new_check_constraint_definition(expression, options)
647
+ end
648
+
649
+ def drop_check_constraint(constraint_name)
650
+ @check_constraint_drops << constraint_name
651
+ end
652
+
653
+ def add_column(name, type, **options)
654
+ name = name.to_s
655
+ type = type.to_sym
656
+ @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, **options))
657
+ end
658
+ end
659
+
660
+ # = Active Record Connection Adapters \Table
661
+ #
662
+ # Represents an SQL table in an abstract way for updating a table.
663
+ # Also see TableDefinition and {connection.create_table}[rdoc-ref:SchemaStatements#create_table]
664
+ #
665
+ # Available transformations are:
666
+ #
667
+ # change_table :table do |t|
668
+ # t.primary_key
669
+ # t.column
670
+ # t.index
671
+ # t.rename_index
672
+ # t.timestamps
673
+ # t.change
674
+ # t.change_default
675
+ # t.change_null
676
+ # t.rename
677
+ # t.references
678
+ # t.belongs_to
679
+ # t.check_constraint
680
+ # t.string
681
+ # t.text
682
+ # t.integer
683
+ # t.bigint
684
+ # t.float
685
+ # t.decimal
686
+ # t.numeric
687
+ # t.datetime
688
+ # t.timestamp
689
+ # t.time
690
+ # t.date
691
+ # t.binary
692
+ # t.blob
693
+ # t.boolean
694
+ # t.foreign_key
695
+ # t.json
696
+ # t.virtual
697
+ # t.remove
698
+ # t.remove_foreign_key
699
+ # t.remove_references
700
+ # t.remove_belongs_to
701
+ # t.remove_index
702
+ # t.remove_check_constraint
703
+ # t.remove_timestamps
704
+ # end
705
+ #
706
+ class Table
707
+ include ColumnMethods
708
+
709
+ attr_reader :name
710
+
711
+ def initialize(table_name, base)
712
+ @name = table_name
713
+ @base = base
714
+ end
715
+
716
+ # Adds a new column to the named table.
717
+ #
718
+ # t.column(:name, :string)
719
+ #
720
+ # See TableDefinition#column for details of the options you can use.
721
+ def column(column_name, type, index: nil, **options)
722
+ raise_on_if_exist_options(options)
723
+ @base.add_column(name, column_name, type, **options)
724
+ if index
725
+ index_options = index.is_a?(Hash) ? index : {}
726
+ index(column_name, **index_options)
727
+ end
728
+ end
729
+
730
+ # Checks to see if a column exists.
731
+ #
732
+ # t.string(:name) unless t.column_exists?(:name, :string)
733
+ #
734
+ # See {connection.column_exists?}[rdoc-ref:SchemaStatements#column_exists?]
735
+ def column_exists?(column_name, type = nil, **options)
736
+ @base.column_exists?(name, column_name, type, **options)
737
+ end
738
+
739
+ # Adds a new index to the table. +column_name+ can be a single Symbol, or
740
+ # an Array of Symbols.
741
+ #
742
+ # t.index(:name)
743
+ # t.index([:branch_id, :party_id], unique: true)
744
+ # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
745
+ #
746
+ # See {connection.add_index}[rdoc-ref:SchemaStatements#add_index] for details of the options you can use.
747
+ def index(column_name, **options)
748
+ raise_on_if_exist_options(options)
749
+ @base.add_index(name, column_name, **options)
750
+ end
751
+
752
+ # Checks to see if an index exists.
753
+ #
754
+ # unless t.index_exists?(:branch_id)
755
+ # t.index(:branch_id)
756
+ # end
757
+ #
758
+ # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
759
+ def index_exists?(column_name, **options)
760
+ @base.index_exists?(name, column_name, **options)
761
+ end
762
+
763
+ # Renames the given index on the table.
764
+ #
765
+ # t.rename_index(:user_id, :account_id)
766
+ #
767
+ # See {connection.rename_index}[rdoc-ref:SchemaStatements#rename_index]
768
+ def rename_index(index_name, new_index_name)
769
+ @base.rename_index(name, index_name, new_index_name)
770
+ end
771
+
772
+ # Adds timestamps (+created_at+ and +updated_at+) columns to the table.
773
+ #
774
+ # t.timestamps(null: false)
775
+ #
776
+ # See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
777
+ def timestamps(**options)
778
+ raise_on_if_exist_options(options)
779
+ @base.add_timestamps(name, **options)
780
+ end
781
+
782
+ # Changes the column's definition according to the new options.
783
+ #
784
+ # t.change(:name, :string, limit: 80)
785
+ # t.change(:description, :text)
786
+ #
787
+ # See TableDefinition#column for details of the options you can use.
788
+ def change(column_name, type, **options)
789
+ raise_on_if_exist_options(options)
790
+ @base.change_column(name, column_name, type, **options)
791
+ end
792
+
793
+ # Sets a new default value for a column.
794
+ #
795
+ # t.change_default(:qualification, 'new')
796
+ # t.change_default(:authorized, 1)
797
+ # t.change_default(:status, from: nil, to: "draft")
798
+ #
799
+ # See {connection.change_column_default}[rdoc-ref:SchemaStatements#change_column_default]
800
+ def change_default(column_name, default_or_changes)
801
+ @base.change_column_default(name, column_name, default_or_changes)
802
+ end
803
+
804
+ # Sets or removes a NOT NULL constraint on a column.
805
+ #
806
+ # t.change_null(:qualification, true)
807
+ # t.change_null(:qualification, false, 0)
808
+ #
809
+ # See {connection.change_column_null}[rdoc-ref:SchemaStatements#change_column_null]
810
+ def change_null(column_name, null, default = nil)
811
+ @base.change_column_null(name, column_name, null, default)
812
+ end
813
+
814
+ # Removes the column(s) from the table definition.
815
+ #
816
+ # t.remove(:qualification)
817
+ # t.remove(:qualification, :experience)
818
+ #
819
+ # See {connection.remove_columns}[rdoc-ref:SchemaStatements#remove_columns]
820
+ def remove(*column_names, **options)
821
+ raise_on_if_exist_options(options)
822
+ @base.remove_columns(name, *column_names, **options)
823
+ end
824
+
825
+ # Removes the given index from the table.
826
+ #
827
+ # t.remove_index(:branch_id)
828
+ # t.remove_index(column: [:branch_id, :party_id])
829
+ # t.remove_index(name: :by_branch_party)
830
+ # t.remove_index(:branch_id, name: :by_branch_party)
831
+ #
832
+ # See {connection.remove_index}[rdoc-ref:SchemaStatements#remove_index]
833
+ def remove_index(column_name = nil, **options)
834
+ raise_on_if_exist_options(options)
835
+ @base.remove_index(name, column_name, **options)
836
+ end
837
+
838
+ # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
839
+ #
840
+ # t.remove_timestamps
841
+ #
842
+ # See {connection.remove_timestamps}[rdoc-ref:SchemaStatements#remove_timestamps]
843
+ def remove_timestamps(**options)
844
+ @base.remove_timestamps(name, **options)
845
+ end
846
+
847
+ # Renames a column.
848
+ #
849
+ # t.rename(:description, :name)
850
+ #
851
+ # See {connection.rename_column}[rdoc-ref:SchemaStatements#rename_column]
852
+ def rename(column_name, new_column_name)
853
+ @base.rename_column(name, column_name, new_column_name)
854
+ end
855
+
856
+ # Adds a reference.
857
+ #
858
+ # t.references(:user)
859
+ # t.belongs_to(:supplier, foreign_key: true)
860
+ #
861
+ # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
862
+ def references(*args, **options)
863
+ raise_on_if_exist_options(options)
864
+ args.each do |ref_name|
865
+ @base.add_reference(name, ref_name, **options)
866
+ end
867
+ end
868
+ alias :belongs_to :references
869
+
870
+ # Removes a reference. Optionally removes a +type+ column.
871
+ #
872
+ # t.remove_references(:user)
873
+ # t.remove_belongs_to(:supplier, polymorphic: true)
874
+ #
875
+ # See {connection.remove_reference}[rdoc-ref:SchemaStatements#remove_reference]
876
+ def remove_references(*args, **options)
877
+ raise_on_if_exist_options(options)
878
+ args.each do |ref_name|
879
+ @base.remove_reference(name, ref_name, **options)
880
+ end
881
+ end
882
+ alias :remove_belongs_to :remove_references
883
+
884
+ # Adds a foreign key to the table using a supplied table name.
885
+ #
886
+ # t.foreign_key(:authors)
887
+ # t.foreign_key(:authors, column: :author_id, primary_key: "id")
888
+ #
889
+ # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
890
+ def foreign_key(*args, **options)
891
+ raise_on_if_exist_options(options)
892
+ @base.add_foreign_key(name, *args, **options)
893
+ end
894
+
895
+ # Removes the given foreign key from the table.
896
+ #
897
+ # t.remove_foreign_key(:authors)
898
+ # t.remove_foreign_key(column: :author_id)
899
+ #
900
+ # See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
901
+ def remove_foreign_key(*args, **options)
902
+ raise_on_if_exist_options(options)
903
+ @base.remove_foreign_key(name, *args, **options)
904
+ end
905
+
906
+ # Checks to see if a foreign key exists.
907
+ #
908
+ # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
909
+ #
910
+ # See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
911
+ def foreign_key_exists?(*args, **options)
912
+ @base.foreign_key_exists?(name, *args, **options)
913
+ end
914
+
915
+ # Adds a check constraint.
916
+ #
917
+ # t.check_constraint("price > 0", name: "price_check")
918
+ #
919
+ # See {connection.add_check_constraint}[rdoc-ref:SchemaStatements#add_check_constraint]
920
+ def check_constraint(*args, **options)
921
+ @base.add_check_constraint(name, *args, **options)
922
+ end
923
+
924
+ # Removes the given check constraint from the table.
925
+ #
926
+ # t.remove_check_constraint(name: "price_check")
927
+ #
928
+ # See {connection.remove_check_constraint}[rdoc-ref:SchemaStatements#remove_check_constraint]
929
+ def remove_check_constraint(*args, **options)
930
+ @base.remove_check_constraint(name, *args, **options)
931
+ end
932
+
933
+ # Checks if a check_constraint exists on a table.
934
+ #
935
+ # unless t.check_constraint_exists?(name: "price_check")
936
+ # t.check_constraint("price > 0", name: "price_check")
937
+ # end
938
+ #
939
+ # See {connection.check_constraint_exists?}[rdoc-ref:SchemaStatements#check_constraint_exists?]
940
+ def check_constraint_exists?(*args, **options)
941
+ @base.check_constraint_exists?(name, *args, **options)
942
+ end
943
+
944
+ private
945
+ def raise_on_if_exist_options(options)
946
+ unrecognized_option = options.keys.find do |key|
947
+ key == :if_exists || key == :if_not_exists
948
+ end
949
+ if unrecognized_option
950
+ conditional = unrecognized_option == :if_exists ? "if" : "unless"
951
+ message = <<~TXT
952
+ Option #{unrecognized_option} will be ignored. If you are calling an expression like
953
+ `t.column(.., #{unrecognized_option}: true)` from inside a change_table block, try a
954
+ conditional clause instead, as in `t.column(..) #{conditional} t.column_exists?(..)`
955
+ TXT
956
+ raise ArgumentError.new(message)
957
+ end
958
+ end
959
+ end
960
+ end
961
+ end