activerecord 5.0.7.2 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (363) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +829 -2015
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +11 -9
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -29
  8. data/lib/active_record/aggregations.rb +249 -247
  9. data/lib/active_record/association_relation.rb +30 -18
  10. data/lib/active_record/associations.rb +1714 -1596
  11. data/lib/active_record/associations/alias_tracker.rb +36 -42
  12. data/lib/active_record/associations/association.rb +143 -68
  13. data/lib/active_record/associations/association_scope.rb +98 -94
  14. data/lib/active_record/associations/belongs_to_association.rb +76 -46
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -28
  17. data/lib/active_record/associations/builder/belongs_to.rb +52 -60
  18. data/lib/active_record/associations/builder/collection_association.rb +12 -22
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
  20. data/lib/active_record/associations/builder/has_many.rb +10 -2
  21. data/lib/active_record/associations/builder/has_one.rb +35 -2
  22. data/lib/active_record/associations/builder/singular_association.rb +5 -1
  23. data/lib/active_record/associations/collection_association.rb +104 -259
  24. data/lib/active_record/associations/collection_proxy.rb +169 -125
  25. data/lib/active_record/associations/foreign_association.rb +22 -0
  26. data/lib/active_record/associations/has_many_association.rb +46 -31
  27. data/lib/active_record/associations/has_many_through_association.rb +66 -46
  28. data/lib/active_record/associations/has_one_association.rb +71 -52
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +169 -180
  31. data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +97 -104
  35. data/lib/active_record/associations/preloader/association.rb +109 -97
  36. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  37. data/lib/active_record/associations/singular_association.rb +12 -45
  38. data/lib/active_record/associations/through_association.rb +27 -15
  39. data/lib/active_record/attribute_assignment.rb +55 -60
  40. data/lib/active_record/attribute_methods.rb +111 -141
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
  42. data/lib/active_record/attribute_methods/dirty.rb +172 -112
  43. data/lib/active_record/attribute_methods/primary_key.rb +88 -91
  44. data/lib/active_record/attribute_methods/query.rb +6 -8
  45. data/lib/active_record/attribute_methods/read.rb +18 -50
  46. data/lib/active_record/attribute_methods/serialization.rb +38 -10
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
  48. data/lib/active_record/attribute_methods/write.rb +25 -32
  49. data/lib/active_record/attributes.rb +69 -31
  50. data/lib/active_record/autosave_association.rb +102 -66
  51. data/lib/active_record/base.rb +16 -25
  52. data/lib/active_record/callbacks.rb +202 -43
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -12
  55. data/lib/active_record/connection_adapters.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
  69. data/lib/active_record/connection_adapters/column.rb +55 -13
  70. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  71. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +79 -49
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -56
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +20 -12
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
  82. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  83. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
  85. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
  86. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  90. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -6
  93. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
  95. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  98. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  106. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
  107. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  109. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  110. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +98 -38
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +426 -324
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
  121. data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
  123. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  124. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -6
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +282 -290
  131. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  132. data/lib/active_record/connection_handling.rb +287 -45
  133. data/lib/active_record/core.rb +385 -181
  134. data/lib/active_record/counter_cache.rb +60 -28
  135. data/lib/active_record/database_configurations.rb +272 -0
  136. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  137. data/lib/active_record/database_configurations/database_config.rb +80 -0
  138. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  139. data/lib/active_record/database_configurations/url_config.rb +53 -0
  140. data/lib/active_record/delegated_type.rb +209 -0
  141. data/lib/active_record/destroy_association_async_job.rb +36 -0
  142. data/lib/active_record/dynamic_matchers.rb +87 -87
  143. data/lib/active_record/enum.rb +122 -47
  144. data/lib/active_record/errors.rb +153 -22
  145. data/lib/active_record/explain.rb +13 -8
  146. data/lib/active_record/explain_registry.rb +3 -1
  147. data/lib/active_record/explain_subscriber.rb +9 -4
  148. data/lib/active_record/fixture_set/file.rb +20 -22
  149. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  150. data/lib/active_record/fixture_set/render_context.rb +17 -0
  151. data/lib/active_record/fixture_set/table_row.rb +152 -0
  152. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  153. data/lib/active_record/fixtures.rb +246 -507
  154. data/lib/active_record/gem_version.rb +6 -4
  155. data/lib/active_record/inheritance.rb +168 -95
  156. data/lib/active_record/insert_all.rb +208 -0
  157. data/lib/active_record/integration.rb +114 -25
  158. data/lib/active_record/internal_metadata.rb +30 -24
  159. data/lib/active_record/legacy_yaml_adapter.rb +11 -5
  160. data/lib/active_record/locking/optimistic.rb +81 -85
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +68 -31
  163. data/lib/active_record/middleware/database_selector.rb +77 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  166. data/lib/active_record/migration.rb +439 -342
  167. data/lib/active_record/migration/command_recorder.rb +152 -98
  168. data/lib/active_record/migration/compatibility.rb +229 -60
  169. data/lib/active_record/migration/join_table.rb +8 -7
  170. data/lib/active_record/model_schema.rb +230 -122
  171. data/lib/active_record/nested_attributes.rb +213 -203
  172. data/lib/active_record/no_touching.rb +11 -2
  173. data/lib/active_record/null_relation.rb +12 -34
  174. data/lib/active_record/persistence.rb +471 -97
  175. data/lib/active_record/query_cache.rb +23 -12
  176. data/lib/active_record/querying.rb +43 -25
  177. data/lib/active_record/railtie.rb +155 -43
  178. data/lib/active_record/railties/console_sandbox.rb +2 -0
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +507 -195
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +245 -269
  183. data/lib/active_record/relation.rb +475 -324
  184. data/lib/active_record/relation/batches.rb +125 -72
  185. data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
  186. data/lib/active_record/relation/calculations.rb +267 -171
  187. data/lib/active_record/relation/delegation.rb +73 -69
  188. data/lib/active_record/relation/finder_methods.rb +238 -248
  189. data/lib/active_record/relation/from_clause.rb +7 -9
  190. data/lib/active_record/relation/merger.rb +95 -77
  191. data/lib/active_record/relation/predicate_builder.rb +109 -110
  192. data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
  193. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  194. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  195. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
  196. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  197. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  198. data/lib/active_record/relation/query_attribute.rb +33 -2
  199. data/lib/active_record/relation/query_methods.rb +654 -374
  200. data/lib/active_record/relation/record_fetch_warning.rb +8 -6
  201. data/lib/active_record/relation/spawn_methods.rb +15 -14
  202. data/lib/active_record/relation/where_clause.rb +171 -109
  203. data/lib/active_record/result.rb +88 -51
  204. data/lib/active_record/runtime_registry.rb +5 -3
  205. data/lib/active_record/sanitization.rb +73 -100
  206. data/lib/active_record/schema.rb +7 -14
  207. data/lib/active_record/schema_dumper.rb +101 -69
  208. data/lib/active_record/schema_migration.rb +16 -12
  209. data/lib/active_record/scoping.rb +20 -20
  210. data/lib/active_record/scoping/default.rb +92 -95
  211. data/lib/active_record/scoping/named.rb +39 -30
  212. data/lib/active_record/secure_token.rb +19 -9
  213. data/lib/active_record/serialization.rb +7 -3
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +80 -29
  216. data/lib/active_record/store.rb +122 -42
  217. data/lib/active_record/suppressor.rb +6 -3
  218. data/lib/active_record/table_metadata.rb +51 -39
  219. data/lib/active_record/tasks/database_tasks.rb +332 -115
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +246 -0
  225. data/lib/active_record/timestamp.rb +70 -38
  226. data/lib/active_record/touch_later.rb +26 -24
  227. data/lib/active_record/transactions.rb +121 -184
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type.rb +29 -17
  230. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  231. data/lib/active_record/type/date.rb +2 -0
  232. data/lib/active_record/type/date_time.rb +2 -0
  233. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  234. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  235. data/lib/active_record/type/internal/timezone.rb +2 -0
  236. data/lib/active_record/type/json.rb +30 -0
  237. data/lib/active_record/type/serialized.rb +20 -9
  238. data/lib/active_record/type/text.rb +11 -0
  239. data/lib/active_record/type/time.rb +12 -1
  240. data/lib/active_record/type/type_map.rb +14 -17
  241. data/lib/active_record/type/unsigned_integer.rb +16 -0
  242. data/lib/active_record/type_caster.rb +4 -2
  243. data/lib/active_record/type_caster/connection.rb +17 -13
  244. data/lib/active_record/type_caster/map.rb +10 -6
  245. data/lib/active_record/validations.rb +8 -5
  246. data/lib/active_record/validations/absence.rb +2 -0
  247. data/lib/active_record/validations/associated.rb +4 -3
  248. data/lib/active_record/validations/length.rb +2 -0
  249. data/lib/active_record/validations/numericality.rb +35 -0
  250. data/lib/active_record/validations/presence.rb +4 -2
  251. data/lib/active_record/validations/uniqueness.rb +52 -45
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/arel.rb +54 -0
  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.rb +70 -0
  269. data/lib/arel/nodes/and.rb +32 -0
  270. data/lib/arel/nodes/ascending.rb +23 -0
  271. data/lib/arel/nodes/binary.rb +126 -0
  272. data/lib/arel/nodes/bind_param.rb +44 -0
  273. data/lib/arel/nodes/case.rb +55 -0
  274. data/lib/arel/nodes/casted.rb +62 -0
  275. data/lib/arel/nodes/comment.rb +29 -0
  276. data/lib/arel/nodes/count.rb +12 -0
  277. data/lib/arel/nodes/delete_statement.rb +45 -0
  278. data/lib/arel/nodes/descending.rb +23 -0
  279. data/lib/arel/nodes/equality.rb +15 -0
  280. data/lib/arel/nodes/extract.rb +24 -0
  281. data/lib/arel/nodes/false.rb +16 -0
  282. data/lib/arel/nodes/full_outer_join.rb +8 -0
  283. data/lib/arel/nodes/function.rb +44 -0
  284. data/lib/arel/nodes/grouping.rb +11 -0
  285. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  286. data/lib/arel/nodes/in.rb +15 -0
  287. data/lib/arel/nodes/infix_operation.rb +92 -0
  288. data/lib/arel/nodes/inner_join.rb +8 -0
  289. data/lib/arel/nodes/insert_statement.rb +37 -0
  290. data/lib/arel/nodes/join_source.rb +20 -0
  291. data/lib/arel/nodes/matches.rb +18 -0
  292. data/lib/arel/nodes/named_function.rb +23 -0
  293. data/lib/arel/nodes/node.rb +51 -0
  294. data/lib/arel/nodes/node_expression.rb +13 -0
  295. data/lib/arel/nodes/ordering.rb +27 -0
  296. data/lib/arel/nodes/outer_join.rb +8 -0
  297. data/lib/arel/nodes/over.rb +15 -0
  298. data/lib/arel/nodes/regexp.rb +16 -0
  299. data/lib/arel/nodes/right_outer_join.rb +8 -0
  300. data/lib/arel/nodes/select_core.rb +67 -0
  301. data/lib/arel/nodes/select_statement.rb +41 -0
  302. data/lib/arel/nodes/sql_literal.rb +19 -0
  303. data/lib/arel/nodes/string_join.rb +11 -0
  304. data/lib/arel/nodes/table_alias.rb +31 -0
  305. data/lib/arel/nodes/terminal.rb +16 -0
  306. data/lib/arel/nodes/true.rb +16 -0
  307. data/lib/arel/nodes/unary.rb +44 -0
  308. data/lib/arel/nodes/unary_operation.rb +20 -0
  309. data/lib/arel/nodes/unqualified_column.rb +22 -0
  310. data/lib/arel/nodes/update_statement.rb +41 -0
  311. data/lib/arel/nodes/values_list.rb +9 -0
  312. data/lib/arel/nodes/window.rb +126 -0
  313. data/lib/arel/nodes/with.rb +11 -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.rb +13 -0
  321. data/lib/arel/visitors/dot.rb +308 -0
  322. data/lib/arel/visitors/mysql.rb +93 -0
  323. data/lib/arel/visitors/postgresql.rb +120 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +899 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/rails/generators/active_record.rb +7 -5
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration.rb +22 -3
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
  333. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
  334. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
  335. data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
  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 → model.rb.tt} +10 -1
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. metadata +141 -57
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  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 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute.rb +0 -213
  348. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  349. data/lib/active_record/attribute_decorators.rb +0 -67
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
  355. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
  356. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  359. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -17
  360. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  361. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  362. data/lib/active_record/relation/where_clause_factory.rb +0 -38
  363. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module Savepoints
@@ -6,15 +8,15 @@ module ActiveRecord
6
8
  end
7
9
 
8
10
  def create_savepoint(name = current_savepoint_name)
9
- execute("SAVEPOINT #{name}")
11
+ execute("SAVEPOINT #{name}", "TRANSACTION")
10
12
  end
11
13
 
12
14
  def exec_rollback_to_savepoint(name = current_savepoint_name)
13
- execute("ROLLBACK TO SAVEPOINT #{name}")
15
+ execute("ROLLBACK TO SAVEPOINT #{name}", "TRANSACTION")
14
16
  end
15
17
 
16
18
  def release_savepoint(name = current_savepoint_name)
17
- execute("RELEASE SAVEPOINT #{name}")
19
+ execute("RELEASE SAVEPOINT #{name}", "TRANSACTION")
18
20
  end
19
21
  end
20
22
  end
@@ -1,147 +1,189 @@
1
- require 'active_support/core_ext/string/strip'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
- class AbstractAdapter
6
- class SchemaCreation # :nodoc:
7
- def initialize(conn)
8
- @conn = conn
9
- @cache = {}
5
+ class SchemaCreation # :nodoc:
6
+ def initialize(conn)
7
+ @conn = conn
8
+ @cache = {}
9
+ end
10
+
11
+ def accept(o)
12
+ m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
13
+ send m, o
14
+ end
15
+
16
+ delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
17
+ :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options,
18
+ :quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?, :check_constraint_options,
19
+ to: :@conn, private: true
20
+
21
+ private
22
+ def visit_AlterTable(o)
23
+ sql = +"ALTER TABLE #{quote_table_name(o.name)} "
24
+ sql << o.adds.map { |col| accept col }.join(" ")
25
+ sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
26
+ sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
27
+ sql << o.check_constraint_adds.map { |con| visit_AddCheckConstraint con }.join(" ")
28
+ sql << o.check_constraint_drops.map { |con| visit_DropCheckConstraint con }.join(" ")
29
+ end
30
+
31
+ def visit_ColumnDefinition(o)
32
+ o.sql_type = type_to_sql(o.type, **o.options)
33
+ column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
34
+ add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
35
+ column_sql
10
36
  end
11
37
 
12
- def accept(o)
13
- m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
14
- send m, o
38
+ def visit_AddColumnDefinition(o)
39
+ +"ADD #{accept(o.column)}"
15
40
  end
16
41
 
17
- delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
18
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options, to: :@conn
19
- private :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
20
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options
42
+ def visit_TableDefinition(o)
43
+ create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
44
+ create_sql << "IF NOT EXISTS " if o.if_not_exists
45
+ create_sql << "#{quote_table_name(o.name)} "
21
46
 
22
- private
47
+ statements = o.columns.map { |c| accept c }
48
+ statements << accept(o.primary_keys) if o.primary_keys
23
49
 
24
- def visit_AlterTable(o)
25
- sql = "ALTER TABLE #{quote_table_name(o.name)} "
26
- sql << o.adds.map { |col| accept col }.join(' ')
27
- sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ')
28
- sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ')
50
+ if supports_indexes_in_create?
51
+ statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
29
52
  end
30
53
 
31
- def visit_ColumnDefinition(o)
32
- o.sql_type ||= type_to_sql(o.type, o.limit, o.precision, o.scale)
33
- column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
34
- add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
35
- column_sql
54
+ if supports_foreign_keys?
55
+ statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
36
56
  end
37
57
 
38
- def visit_AddColumnDefinition(o)
39
- "ADD #{accept(o.column)}"
58
+ if supports_check_constraints?
59
+ statements.concat(o.check_constraints.map { |expression, options| check_constraint_in_create(o.name, expression, options) })
40
60
  end
41
61
 
42
- def visit_TableDefinition(o)
43
- create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
62
+ create_sql << "(#{statements.join(', ')})" if statements.present?
63
+ add_table_options!(create_sql, o)
64
+ create_sql << " AS #{to_sql(o.as)}" if o.as
65
+ create_sql
66
+ end
44
67
 
45
- statements = o.columns.map { |c| accept c }
46
- statements << accept(o.primary_keys) if o.primary_keys
68
+ def visit_PrimaryKeyDefinition(o)
69
+ "PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})"
70
+ end
47
71
 
48
- if supports_indexes_in_create?
49
- statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
50
- end
72
+ def visit_ForeignKeyDefinition(o)
73
+ sql = +<<~SQL
74
+ CONSTRAINT #{quote_column_name(o.name)}
75
+ FOREIGN KEY (#{quote_column_name(o.column)})
76
+ REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
77
+ SQL
78
+ sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
79
+ sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
80
+ sql
81
+ end
51
82
 
52
- if supports_foreign_keys?
53
- statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
54
- end
83
+ def visit_AddForeignKey(o)
84
+ "ADD #{accept(o)}"
85
+ end
55
86
 
56
- create_sql << "(#{statements.join(', ')})" if statements.present?
57
- add_table_options!(create_sql, table_options(o))
58
- create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
59
- create_sql
60
- end
87
+ def visit_DropForeignKey(name)
88
+ "DROP CONSTRAINT #{quote_column_name(name)}"
89
+ end
61
90
 
62
- def visit_PrimaryKeyDefinition(o)
63
- "PRIMARY KEY (#{o.name.join(', ')})"
64
- end
91
+ def visit_CreateIndexDefinition(o)
92
+ index = o.index
93
+
94
+ sql = ["CREATE"]
95
+ sql << "UNIQUE" if index.unique
96
+ sql << "INDEX"
97
+ sql << "IF NOT EXISTS" if o.if_not_exists
98
+ sql << o.algorithm if o.algorithm
99
+ sql << index.type if index.type
100
+ sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
101
+ sql << "USING #{index.using}" if supports_index_using? && index.using
102
+ sql << "(#{quoted_columns(index)})"
103
+ sql << "WHERE #{index.where}" if supports_partial_index? && index.where
104
+
105
+ sql.join(" ")
106
+ end
65
107
 
66
- def visit_ForeignKeyDefinition(o)
67
- sql = <<-SQL.strip_heredoc
68
- CONSTRAINT #{quote_column_name(o.name)}
69
- FOREIGN KEY (#{quote_column_name(o.column)})
70
- REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
71
- SQL
72
- sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
73
- sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
74
- sql
75
- end
108
+ def visit_CheckConstraintDefinition(o)
109
+ "CONSTRAINT #{o.name} CHECK (#{o.expression})"
110
+ end
76
111
 
77
- def visit_AddForeignKey(o)
78
- "ADD #{accept(o)}"
79
- end
112
+ def visit_AddCheckConstraint(o)
113
+ "ADD #{accept(o)}"
114
+ end
80
115
 
81
- def visit_DropForeignKey(name)
82
- "DROP CONSTRAINT #{quote_column_name(name)}"
83
- end
116
+ def visit_DropCheckConstraint(name)
117
+ "DROP CONSTRAINT #{quote_column_name(name)}"
118
+ end
84
119
 
85
- def table_options(o)
86
- table_options = {}
87
- table_options[:comment] = o.comment
88
- table_options[:options] = o.options
89
- table_options
90
- end
120
+ def quoted_columns(o)
121
+ String === o.columns ? o.columns : quoted_columns_for_index(o.columns, o.column_options)
122
+ end
91
123
 
92
- def add_table_options!(create_sql, options)
93
- if options_sql = options[:options]
94
- create_sql << " #{options_sql}"
95
- end
96
- end
124
+ def supports_index_using?
125
+ true
126
+ end
97
127
 
98
- def column_options(o)
99
- column_options = {}
100
- column_options[:null] = o.null unless o.null.nil?
101
- column_options[:default] = o.default unless o.default.nil?
102
- column_options[:column] = o
103
- column_options[:first] = o.first
104
- column_options[:after] = o.after
105
- column_options[:auto_increment] = o.auto_increment
106
- column_options[:primary_key] = o.primary_key
107
- column_options[:collation] = o.collation
108
- column_options[:comment] = o.comment
109
- column_options
110
- end
128
+ def add_table_options!(create_sql, o)
129
+ create_sql << " #{o.options}" if o.options
130
+ create_sql
131
+ end
111
132
 
112
- def add_column_options!(sql, options)
113
- sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
114
- # must explicitly check for :null to allow change_column to work on migrations
115
- if options[:null] == false
116
- sql << " NOT NULL"
117
- end
118
- if options[:auto_increment] == true
119
- sql << " AUTO_INCREMENT"
120
- end
121
- if options[:primary_key] == true
122
- sql << " PRIMARY KEY"
123
- end
124
- sql
125
- end
133
+ def column_options(o)
134
+ o.options.merge(column: o)
135
+ end
126
136
 
127
- def foreign_key_in_create(from_table, to_table, options)
128
- options = foreign_key_options(from_table, to_table, options)
129
- accept ForeignKeyDefinition.new(from_table, to_table, options)
137
+ def add_column_options!(sql, options)
138
+ sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
139
+ # must explicitly check for :null to allow change_column to work on migrations
140
+ if options[:null] == false
141
+ sql << " NOT NULL"
142
+ end
143
+ if options[:auto_increment] == true
144
+ sql << " AUTO_INCREMENT"
130
145
  end
146
+ if options[:primary_key] == true
147
+ sql << " PRIMARY KEY"
148
+ end
149
+ sql
150
+ end
131
151
 
132
- def action_sql(action, dependency)
133
- case dependency
134
- when :nullify then "ON #{action} SET NULL"
135
- when :cascade then "ON #{action} CASCADE"
136
- when :restrict then "ON #{action} RESTRICT"
137
- else
138
- raise ArgumentError, <<-MSG.strip_heredoc
139
- '#{dependency}' is not supported for :on_update or :on_delete.
140
- Supported values are: :nullify, :cascade, :restrict
141
- MSG
142
- end
152
+ def to_sql(sql)
153
+ sql = sql.to_sql if sql.respond_to?(:to_sql)
154
+ sql
155
+ end
156
+
157
+ # Returns any SQL string to go between CREATE and TABLE. May be nil.
158
+ def table_modifier_in_create(o)
159
+ " TEMPORARY" if o.temporary
160
+ end
161
+
162
+ def foreign_key_in_create(from_table, to_table, options)
163
+ prefix = ActiveRecord::Base.table_name_prefix
164
+ suffix = ActiveRecord::Base.table_name_suffix
165
+ to_table = "#{prefix}#{to_table}#{suffix}"
166
+ options = foreign_key_options(from_table, to_table, options)
167
+ accept ForeignKeyDefinition.new(from_table, to_table, options)
168
+ end
169
+
170
+ def check_constraint_in_create(table_name, expression, options)
171
+ options = check_constraint_options(table_name, expression, options)
172
+ accept CheckConstraintDefinition.new(table_name, expression, options)
173
+ end
174
+
175
+ def action_sql(action, dependency)
176
+ case dependency
177
+ when :nullify then "ON #{action} SET NULL"
178
+ when :cascade then "ON #{action} CASCADE"
179
+ when :restrict then "ON #{action} RESTRICT"
180
+ else
181
+ raise ArgumentError, <<~MSG
182
+ '#{dependency}' is not supported for :on_update or :on_delete.
183
+ Supported values are: :nullify, :cascade, :restrict
184
+ MSG
143
185
  end
144
- end
186
+ end
145
187
  end
146
188
  end
147
189
  end
@@ -1,32 +1,87 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters #:nodoc:
3
5
  # Abstract representation of an index definition on a table. Instances of
4
6
  # this type are typically created and returned by methods in database
5
- # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
6
- class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using, :comment) #: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
7
52
  end
8
53
 
9
54
  # Abstract representation of a column definition. Instances of this type
10
55
  # are typically created by methods in TableDefinition, and added to the
11
56
  # +columns+ attribute of said TableDefinition object, in order to be used
12
57
  # for generating a number of table creation or table changing SQL statements.
13
- class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :collation, :sql_type, :comment) #:nodoc:
14
-
58
+ ColumnDefinition = Struct.new(:name, :type, :options, :sql_type) do # :nodoc:
15
59
  def primary_key?
16
- primary_key || type.to_sym == :primary_key
60
+ options[:primary_key]
17
61
  end
18
- end
19
62
 
20
- class AddColumnDefinition < Struct.new(:column) # :nodoc:
21
- end
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
22
68
 
23
- class ChangeColumnDefinition < Struct.new(:column, :name) #:nodoc:
69
+ def #{option_name}=(value)
70
+ options[:#{option_name}] = value
71
+ end
72
+ CODE
73
+ end
24
74
  end
25
75
 
26
- class PrimaryKeyDefinition < Struct.new(:name) # :nodoc:
27
- end
76
+ AddColumnDefinition = Struct.new(:column) # :nodoc:
77
+
78
+ ChangeColumnDefinition = Struct.new(:column, :name) #:nodoc:
79
+
80
+ CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists) # :nodoc:
81
+
82
+ PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
28
83
 
29
- class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
84
+ ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do #:nodoc:
30
85
  def name
31
86
  options[:name]
32
87
  end
@@ -51,18 +106,39 @@ module ActiveRecord
51
106
  options[:primary_key] != default_primary_key
52
107
  end
53
108
 
54
- def defined_for?(to_table_ord = nil, to_table: nil, **options)
55
- if to_table_ord
56
- self.to_table == to_table_ord.to_s
57
- else
58
- (to_table.nil? || to_table.to_s == self.to_table) &&
59
- options.all? { |k, v| self.options[k].to_s == v.to_s }
60
- end
109
+ def validate?
110
+ options.fetch(:validate, true)
111
+ end
112
+ alias validated? validate?
113
+
114
+ def export_name_on_schema_dump?
115
+ !ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
116
+ end
117
+
118
+ def defined_for?(to_table: nil, validate: nil, **options)
119
+ (to_table.nil? || to_table.to_s == self.to_table) &&
120
+ (validate.nil? || validate == options.fetch(:validate, validate)) &&
121
+ options.all? { |k, v| self.options[k].to_s == v.to_s }
61
122
  end
62
123
 
63
124
  private
64
- def default_primary_key
65
- "id"
125
+ def default_primary_key
126
+ "id"
127
+ end
128
+ end
129
+
130
+ CheckConstraintDefinition = Struct.new(:table_name, :expression, :options) do
131
+ def name
132
+ options[:name]
133
+ end
134
+
135
+ def validate?
136
+ options.fetch(:validate, true)
137
+ end
138
+ alias validated? validate?
139
+
140
+ def export_name_on_schema_dump?
141
+ !ActiveRecord::SchemaDumper.chk_ignore_pattern.match?(name) if name
66
142
  end
67
143
  end
68
144
 
@@ -72,7 +148,7 @@ module ActiveRecord
72
148
  polymorphic: false,
73
149
  index: true,
74
150
  foreign_key: false,
75
- type: :integer,
151
+ type: :bigint,
76
152
  **options
77
153
  )
78
154
  @name = name
@@ -88,98 +164,107 @@ module ActiveRecord
88
164
  end
89
165
 
90
166
  def add_to(table)
91
- columns.each do |column_options|
92
- table.column(*column_options)
167
+ columns.each do |name, type, options|
168
+ table.column(name, type, **options)
93
169
  end
94
170
 
95
171
  if index
96
- table.index(column_names, index_options)
172
+ table.index(column_names, **index_options(table.name))
97
173
  end
98
174
 
99
175
  if foreign_key
100
- table.foreign_key(foreign_table_name, foreign_key_options)
176
+ table.foreign_key(foreign_table_name, **foreign_key_options)
101
177
  end
102
178
  end
103
179
 
104
- protected
105
-
106
- attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
107
-
108
180
  private
181
+ attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
109
182
 
110
- def as_options(value)
111
- value.is_a?(Hash) ? value : {}
112
- end
183
+ def as_options(value)
184
+ value.is_a?(Hash) ? value : {}
185
+ end
113
186
 
114
- def polymorphic_options
115
- as_options(polymorphic).merge(null: options[:null])
116
- end
187
+ def polymorphic_options
188
+ as_options(polymorphic).merge(options.slice(:null, :first, :after))
189
+ end
117
190
 
118
- def index_options
119
- as_options(index)
120
- end
191
+ def polymorphic_index_name(table_name)
192
+ "index_#{table_name}_on_#{name}"
193
+ end
121
194
 
122
- def foreign_key_options
123
- as_options(foreign_key).merge(column: column_name)
124
- end
195
+ def index_options(table_name)
196
+ index_options = as_options(index)
197
+ index_options[:name] ||= polymorphic_index_name(table_name) if polymorphic
198
+ index_options
199
+ end
125
200
 
126
- def columns
127
- result = [[column_name, type, options]]
128
- if polymorphic
129
- result.unshift(["#{name}_type", :string, polymorphic_options])
201
+ def foreign_key_options
202
+ as_options(foreign_key).merge(column: column_name)
130
203
  end
131
- result
132
- end
133
204
 
134
- def column_name
135
- "#{name}_id"
136
- end
205
+ def columns
206
+ result = [[column_name, type, options]]
207
+ if polymorphic
208
+ result.unshift(["#{name}_type", :string, polymorphic_options])
209
+ end
210
+ result
211
+ end
137
212
 
138
- def column_names
139
- columns.map(&:first)
140
- end
213
+ def column_name
214
+ "#{name}_id"
215
+ end
141
216
 
142
- def foreign_table_name
143
- foreign_key_options.fetch(:to_table) do
144
- Base.pluralize_table_names ? name.to_s.pluralize : name
217
+ def column_names
218
+ columns.map(&:first)
219
+ end
220
+
221
+ def foreign_table_name
222
+ foreign_key_options.fetch(:to_table) do
223
+ Base.pluralize_table_names ? name.to_s.pluralize : name
224
+ end
145
225
  end
146
- end
147
226
  end
148
227
 
149
228
  module ColumnMethods
229
+ extend ActiveSupport::Concern
230
+
150
231
  # Appends a primary key definition to the table definition.
151
232
  # Can be called multiple times, but this is probably not a good idea.
152
233
  def primary_key(name, type = :primary_key, **options)
153
- column(name, type, options.merge(primary_key: true))
234
+ column(name, type, **options.merge(primary_key: true))
154
235
  end
155
236
 
237
+ ##
238
+ # :method: column
239
+ # :call-seq: column(name, type, **options)
240
+ #
156
241
  # Appends a column or columns of a specified type.
157
242
  #
158
243
  # t.string(:goat)
159
244
  # t.string(:goat, :sheep)
160
245
  #
161
246
  # See TableDefinition#column
162
- [
163
- :bigint,
164
- :binary,
165
- :boolean,
166
- :date,
167
- :datetime,
168
- :decimal,
169
- :float,
170
- :integer,
171
- :string,
172
- :text,
173
- :time,
174
- :timestamp,
175
- ].each do |column_type|
176
- module_eval <<-CODE, __FILE__, __LINE__ + 1
177
- def #{column_type}(*args, **options)
178
- args.each { |name| column(name, :#{column_type}, options) }
247
+
248
+ included do
249
+ define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
250
+ :float, :integer, :json, :string, :text, :time, :timestamp, :virtual
251
+
252
+ alias :numeric :decimal
253
+ end
254
+
255
+ class_methods do
256
+ def define_column_methods(*column_types) # :nodoc:
257
+ column_types.each do |column_type|
258
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
259
+ def #{column_type}(*names, **options)
260
+ raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
261
+ names.each { |name| column(name, :#{column_type}, **options) }
262
+ end
263
+ RUBY
179
264
  end
180
- CODE
265
+ end
266
+ private :define_column_methods
181
267
  end
182
- alias_method :numeric, :decimal
183
268
  end
184
269
 
185
270
  # Represents the schema of an SQL table in an abstract way. This class
@@ -188,7 +273,7 @@ module ActiveRecord
188
273
  # Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
189
274
  # is actually of this type:
190
275
  #
191
- # class SomeMigration < ActiveRecord::Migration[5.0]
276
+ # class SomeMigration < ActiveRecord::Migration[6.0]
192
277
  # def up
193
278
  # create_table :foo do |t|
194
279
  # puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
@@ -203,15 +288,26 @@ module ActiveRecord
203
288
  class TableDefinition
204
289
  include ColumnMethods
205
290
 
206
- attr_accessor :indexes
207
- attr_reader :name, :temporary, :options, :as, :foreign_keys, :comment
291
+ attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys, :check_constraints
208
292
 
209
- def initialize(name, temporary = false, options = nil, as = nil, comment: nil)
293
+ def initialize(
294
+ conn,
295
+ name,
296
+ temporary: false,
297
+ if_not_exists: false,
298
+ options: nil,
299
+ as: nil,
300
+ comment: nil,
301
+ **
302
+ )
303
+ @conn = conn
210
304
  @columns_hash = {}
211
305
  @indexes = []
212
306
  @foreign_keys = []
213
307
  @primary_keys = nil
308
+ @check_constraints = []
214
309
  @temporary = temporary
310
+ @if_not_exists = if_not_exists
215
311
  @options = options
216
312
  @as = as
217
313
  @name = name
@@ -295,21 +391,28 @@ module ActiveRecord
295
391
  #
296
392
  # create_table :taggings do |t|
297
393
  # t.references :tag, index: { name: 'index_taggings_on_tag_id' }
298
- # t.references :tagger, polymorphic: true, index: true
299
- # t.references :taggable, polymorphic: { default: 'Photo' }
394
+ # t.references :tagger, polymorphic: true
395
+ # t.references :taggable, polymorphic: { default: 'Photo' }, index: false
300
396
  # end
301
- def column(name, type, options = {})
397
+ def column(name, type, index: nil, **options)
302
398
  name = name.to_s
303
399
  type = type.to_sym if type
304
- options = options.dup
305
400
 
306
- if @columns_hash[name] && @columns_hash[name].primary_key?
307
- raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
401
+ if @columns_hash[name]
402
+ if @columns_hash[name].primary_key?
403
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
404
+ else
405
+ raise ArgumentError, "you can't define an already defined column '#{name}'."
406
+ end
407
+ end
408
+
409
+ @columns_hash[name] = new_column_definition(name, type, **options)
410
+
411
+ if index
412
+ index_options = index.is_a?(Hash) ? index : {}
413
+ index(name, **index_options)
308
414
  end
309
415
 
310
- index_options = options.delete(:index)
311
- index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
312
- @columns_hash[name] = new_column_definition(name, type, options)
313
416
  self
314
417
  end
315
418
 
@@ -323,81 +426,87 @@ module ActiveRecord
323
426
  # This is primarily used to track indexes that need to be created after the table
324
427
  #
325
428
  # index(:account_id, name: 'index_projects_on_account_id')
326
- def index(column_name, options = {})
429
+ def index(column_name, **options)
327
430
  indexes << [column_name, options]
328
431
  end
329
432
 
330
- def foreign_key(table_name, options = {}) # :nodoc:
331
- table_name_prefix = ActiveRecord::Base.table_name_prefix
332
- table_name_suffix = ActiveRecord::Base.table_name_suffix
333
- table_name = "#{table_name_prefix}#{table_name}#{table_name_suffix}"
334
- foreign_keys.push([table_name, options])
433
+ def foreign_key(table_name, **options) # :nodoc:
434
+ foreign_keys << [table_name, options]
435
+ end
436
+
437
+ def check_constraint(expression, **options)
438
+ check_constraints << [expression, options]
335
439
  end
336
440
 
337
441
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
338
442
  # <tt>:updated_at</tt> to the table. See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
339
443
  #
340
444
  # t.timestamps null: false
341
- def timestamps(*args)
342
- options = args.extract_options!
343
-
445
+ def timestamps(**options)
344
446
  options[:null] = false if options[:null].nil?
345
447
 
346
- column(:created_at, :datetime, options)
347
- column(:updated_at, :datetime, options)
448
+ if !options.key?(:precision) && @conn.supports_datetime_with_precision?
449
+ options[:precision] = 6
450
+ end
451
+
452
+ column(:created_at, :datetime, **options)
453
+ column(:updated_at, :datetime, **options)
348
454
  end
349
455
 
350
456
  # Adds a reference.
351
457
  #
352
458
  # t.references(:user)
353
459
  # t.belongs_to(:supplier, foreign_key: true)
460
+ # t.belongs_to(:supplier, foreign_key: true, type: :integer)
354
461
  #
355
462
  # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
356
463
  def references(*args, **options)
357
- args.each do |col|
358
- ReferenceDefinition.new(col, **options).add_to(self)
464
+ args.each do |ref_name|
465
+ ReferenceDefinition.new(ref_name, **options).add_to(self)
359
466
  end
360
467
  end
361
468
  alias :belongs_to :references
362
469
 
363
- def new_column_definition(name, type, options) # :nodoc:
470
+ def new_column_definition(name, type, **options) # :nodoc:
471
+ if integer_like_primary_key?(type, options)
472
+ type = integer_like_primary_key_type(type, options)
473
+ end
364
474
  type = aliased_types(type.to_s, type)
365
- column = create_column_definition name, type
366
-
367
- column.limit = options[:limit]
368
- column.precision = options[:precision]
369
- column.scale = options[:scale]
370
- column.default = options[:default]
371
- column.null = options[:null]
372
- column.first = options[:first]
373
- column.after = options[:after]
374
- column.auto_increment = options[:auto_increment]
375
- column.primary_key = type == :primary_key || options[:primary_key]
376
- column.collation = options[:collation]
377
- column.comment = options[:comment]
378
- column
475
+ options[:primary_key] ||= type == :primary_key
476
+ options[:null] = false if options[:primary_key]
477
+ create_column_definition(name, type, options)
379
478
  end
380
479
 
381
480
  private
382
- def create_column_definition(name, type)
383
- ColumnDefinition.new name, type
384
- end
481
+ def create_column_definition(name, type, options)
482
+ ColumnDefinition.new(name, type, options)
483
+ end
385
484
 
386
- def aliased_types(name, fallback)
387
- 'timestamp' == name ? :datetime : fallback
388
- end
485
+ def aliased_types(name, fallback)
486
+ "timestamp" == name ? :datetime : fallback
487
+ end
488
+
489
+ def integer_like_primary_key?(type, options)
490
+ options[:primary_key] && [:integer, :bigint].include?(type) && !options.key?(:default)
491
+ end
492
+
493
+ def integer_like_primary_key_type(type, options)
494
+ type
495
+ end
389
496
  end
390
497
 
391
498
  class AlterTable # :nodoc:
392
499
  attr_reader :adds
393
- attr_reader :foreign_key_adds
394
- attr_reader :foreign_key_drops
500
+ attr_reader :foreign_key_adds, :foreign_key_drops
501
+ attr_reader :check_constraint_adds, :check_constraint_drops
395
502
 
396
503
  def initialize(td)
397
504
  @td = td
398
505
  @adds = []
399
506
  @foreign_key_adds = []
400
507
  @foreign_key_drops = []
508
+ @check_constraint_adds = []
509
+ @check_constraint_drops = []
401
510
  end
402
511
 
403
512
  def name; @td.name; end
@@ -410,10 +519,18 @@ module ActiveRecord
410
519
  @foreign_key_drops << name
411
520
  end
412
521
 
413
- def add_column(name, type, options)
522
+ def add_check_constraint(expression, options)
523
+ @check_constraint_adds << CheckConstraintDefinition.new(name, expression, options)
524
+ end
525
+
526
+ def drop_check_constraint(constraint_name)
527
+ @check_constraint_drops << constraint_name
528
+ end
529
+
530
+ def add_column(name, type, **options)
414
531
  name = name.to_s
415
532
  type = type.to_sym
416
- @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, options))
533
+ @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, **options))
417
534
  end
418
535
  end
419
536
 
@@ -430,9 +547,11 @@ module ActiveRecord
430
547
  # t.timestamps
431
548
  # t.change
432
549
  # t.change_default
550
+ # t.change_null
433
551
  # t.rename
434
552
  # t.references
435
553
  # t.belongs_to
554
+ # t.check_constraint
436
555
  # t.string
437
556
  # t.text
438
557
  # t.integer
@@ -446,10 +565,15 @@ module ActiveRecord
446
565
  # t.date
447
566
  # t.binary
448
567
  # t.boolean
568
+ # t.foreign_key
569
+ # t.json
570
+ # t.virtual
449
571
  # t.remove
572
+ # t.remove_foreign_key
450
573
  # t.remove_references
451
574
  # t.remove_belongs_to
452
575
  # t.remove_index
576
+ # t.remove_check_constraint
453
577
  # t.remove_timestamps
454
578
  # end
455
579
  #
@@ -468,17 +592,21 @@ module ActiveRecord
468
592
  # t.column(:name, :string)
469
593
  #
470
594
  # See TableDefinition#column for details of the options you can use.
471
- def column(column_name, type, options = {})
472
- @base.add_column(name, column_name, type, options)
595
+ def column(column_name, type, index: nil, **options)
596
+ @base.add_column(name, column_name, type, **options)
597
+ if index
598
+ index_options = index.is_a?(Hash) ? index : {}
599
+ index(column_name, **index_options)
600
+ end
473
601
  end
474
602
 
475
603
  # Checks to see if a column exists.
476
604
  #
477
- # t.string(:name) unless t.column_exists?(:name, :string)
605
+ # t.string(:name) unless t.column_exists?(:name, :string)
478
606
  #
479
607
  # See {connection.column_exists?}[rdoc-ref:SchemaStatements#column_exists?]
480
- def column_exists?(column_name, type = nil, options = {})
481
- @base.column_exists?(name, column_name, type, options)
608
+ def column_exists?(column_name, type = nil, **options)
609
+ @base.column_exists?(name, column_name, type, **options)
482
610
  end
483
611
 
484
612
  # Adds a new index to the table. +column_name+ can be a single Symbol, or
@@ -489,15 +617,15 @@ module ActiveRecord
489
617
  # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
490
618
  #
491
619
  # See {connection.add_index}[rdoc-ref:SchemaStatements#add_index] for details of the options you can use.
492
- def index(column_name, options = {})
493
- @base.add_index(name, column_name, options)
620
+ def index(column_name, **options)
621
+ @base.add_index(name, column_name, **options)
494
622
  end
495
623
 
496
624
  # Checks to see if an index exists.
497
625
  #
498
- # unless t.index_exists?(:branch_id)
499
- # t.index(:branch_id)
500
- # end
626
+ # unless t.index_exists?(:branch_id)
627
+ # t.index(:branch_id)
628
+ # end
501
629
  #
502
630
  # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
503
631
  def index_exists?(column_name, options = {})
@@ -518,8 +646,8 @@ module ActiveRecord
518
646
  # t.timestamps(null: false)
519
647
  #
520
648
  # See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
521
- def timestamps(options = {})
522
- @base.add_timestamps(name, options)
649
+ def timestamps(**options)
650
+ @base.add_timestamps(name, **options)
523
651
  end
524
652
 
525
653
  # Changes the column's definition according to the new options.
@@ -528,8 +656,8 @@ module ActiveRecord
528
656
  # t.change(:description, :text)
529
657
  #
530
658
  # See TableDefinition#column for details of the options you can use.
531
- def change(column_name, type, options = {})
532
- @base.change_column(name, column_name, type, options)
659
+ def change(column_name, type, **options)
660
+ @base.change_column(name, column_name, type, **options)
533
661
  end
534
662
 
535
663
  # Sets a new default value for a column.
@@ -543,14 +671,24 @@ module ActiveRecord
543
671
  @base.change_column_default(name, column_name, default_or_changes)
544
672
  end
545
673
 
674
+ # Sets or removes a NOT NULL constraint on a column.
675
+ #
676
+ # t.change_null(:qualification, true)
677
+ # t.change_null(:qualification, false, 0)
678
+ #
679
+ # See {connection.change_column_null}[rdoc-ref:SchemaStatements#change_column_null]
680
+ def change_null(column_name, null, default = nil)
681
+ @base.change_column_null(name, column_name, null, default)
682
+ end
683
+
546
684
  # Removes the column(s) from the table definition.
547
685
  #
548
686
  # t.remove(:qualification)
549
687
  # t.remove(:qualification, :experience)
550
688
  #
551
689
  # See {connection.remove_columns}[rdoc-ref:SchemaStatements#remove_columns]
552
- def remove(*column_names)
553
- @base.remove_columns(name, *column_names)
690
+ def remove(*column_names, **options)
691
+ @base.remove_columns(name, *column_names, **options)
554
692
  end
555
693
 
556
694
  # Removes the given index from the table.
@@ -558,10 +696,11 @@ module ActiveRecord
558
696
  # t.remove_index(:branch_id)
559
697
  # t.remove_index(column: [:branch_id, :party_id])
560
698
  # t.remove_index(name: :by_branch_party)
699
+ # t.remove_index(:branch_id, name: :by_branch_party)
561
700
  #
562
701
  # See {connection.remove_index}[rdoc-ref:SchemaStatements#remove_index]
563
- def remove_index(options = {})
564
- @base.remove_index(name, options)
702
+ def remove_index(column_name = nil, **options)
703
+ @base.remove_index(name, column_name, **options)
565
704
  end
566
705
 
567
706
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
@@ -569,8 +708,8 @@ module ActiveRecord
569
708
  # t.remove_timestamps
570
709
  #
571
710
  # See {connection.remove_timestamps}[rdoc-ref:SchemaStatements#remove_timestamps]
572
- def remove_timestamps(options = {})
573
- @base.remove_timestamps(name, options)
711
+ def remove_timestamps(**options)
712
+ @base.remove_timestamps(name, **options)
574
713
  end
575
714
 
576
715
  # Renames a column.
@@ -588,10 +727,9 @@ module ActiveRecord
588
727
  # t.belongs_to(:supplier, foreign_key: true)
589
728
  #
590
729
  # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
591
- def references(*args)
592
- options = args.extract_options!
730
+ def references(*args, **options)
593
731
  args.each do |ref_name|
594
- @base.add_reference(name, ref_name, options)
732
+ @base.add_reference(name, ref_name, **options)
595
733
  end
596
734
  end
597
735
  alias :belongs_to :references
@@ -602,30 +740,58 @@ module ActiveRecord
602
740
  # t.remove_belongs_to(:supplier, polymorphic: true)
603
741
  #
604
742
  # See {connection.remove_reference}[rdoc-ref:SchemaStatements#remove_reference]
605
- def remove_references(*args)
606
- options = args.extract_options!
743
+ def remove_references(*args, **options)
607
744
  args.each do |ref_name|
608
- @base.remove_reference(name, ref_name, options)
745
+ @base.remove_reference(name, ref_name, **options)
609
746
  end
610
747
  end
611
748
  alias :remove_belongs_to :remove_references
612
749
 
613
- # Adds a foreign key.
750
+ # Adds a foreign key to the table using a supplied table name.
614
751
  #
615
- # t.foreign_key(:authors)
752
+ # t.foreign_key(:authors)
753
+ # t.foreign_key(:authors, column: :author_id, primary_key: "id")
616
754
  #
617
755
  # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
618
- def foreign_key(*args) # :nodoc:
619
- @base.add_foreign_key(name, *args)
756
+ def foreign_key(*args, **options)
757
+ @base.add_foreign_key(name, *args, **options)
758
+ end
759
+
760
+ # Removes the given foreign key from the table.
761
+ #
762
+ # t.remove_foreign_key(:authors)
763
+ # t.remove_foreign_key(column: :author_id)
764
+ #
765
+ # See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
766
+ def remove_foreign_key(*args, **options)
767
+ @base.remove_foreign_key(name, *args, **options)
620
768
  end
621
769
 
622
770
  # Checks to see if a foreign key exists.
623
771
  #
624
- # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
772
+ # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
625
773
  #
626
774
  # See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
627
- def foreign_key_exists?(*args) # :nodoc:
628
- @base.foreign_key_exists?(name, *args)
775
+ def foreign_key_exists?(*args, **options)
776
+ @base.foreign_key_exists?(name, *args, **options)
777
+ end
778
+
779
+ # Adds a check constraint.
780
+ #
781
+ # t.check_constraint("price > 0", name: "price_check")
782
+ #
783
+ # See {connection.add_check_constraint}[rdoc-ref:SchemaStatements#add_check_constraint]
784
+ def check_constraint(*args)
785
+ @base.add_check_constraint(name, *args)
786
+ end
787
+
788
+ # Removes the given check constraint from the table.
789
+ #
790
+ # t.remove_check_constraint(name: "price_check")
791
+ #
792
+ # See {connection.remove_check_constraint}[rdoc-ref:SchemaStatements#remove_check_constraint]
793
+ def remove_check_constraint(*args)
794
+ @base.remove_check_constraint(name, *args)
629
795
  end
630
796
  end
631
797
  end