activerecord 4.2.0 → 6.1.7.1

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 (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1221 -796
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +267 -249
  8. data/lib/active_record/association_relation.rb +45 -7
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +172 -67
  11. data/lib/active_record/associations/association_scope.rb +105 -129
  12. data/lib/active_record/associations/belongs_to_association.rb +85 -59
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -33
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +168 -279
  22. data/lib/active_record/associations/collection_proxy.rb +263 -155
  23. data/lib/active_record/associations/foreign_association.rb +33 -0
  24. data/lib/active_record/associations/has_many_association.rb +57 -84
  25. data/lib/active_record/associations/has_many_through_association.rb +70 -82
  26. data/lib/active_record/associations/has_one_association.rb +74 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -73
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +175 -164
  32. data/lib/active_record/associations/preloader/association.rb +107 -112
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +99 -96
  35. data/lib/active_record/associations/singular_association.rb +18 -45
  36. data/lib/active_record/associations/through_association.rb +49 -24
  37. data/lib/active_record/associations.rb +1845 -1597
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -138
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -36
  46. data/lib/active_record/attribute_methods/write.rb +25 -56
  47. data/lib/active_record/attribute_methods.rb +153 -162
  48. data/lib/active_record/attributes.rb +234 -70
  49. data/lib/active_record/autosave_association.rb +157 -69
  50. data/lib/active_record/base.rb +49 -50
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +46 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +271 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +78 -161
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +499 -293
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +595 -382
  119. data/lib/active_record/connection_adapters/schema_cache.rb +191 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -389
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +488 -243
  133. data/lib/active_record/counter_cache.rb +71 -50
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +273 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +212 -94
  143. data/lib/active_record/errors.rb +225 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +11 -6
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +273 -496
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +64 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +52 -0
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +103 -95
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +298 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +685 -309
  170. data/lib/active_record/model_schema.rb +420 -113
  171. data/lib/active_record/nested_attributes.rb +265 -216
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +574 -135
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +175 -54
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +533 -216
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +485 -310
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +326 -244
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +318 -256
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +99 -84
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +139 -96
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -409
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +23 -21
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -342
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -26
  209. data/lib/active_record/scoping/default.rb +96 -82
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +133 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +366 -129
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +291 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +181 -152
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -41
  231. data/lib/active_record/type/date_time.rb +4 -38
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +33 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +65 -48
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +44 -28
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -10
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +175 -65
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  347. data/lib/active_record/attribute.rb +0 -149
  348. data/lib/active_record/attribute_decorators.rb +0 -66
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  351. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -30
  363. data/lib/active_record/type/decimal.rb +0 -40
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -55
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -36
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -101
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  374. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,31 +1,91 @@
1
- require 'date'
2
- require 'set'
3
- require 'bigdecimal'
4
- require 'bigdecimal/util'
1
+ # frozen_string_literal: true
5
2
 
6
3
  module ActiveRecord
7
4
  module ConnectionAdapters #:nodoc:
8
5
  # Abstract representation of an index definition on a table. Instances of
9
6
  # this type are typically created and returned by methods in database
10
- # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
11
- class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using) #:nodoc:
7
+ # adapters. e.g. ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#indexes
8
+ class IndexDefinition # :nodoc:
9
+ attr_reader :table, :name, :unique, :columns, :lengths, :orders, :opclasses, :where, :type, :using, :comment
10
+
11
+ def initialize(
12
+ table, name,
13
+ unique = false,
14
+ columns = [],
15
+ lengths: {},
16
+ orders: {},
17
+ opclasses: {},
18
+ where: nil,
19
+ type: nil,
20
+ using: nil,
21
+ comment: nil
22
+ )
23
+ @table = table
24
+ @name = name
25
+ @unique = unique
26
+ @columns = columns
27
+ @lengths = concise_options(lengths)
28
+ @orders = concise_options(orders)
29
+ @opclasses = concise_options(opclasses)
30
+ @where = where
31
+ @type = type
32
+ @using = using
33
+ @comment = comment
34
+ end
35
+
36
+ def column_options
37
+ {
38
+ length: lengths,
39
+ order: orders,
40
+ opclass: opclasses,
41
+ }
42
+ end
43
+
44
+ private
45
+ def concise_options(options)
46
+ if columns.size == options.size && options.values.uniq.size == 1
47
+ options.values.first
48
+ else
49
+ options
50
+ end
51
+ end
12
52
  end
13
53
 
14
54
  # Abstract representation of a column definition. Instances of this type
15
55
  # are typically created by methods in TableDefinition, and added to the
16
56
  # +columns+ attribute of said TableDefinition object, in order to be used
17
57
  # for generating a number of table creation or table changing SQL statements.
18
- class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type, :cast_type) #:nodoc:
19
-
58
+ ColumnDefinition = Struct.new(:name, :type, :options, :sql_type) do # :nodoc:
20
59
  def primary_key?
21
- primary_key || type.to_sym == :primary_key
60
+ options[:primary_key]
22
61
  end
23
- end
24
62
 
25
- class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc:
63
+ [:limit, :precision, :scale, :default, :null, :collation, :comment].each do |option_name|
64
+ module_eval <<-CODE, __FILE__, __LINE__ + 1
65
+ def #{option_name}
66
+ options[:#{option_name}]
67
+ end
68
+
69
+ def #{option_name}=(value)
70
+ options[:#{option_name}] = value
71
+ end
72
+ CODE
73
+ end
74
+
75
+ def aliased_types(name, fallback)
76
+ "timestamp" == name ? :datetime : fallback
77
+ end
26
78
  end
27
79
 
28
- class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
80
+ AddColumnDefinition = Struct.new(:column) # :nodoc:
81
+
82
+ ChangeColumnDefinition = Struct.new(:column, :name) #:nodoc:
83
+
84
+ CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists) # :nodoc:
85
+
86
+ PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
87
+
88
+ ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do #:nodoc:
29
89
  def name
30
90
  options[:name]
31
91
  end
@@ -50,31 +110,178 @@ module ActiveRecord
50
110
  options[:primary_key] != default_primary_key
51
111
  end
52
112
 
113
+ def validate?
114
+ options.fetch(:validate, true)
115
+ end
116
+ alias validated? validate?
117
+
118
+ def export_name_on_schema_dump?
119
+ !ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
120
+ end
121
+
122
+ def defined_for?(to_table: nil, validate: nil, **options)
123
+ (to_table.nil? || to_table.to_s == self.to_table) &&
124
+ (validate.nil? || validate == options.fetch(:validate, validate)) &&
125
+ options.all? { |k, v| self.options[k].to_s == v.to_s }
126
+ end
127
+
53
128
  private
54
- def default_primary_key
55
- "id"
129
+ def default_primary_key
130
+ "id"
131
+ end
132
+ end
133
+
134
+ CheckConstraintDefinition = Struct.new(:table_name, :expression, :options) do
135
+ def name
136
+ options[:name]
137
+ end
138
+
139
+ def validate?
140
+ options.fetch(:validate, true)
141
+ end
142
+ alias validated? validate?
143
+
144
+ def export_name_on_schema_dump?
145
+ !ActiveRecord::SchemaDumper.chk_ignore_pattern.match?(name) if name
56
146
  end
57
147
  end
58
148
 
59
- module TimestampDefaultDeprecation # :nodoc:
60
- def emit_warning_if_null_unspecified(options)
61
- return if options.key?(:null)
149
+ class ReferenceDefinition # :nodoc:
150
+ def initialize(
151
+ name,
152
+ polymorphic: false,
153
+ index: true,
154
+ foreign_key: false,
155
+ type: :bigint,
156
+ **options
157
+ )
158
+ @name = name
159
+ @polymorphic = polymorphic
160
+ @index = index
161
+ @foreign_key = foreign_key
162
+ @type = type
163
+ @options = options
62
164
 
63
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
64
- `#timestamp` was called without specifying an option for `null`. In Rails 5,
65
- this behavior will change to `null: false`. You should manually specify
66
- `null: true` to prevent the behavior of your existing migrations from changing.
67
- MSG
165
+ if polymorphic && foreign_key
166
+ raise ArgumentError, "Cannot add a foreign key to a polymorphic relation"
167
+ end
168
+ end
169
+
170
+ def add_to(table)
171
+ columns.each do |name, type, options|
172
+ table.column(name, type, **options)
173
+ end
174
+
175
+ if index
176
+ table.index(column_names, **index_options(table.name))
177
+ end
178
+
179
+ if foreign_key
180
+ table.foreign_key(foreign_table_name, **foreign_key_options)
181
+ end
182
+ end
183
+
184
+ private
185
+ attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
186
+
187
+ def as_options(value)
188
+ value.is_a?(Hash) ? value : {}
189
+ end
190
+
191
+ def polymorphic_options
192
+ as_options(polymorphic).merge(options.slice(:null, :first, :after))
193
+ end
194
+
195
+ def polymorphic_index_name(table_name)
196
+ "index_#{table_name}_on_#{name}"
197
+ end
198
+
199
+ def index_options(table_name)
200
+ index_options = as_options(index)
201
+
202
+ # legacy reference index names are used on versions 6.0 and earlier
203
+ return index_options if options[:_uses_legacy_reference_index_name]
204
+
205
+ index_options[:name] ||= polymorphic_index_name(table_name) if polymorphic
206
+ index_options
207
+ end
208
+
209
+ def foreign_key_options
210
+ as_options(foreign_key).merge(column: column_name)
211
+ end
212
+
213
+ def columns
214
+ result = [[column_name, type, options]]
215
+ if polymorphic
216
+ result.unshift(["#{name}_type", :string, polymorphic_options])
217
+ end
218
+ result
219
+ end
220
+
221
+ def column_name
222
+ "#{name}_id"
223
+ end
224
+
225
+ def column_names
226
+ columns.map(&:first)
227
+ end
228
+
229
+ def foreign_table_name
230
+ foreign_key_options.fetch(:to_table) do
231
+ Base.pluralize_table_names ? name.to_s.pluralize : name
232
+ end
233
+ end
234
+ end
235
+
236
+ module ColumnMethods
237
+ extend ActiveSupport::Concern
238
+
239
+ # Appends a primary key definition to the table definition.
240
+ # Can be called multiple times, but this is probably not a good idea.
241
+ def primary_key(name, type = :primary_key, **options)
242
+ column(name, type, **options.merge(primary_key: true))
243
+ end
244
+
245
+ ##
246
+ # :method: column
247
+ # :call-seq: column(name, type, **options)
248
+ #
249
+ # Appends a column or columns of a specified type.
250
+ #
251
+ # t.string(:goat)
252
+ # t.string(:goat, :sheep)
253
+ #
254
+ # See TableDefinition#column
255
+
256
+ included do
257
+ define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
258
+ :float, :integer, :json, :string, :text, :time, :timestamp, :virtual
259
+
260
+ alias :numeric :decimal
261
+ end
262
+
263
+ class_methods do
264
+ def define_column_methods(*column_types) # :nodoc:
265
+ column_types.each do |column_type|
266
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
267
+ def #{column_type}(*names, **options)
268
+ raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
269
+ names.each { |name| column(name, :#{column_type}, **options) }
270
+ end
271
+ RUBY
272
+ end
273
+ end
274
+ private :define_column_methods
68
275
  end
69
276
  end
70
277
 
71
278
  # Represents the schema of an SQL table in an abstract way. This class
72
279
  # provides methods for manipulating the schema representation.
73
280
  #
74
- # Inside migration files, the +t+ object in +create_table+
281
+ # Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
75
282
  # is actually of this type:
76
283
  #
77
- # class SomeMigration < ActiveRecord::Migration
284
+ # class SomeMigration < ActiveRecord::Migration[6.0]
78
285
  # def up
79
286
  # create_table :foo do |t|
80
287
  # puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
@@ -86,124 +293,66 @@ module ActiveRecord
86
293
  # end
87
294
  # end
88
295
  #
89
- # The table definitions
90
- # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
91
296
  class TableDefinition
92
- include TimestampDefaultDeprecation
93
-
94
- # An array of ColumnDefinition objects, representing the column changes
95
- # that have been defined.
96
- attr_accessor :indexes
97
- attr_reader :name, :temporary, :options, :as
98
-
99
- def initialize(types, name, temporary, options, as = nil)
297
+ include ColumnMethods
298
+
299
+ attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys, :check_constraints
300
+
301
+ def initialize(
302
+ conn,
303
+ name,
304
+ temporary: false,
305
+ if_not_exists: false,
306
+ options: nil,
307
+ as: nil,
308
+ comment: nil,
309
+ **
310
+ )
311
+ @conn = conn
100
312
  @columns_hash = {}
101
- @indexes = {}
102
- @native = types
313
+ @indexes = []
314
+ @foreign_keys = []
315
+ @primary_keys = nil
316
+ @check_constraints = []
103
317
  @temporary = temporary
318
+ @if_not_exists = if_not_exists
104
319
  @options = options
105
320
  @as = as
106
321
  @name = name
322
+ @comment = comment
107
323
  end
108
324
 
109
- def columns; @columns_hash.values; end
110
-
111
- # Appends a primary key definition to the table definition.
112
- # Can be called multiple times, but this is probably not a good idea.
113
- def primary_key(name, type = :primary_key, options = {})
114
- column(name, type, options.merge(:primary_key => true))
325
+ def primary_keys(name = nil) # :nodoc:
326
+ @primary_keys = PrimaryKeyDefinition.new(name) if name
327
+ @primary_keys
115
328
  end
116
329
 
330
+ # Returns an array of ColumnDefinition objects for the columns of the table.
331
+ def columns; @columns_hash.values; end
332
+
117
333
  # Returns a ColumnDefinition for the column with name +name+.
118
334
  def [](name)
119
335
  @columns_hash[name.to_s]
120
336
  end
121
337
 
122
338
  # Instantiates a new column for the table.
123
- # The +type+ parameter is normally one of the migrations native types,
124
- # which is one of the following:
125
- # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
126
- # <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
127
- # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
128
- # <tt>:binary</tt>, <tt>:boolean</tt>.
129
- #
130
- # You may use a type not in this list as long as it is supported by your
131
- # database (for example, "polygon" in MySQL), but this will not be database
132
- # agnostic and should usually be avoided.
133
- #
134
- # Available options are (none of these exists by default):
135
- # * <tt>:limit</tt> -
136
- # Requests a maximum column length. This is number of characters for <tt>:string</tt> and
137
- # <tt>:text</tt> columns and number of bytes for <tt>:binary</tt> and <tt>:integer</tt> columns.
138
- # * <tt>:default</tt> -
139
- # The column's default value. Use nil for NULL.
140
- # * <tt>:null</tt> -
141
- # Allows or disallows +NULL+ values in the column. This option could
142
- # have been named <tt>:null_allowed</tt>.
143
- # * <tt>:precision</tt> -
144
- # Specifies the precision for a <tt>:decimal</tt> column.
145
- # * <tt>:scale</tt> -
146
- # Specifies the scale for a <tt>:decimal</tt> column.
339
+ # See {connection.add_column}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_column]
340
+ # for available options.
341
+ #
342
+ # Additional options are:
147
343
  # * <tt>:index</tt> -
148
344
  # Create an index for the column. Can be either <tt>true</tt> or an options hash.
149
345
  #
150
- # Note: The precision is the total number of significant digits
151
- # and the scale is the number of digits that can be stored following
152
- # the decimal point. For example, the number 123.45 has a precision of 5
153
- # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
154
- # range from -999.99 to 999.99.
155
- #
156
- # Please be aware of different RDBMS implementations behavior with
157
- # <tt>:decimal</tt> columns:
158
- # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
159
- # <tt>:precision</tt>, and makes no comments about the requirements of
160
- # <tt>:precision</tt>.
161
- # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
162
- # Default is (10,0).
163
- # * PostgreSQL: <tt>:precision</tt> [1..infinity],
164
- # <tt>:scale</tt> [0..infinity]. No default.
165
- # * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
166
- # Internal storage as strings. No default.
167
- # * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
168
- # but the maximum supported <tt>:precision</tt> is 16. No default.
169
- # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
170
- # Default is (38,0).
171
- # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
172
- # Default unknown.
173
- # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
174
- # Default (38,0).
175
- #
176
346
  # This method returns <tt>self</tt>.
177
347
  #
178
348
  # == Examples
179
- # # Assuming +td+ is an instance of TableDefinition
180
- # td.column(:granted, :boolean)
181
- # # granted BOOLEAN
182
- #
183
- # td.column(:picture, :binary, limit: 2.megabytes)
184
- # # => picture BLOB(2097152)
185
- #
186
- # td.column(:sales_stage, :string, limit: 20, default: 'new', null: false)
187
- # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
188
- #
189
- # td.column(:bill_gates_money, :decimal, precision: 15, scale: 2)
190
- # # => bill_gates_money DECIMAL(15,2)
191
- #
192
- # td.column(:sensor_reading, :decimal, precision: 30, scale: 20)
193
- # # => sensor_reading DECIMAL(30,20)
194
- #
195
- # # While <tt>:scale</tt> defaults to zero on most databases, it
196
- # # probably wouldn't hurt to include it.
197
- # td.column(:huge_integer, :decimal, precision: 30)
198
- # # => huge_integer DECIMAL(30)
199
349
  #
200
- # # Defines a column with a database-specific type.
201
- # td.column(:foo, 'polygon')
202
- # # => foo polygon
350
+ # # Assuming +td+ is an instance of TableDefinition
351
+ # td.column(:granted, :boolean, index: true)
203
352
  #
204
353
  # == Short-hand examples
205
354
  #
206
- # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.
355
+ # Instead of calling #column directly, you can also work with the short-hand definitions for the default types.
207
356
  # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined
208
357
  # in a single statement.
209
358
  #
@@ -235,7 +384,8 @@ module ActiveRecord
235
384
  # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
236
385
  # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
237
386
  # options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
238
- # will also create an index, similar to calling <tt>add_index</tt>. So what can be written like this:
387
+ # will also create an index, similar to calling {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index].
388
+ # So what can be written like this:
239
389
  #
240
390
  # create_table :taggings do |t|
241
391
  # t.integer :tag_id, :tagger_id, :taggable_id
@@ -249,118 +399,122 @@ module ActiveRecord
249
399
  #
250
400
  # create_table :taggings do |t|
251
401
  # t.references :tag, index: { name: 'index_taggings_on_tag_id' }
252
- # t.references :tagger, polymorphic: true, index: true
253
- # t.references :taggable, polymorphic: { default: 'Photo' }
402
+ # t.references :tagger, polymorphic: true
403
+ # t.references :taggable, polymorphic: { default: 'Photo' }, index: false
254
404
  # end
255
- def column(name, type, options = {})
405
+ def column(name, type, index: nil, **options)
256
406
  name = name.to_s
257
- type = type.to_sym
407
+ type = type.to_sym if type
408
+
409
+ if @columns_hash[name]
410
+ if @columns_hash[name].primary_key?
411
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
412
+ else
413
+ raise ArgumentError, "you can't define an already defined column '#{name}'."
414
+ end
415
+ end
416
+
417
+ @columns_hash[name] = new_column_definition(name, type, **options)
258
418
 
259
- if @columns_hash[name] && @columns_hash[name].primary_key?
260
- raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
419
+ if index
420
+ index_options = index.is_a?(Hash) ? index : {}
421
+ index(name, **index_options)
261
422
  end
262
423
 
263
- index_options = options.delete(:index)
264
- index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
265
- @columns_hash[name] = new_column_definition(name, type, options)
266
424
  self
267
425
  end
268
426
 
427
+ # remove the column +name+ from the table.
428
+ # remove_column(:account_id)
269
429
  def remove_column(name)
270
430
  @columns_hash.delete name.to_s
271
431
  end
272
432
 
273
- [:string, :text, :integer, :bigint, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
274
- define_method column_type do |*args|
275
- options = args.extract_options!
276
- column_names = args
277
- column_names.each { |name| column(name, column_type, options) }
278
- end
279
- end
280
-
281
433
  # Adds index options to the indexes hash, keyed by column name
282
434
  # This is primarily used to track indexes that need to be created after the table
283
435
  #
284
436
  # index(:account_id, name: 'index_projects_on_account_id')
285
- def index(column_name, options = {})
286
- indexes[column_name] = options
437
+ def index(column_name, **options)
438
+ indexes << [column_name, options]
439
+ end
440
+
441
+ def foreign_key(table_name, **options) # :nodoc:
442
+ foreign_keys << [table_name, options]
443
+ end
444
+
445
+ def check_constraint(expression, **options)
446
+ check_constraints << [expression, options]
287
447
  end
288
448
 
289
449
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
290
- # <tt>:updated_at</tt> to the table. See SchemaStatements#add_timestamps
450
+ # <tt>:updated_at</tt> to the table. See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
291
451
  #
292
452
  # t.timestamps null: false
293
- def timestamps(*args)
294
- options = args.extract_options!
295
- emit_warning_if_null_unspecified(options)
296
- column(:created_at, :datetime, options)
297
- column(:updated_at, :datetime, options)
453
+ def timestamps(**options)
454
+ options[:null] = false if options[:null].nil?
455
+
456
+ if !options.key?(:precision) && @conn.supports_datetime_with_precision?
457
+ options[:precision] = 6
458
+ end
459
+
460
+ column(:created_at, :datetime, **options)
461
+ column(:updated_at, :datetime, **options)
298
462
  end
299
463
 
300
- # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
301
- # <tt>references</tt> and <tt>belongs_to</tt> are acceptable. The reference column will be an +integer+
302
- # by default, the <tt>:type</tt> option can be used to specify a different type.
464
+ # Adds a reference.
303
465
  #
304
466
  # t.references(:user)
305
- # t.references(:user, type: "string")
306
- # t.belongs_to(:supplier, polymorphic: true)
307
- #
308
- # See SchemaStatements#add_reference
309
- def references(*args)
310
- options = args.extract_options!
311
- polymorphic = options.delete(:polymorphic)
312
- index_options = options.delete(:index)
313
- type = options.delete(:type) || :integer
314
- args.each do |col|
315
- column("#{col}_id", type, options)
316
- column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
317
- index(polymorphic ? %w(type id).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
467
+ # t.belongs_to(:supplier, foreign_key: true)
468
+ # t.belongs_to(:supplier, foreign_key: true, type: :integer)
469
+ #
470
+ # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
471
+ def references(*args, **options)
472
+ args.each do |ref_name|
473
+ ReferenceDefinition.new(ref_name, **options).add_to(self)
318
474
  end
319
475
  end
320
476
  alias :belongs_to :references
321
477
 
322
- def new_column_definition(name, type, options) # :nodoc:
323
- type = aliased_types(type.to_s, type)
324
- column = create_column_definition name, type
325
- limit = options.fetch(:limit) do
326
- native[type][:limit] if native[type].is_a?(Hash)
478
+ def new_column_definition(name, type, **options) # :nodoc:
479
+ if integer_like_primary_key?(type, options)
480
+ type = integer_like_primary_key_type(type, options)
327
481
  end
328
-
329
- column.limit = limit
330
- column.precision = options[:precision]
331
- column.scale = options[:scale]
332
- column.default = options[:default]
333
- column.null = options[:null]
334
- column.first = options[:first]
335
- column.after = options[:after]
336
- column.primary_key = type == :primary_key || options[:primary_key]
337
- column
482
+ type = aliased_types(type.to_s, type)
483
+ options[:primary_key] ||= type == :primary_key
484
+ options[:null] = false if options[:primary_key]
485
+ create_column_definition(name, type, options)
338
486
  end
339
487
 
340
488
  private
341
- def create_column_definition(name, type)
342
- ColumnDefinition.new name, type
343
- end
489
+ def create_column_definition(name, type, options)
490
+ ColumnDefinition.new(name, type, options)
491
+ end
344
492
 
345
- def native
346
- @native
347
- end
493
+ def aliased_types(name, fallback)
494
+ "timestamp" == name ? :datetime : fallback
495
+ end
348
496
 
349
- def aliased_types(name, fallback)
350
- 'timestamp' == name ? :datetime : fallback
351
- end
497
+ def integer_like_primary_key?(type, options)
498
+ options[:primary_key] && [:integer, :bigint].include?(type) && !options.key?(:default)
499
+ end
500
+
501
+ def integer_like_primary_key_type(type, options)
502
+ type
503
+ end
352
504
  end
353
505
 
354
506
  class AlterTable # :nodoc:
355
507
  attr_reader :adds
356
- attr_reader :foreign_key_adds
357
- attr_reader :foreign_key_drops
508
+ attr_reader :foreign_key_adds, :foreign_key_drops
509
+ attr_reader :check_constraint_adds, :check_constraint_drops
358
510
 
359
511
  def initialize(td)
360
512
  @td = td
361
513
  @adds = []
362
514
  @foreign_key_adds = []
363
515
  @foreign_key_drops = []
516
+ @check_constraint_adds = []
517
+ @check_constraint_drops = []
364
518
  end
365
519
 
366
520
  def name; @td.name; end
@@ -373,47 +527,67 @@ module ActiveRecord
373
527
  @foreign_key_drops << name
374
528
  end
375
529
 
376
- def add_column(name, type, options)
530
+ def add_check_constraint(expression, options)
531
+ @check_constraint_adds << CheckConstraintDefinition.new(name, expression, options)
532
+ end
533
+
534
+ def drop_check_constraint(constraint_name)
535
+ @check_constraint_drops << constraint_name
536
+ end
537
+
538
+ def add_column(name, type, **options)
377
539
  name = name.to_s
378
540
  type = type.to_sym
379
- @adds << @td.new_column_definition(name, type, options)
541
+ @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, **options))
380
542
  end
381
543
  end
382
544
 
383
545
  # Represents an SQL table in an abstract way for updating a table.
384
- # Also see TableDefinition and SchemaStatements#create_table
546
+ # Also see TableDefinition and {connection.create_table}[rdoc-ref:SchemaStatements#create_table]
385
547
  #
386
548
  # Available transformations are:
387
549
  #
388
550
  # change_table :table do |t|
551
+ # t.primary_key
389
552
  # t.column
390
553
  # t.index
391
554
  # t.rename_index
392
555
  # t.timestamps
393
556
  # t.change
394
557
  # t.change_default
558
+ # t.change_null
395
559
  # t.rename
396
560
  # t.references
397
561
  # t.belongs_to
562
+ # t.check_constraint
398
563
  # t.string
399
564
  # t.text
400
565
  # t.integer
566
+ # t.bigint
401
567
  # t.float
402
568
  # t.decimal
569
+ # t.numeric
403
570
  # t.datetime
404
571
  # t.timestamp
405
572
  # t.time
406
573
  # t.date
407
574
  # t.binary
408
575
  # t.boolean
576
+ # t.foreign_key
577
+ # t.json
578
+ # t.virtual
409
579
  # t.remove
580
+ # t.remove_foreign_key
410
581
  # t.remove_references
411
582
  # t.remove_belongs_to
412
583
  # t.remove_index
584
+ # t.remove_check_constraint
413
585
  # t.remove_timestamps
414
586
  # end
415
587
  #
416
588
  class Table
589
+ include ColumnMethods
590
+
417
591
  attr_reader :name
418
592
 
419
593
  def initialize(table_name, base)
@@ -422,33 +596,46 @@ module ActiveRecord
422
596
  end
423
597
 
424
598
  # Adds a new column to the named table.
425
- # See TableDefinition#column for details of the options you can use.
426
599
  #
427
- # ====== Creating a simple column
428
600
  # t.column(:name, :string)
429
- def column(column_name, type, options = {})
430
- @base.add_column(name, column_name, type, options)
601
+ #
602
+ # See TableDefinition#column for details of the options you can use.
603
+ def column(column_name, type, index: nil, **options)
604
+ @base.add_column(name, column_name, type, **options)
605
+ if index
606
+ index_options = index.is_a?(Hash) ? index : {}
607
+ index(column_name, **index_options)
608
+ end
431
609
  end
432
610
 
433
- # Checks to see if a column exists. See SchemaStatements#column_exists?
434
- def column_exists?(column_name, type = nil, options = {})
435
- @base.column_exists?(name, column_name, type, options)
611
+ # Checks to see if a column exists.
612
+ #
613
+ # t.string(:name) unless t.column_exists?(:name, :string)
614
+ #
615
+ # See {connection.column_exists?}[rdoc-ref:SchemaStatements#column_exists?]
616
+ def column_exists?(column_name, type = nil, **options)
617
+ @base.column_exists?(name, column_name, type, **options)
436
618
  end
437
619
 
438
620
  # Adds a new index to the table. +column_name+ can be a single Symbol, or
439
- # an Array of Symbols. See SchemaStatements#add_index
621
+ # an Array of Symbols.
440
622
  #
441
- # ====== Creating a simple index
442
623
  # t.index(:name)
443
- # ====== Creating a unique index
444
624
  # t.index([:branch_id, :party_id], unique: true)
445
- # ====== Creating a named index
446
625
  # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
447
- def index(column_name, options = {})
448
- @base.add_index(name, column_name, options)
626
+ #
627
+ # See {connection.add_index}[rdoc-ref:SchemaStatements#add_index] for details of the options you can use.
628
+ def index(column_name, **options)
629
+ @base.add_index(name, column_name, **options)
449
630
  end
450
631
 
451
- # Checks to see if an index exists. See SchemaStatements#index_exists?
632
+ # Checks to see if an index exists.
633
+ #
634
+ # unless t.index_exists?(:branch_id)
635
+ # t.index(:branch_id)
636
+ # end
637
+ #
638
+ # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
452
639
  def index_exists?(column_name, options = {})
453
640
  @base.index_exists?(name, column_name, options)
454
641
  end
@@ -456,119 +643,164 @@ module ActiveRecord
456
643
  # Renames the given index on the table.
457
644
  #
458
645
  # t.rename_index(:user_id, :account_id)
646
+ #
647
+ # See {connection.rename_index}[rdoc-ref:SchemaStatements#rename_index]
459
648
  def rename_index(index_name, new_index_name)
460
649
  @base.rename_index(name, index_name, new_index_name)
461
650
  end
462
651
 
463
- # Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
652
+ # Adds timestamps (+created_at+ and +updated_at+) columns to the table.
653
+ #
654
+ # t.timestamps(null: false)
464
655
  #
465
- # t.timestamps null: false
466
- def timestamps(options = {})
467
- @base.add_timestamps(name, options)
656
+ # See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
657
+ def timestamps(**options)
658
+ @base.add_timestamps(name, **options)
468
659
  end
469
660
 
470
661
  # Changes the column's definition according to the new options.
471
- # See TableDefinition#column for details of the options you can use.
472
662
  #
473
663
  # t.change(:name, :string, limit: 80)
474
664
  # t.change(:description, :text)
475
- def change(column_name, type, options = {})
476
- @base.change_column(name, column_name, type, options)
665
+ #
666
+ # See TableDefinition#column for details of the options you can use.
667
+ def change(column_name, type, **options)
668
+ @base.change_column(name, column_name, type, **options)
477
669
  end
478
670
 
479
- # Sets a new default value for a column. See SchemaStatements#change_column_default
671
+ # Sets a new default value for a column.
480
672
  #
481
673
  # t.change_default(:qualification, 'new')
482
674
  # t.change_default(:authorized, 1)
483
- def change_default(column_name, default)
484
- @base.change_column_default(name, column_name, default)
675
+ # t.change_default(:status, from: nil, to: "draft")
676
+ #
677
+ # See {connection.change_column_default}[rdoc-ref:SchemaStatements#change_column_default]
678
+ def change_default(column_name, default_or_changes)
679
+ @base.change_column_default(name, column_name, default_or_changes)
680
+ end
681
+
682
+ # Sets or removes a NOT NULL constraint on a column.
683
+ #
684
+ # t.change_null(:qualification, true)
685
+ # t.change_null(:qualification, false, 0)
686
+ #
687
+ # See {connection.change_column_null}[rdoc-ref:SchemaStatements#change_column_null]
688
+ def change_null(column_name, null, default = nil)
689
+ @base.change_column_null(name, column_name, null, default)
485
690
  end
486
691
 
487
692
  # Removes the column(s) from the table definition.
488
693
  #
489
694
  # t.remove(:qualification)
490
695
  # t.remove(:qualification, :experience)
491
- def remove(*column_names)
492
- @base.remove_columns(name, *column_names)
696
+ #
697
+ # See {connection.remove_columns}[rdoc-ref:SchemaStatements#remove_columns]
698
+ def remove(*column_names, **options)
699
+ @base.remove_columns(name, *column_names, **options)
493
700
  end
494
701
 
495
702
  # Removes the given index from the table.
496
703
  #
497
- # ====== Remove the index_table_name_on_column in the table_name table
498
- # t.remove_index :column
499
- # ====== Remove the index named index_table_name_on_branch_id in the table_name table
500
- # t.remove_index column: :branch_id
501
- # ====== Remove the index named index_table_name_on_branch_id_and_party_id in the table_name table
502
- # t.remove_index column: [:branch_id, :party_id]
503
- # ====== Remove the index named by_branch_party in the table_name table
504
- # t.remove_index name: :by_branch_party
505
- def remove_index(options = {})
506
- @base.remove_index(name, options)
704
+ # t.remove_index(:branch_id)
705
+ # t.remove_index(column: [:branch_id, :party_id])
706
+ # t.remove_index(name: :by_branch_party)
707
+ # t.remove_index(:branch_id, name: :by_branch_party)
708
+ #
709
+ # See {connection.remove_index}[rdoc-ref:SchemaStatements#remove_index]
710
+ def remove_index(column_name = nil, **options)
711
+ @base.remove_index(name, column_name, **options)
507
712
  end
508
713
 
509
714
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
510
715
  #
511
716
  # t.remove_timestamps
512
- def remove_timestamps(options = {})
513
- @base.remove_timestamps(name, options)
717
+ #
718
+ # See {connection.remove_timestamps}[rdoc-ref:SchemaStatements#remove_timestamps]
719
+ def remove_timestamps(**options)
720
+ @base.remove_timestamps(name, **options)
514
721
  end
515
722
 
516
723
  # Renames a column.
517
724
  #
518
725
  # t.rename(:description, :name)
726
+ #
727
+ # See {connection.rename_column}[rdoc-ref:SchemaStatements#rename_column]
519
728
  def rename(column_name, new_column_name)
520
729
  @base.rename_column(name, column_name, new_column_name)
521
730
  end
522
731
 
523
- # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
524
- # <tt>references</tt> and <tt>belongs_to</tt> are acceptable. The reference column will be an +integer+
525
- # by default, the <tt>:type</tt> option can be used to specify a different type.
732
+ # Adds a reference.
526
733
  #
527
734
  # t.references(:user)
528
- # t.references(:user, type: "string")
529
- # t.belongs_to(:supplier, polymorphic: true)
735
+ # t.belongs_to(:supplier, foreign_key: true)
530
736
  #
531
- # See SchemaStatements#add_reference
532
- def references(*args)
533
- options = args.extract_options!
737
+ # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
738
+ def references(*args, **options)
534
739
  args.each do |ref_name|
535
- @base.add_reference(name, ref_name, options)
740
+ @base.add_reference(name, ref_name, **options)
536
741
  end
537
742
  end
538
743
  alias :belongs_to :references
539
744
 
540
745
  # Removes a reference. Optionally removes a +type+ column.
541
- # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
542
746
  #
543
747
  # t.remove_references(:user)
544
748
  # t.remove_belongs_to(:supplier, polymorphic: true)
545
749
  #
546
- # See SchemaStatements#remove_reference
547
- def remove_references(*args)
548
- options = args.extract_options!
750
+ # See {connection.remove_reference}[rdoc-ref:SchemaStatements#remove_reference]
751
+ def remove_references(*args, **options)
549
752
  args.each do |ref_name|
550
- @base.remove_reference(name, ref_name, options)
753
+ @base.remove_reference(name, ref_name, **options)
551
754
  end
552
755
  end
553
756
  alias :remove_belongs_to :remove_references
554
757
 
555
- # Adds a column or columns of a specified type
758
+ # Adds a foreign key to the table using a supplied table name.
556
759
  #
557
- # t.string(:goat)
558
- # t.string(:goat, :sheep)
559
- [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
560
- define_method column_type do |*args|
561
- options = args.extract_options!
562
- args.each do |column_name|
563
- @base.add_column(name, column_name, column_type, options)
564
- end
565
- end
760
+ # t.foreign_key(:authors)
761
+ # t.foreign_key(:authors, column: :author_id, primary_key: "id")
762
+ #
763
+ # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
764
+ def foreign_key(*args, **options)
765
+ @base.add_foreign_key(name, *args, **options)
566
766
  end
567
767
 
568
- private
569
- def native
570
- @base.native_database_types
571
- end
768
+ # Removes the given foreign key from the table.
769
+ #
770
+ # t.remove_foreign_key(:authors)
771
+ # t.remove_foreign_key(column: :author_id)
772
+ #
773
+ # See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
774
+ def remove_foreign_key(*args, **options)
775
+ @base.remove_foreign_key(name, *args, **options)
776
+ end
777
+
778
+ # Checks to see if a foreign key exists.
779
+ #
780
+ # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
781
+ #
782
+ # See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
783
+ def foreign_key_exists?(*args, **options)
784
+ @base.foreign_key_exists?(name, *args, **options)
785
+ end
786
+
787
+ # Adds a check constraint.
788
+ #
789
+ # t.check_constraint("price > 0", name: "price_check")
790
+ #
791
+ # See {connection.add_check_constraint}[rdoc-ref:SchemaStatements#add_check_constraint]
792
+ def check_constraint(*args)
793
+ @base.add_check_constraint(name, *args)
794
+ end
795
+
796
+ # Removes the given check constraint from the table.
797
+ #
798
+ # t.remove_check_constraint(name: "price_check")
799
+ #
800
+ # See {connection.remove_check_constraint}[rdoc-ref:SchemaStatements#remove_check_constraint]
801
+ def remove_check_constraint(*args)
802
+ @base.remove_check_constraint(name, *args)
803
+ end
572
804
  end
573
805
  end
574
806
  end