activerecord 4.2.11.2 → 6.0.0

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