activerecord 5.1.7 → 5.2.4.3

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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +556 -685
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record.rb +11 -4
  8. data/lib/active_record/aggregations.rb +6 -5
  9. data/lib/active_record/association_relation.rb +7 -5
  10. data/lib/active_record/associations.rb +40 -63
  11. data/lib/active_record/associations/alias_tracker.rb +19 -27
  12. data/lib/active_record/associations/association.rb +41 -37
  13. data/lib/active_record/associations/association_scope.rb +38 -50
  14. data/lib/active_record/associations/belongs_to_association.rb +27 -8
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  16. data/lib/active_record/associations/builder/association.rb +4 -7
  17. data/lib/active_record/associations/builder/belongs_to.rb +12 -4
  18. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +2 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +59 -47
  24. data/lib/active_record/associations/collection_proxy.rb +20 -49
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +12 -1
  27. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  28. data/lib/active_record/associations/has_one_association.rb +12 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +48 -93
  31. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  32. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  33. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  34. data/lib/active_record/associations/preloader.rb +18 -38
  35. data/lib/active_record/associations/preloader/association.rb +45 -61
  36. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +26 -11
  39. data/lib/active_record/attribute_assignment.rb +2 -5
  40. data/lib/active_record/attribute_decorators.rb +3 -2
  41. data/lib/active_record/attribute_methods.rb +65 -24
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +30 -214
  44. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  45. data/lib/active_record/attribute_methods/query.rb +2 -0
  46. data/lib/active_record/attribute_methods/read.rb +9 -3
  47. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  49. data/lib/active_record/attribute_methods/write.rb +21 -9
  50. data/lib/active_record/attributes.rb +6 -5
  51. data/lib/active_record/autosave_association.rb +35 -19
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +8 -6
  54. data/lib/active_record/coders/json.rb +2 -0
  55. data/lib/active_record/coders/yaml_column.rb +2 -0
  56. data/lib/active_record/collection_cache_key.rb +12 -8
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
  70. data/lib/active_record/connection_adapters/column.rb +3 -1
  71. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  73. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +233 -111
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
  118. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +81 -94
  127. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  128. data/lib/active_record/connection_handling.rb +4 -2
  129. data/lib/active_record/core.rb +41 -61
  130. data/lib/active_record/counter_cache.rb +10 -3
  131. data/lib/active_record/define_callbacks.rb +5 -3
  132. data/lib/active_record/dynamic_matchers.rb +9 -9
  133. data/lib/active_record/enum.rb +18 -13
  134. data/lib/active_record/errors.rb +42 -3
  135. data/lib/active_record/explain.rb +3 -1
  136. data/lib/active_record/explain_registry.rb +2 -0
  137. data/lib/active_record/explain_subscriber.rb +2 -0
  138. data/lib/active_record/fixture_set/file.rb +2 -0
  139. data/lib/active_record/fixtures.rb +67 -60
  140. data/lib/active_record/gem_version.rb +5 -3
  141. data/lib/active_record/inheritance.rb +49 -19
  142. data/lib/active_record/integration.rb +58 -19
  143. data/lib/active_record/internal_metadata.rb +2 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  145. data/lib/active_record/locking/optimistic.rb +14 -17
  146. data/lib/active_record/locking/pessimistic.rb +9 -6
  147. data/lib/active_record/log_subscriber.rb +43 -0
  148. data/lib/active_record/migration.rb +189 -139
  149. data/lib/active_record/migration/command_recorder.rb +11 -9
  150. data/lib/active_record/migration/compatibility.rb +47 -9
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +16 -21
  153. data/lib/active_record/nested_attributes.rb +18 -6
  154. data/lib/active_record/no_touching.rb +3 -1
  155. data/lib/active_record/null_relation.rb +2 -0
  156. data/lib/active_record/persistence.rb +167 -16
  157. data/lib/active_record/query_cache.rb +6 -8
  158. data/lib/active_record/querying.rb +4 -2
  159. data/lib/active_record/railtie.rb +62 -6
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +2 -0
  162. data/lib/active_record/railties/databases.rake +46 -36
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +108 -194
  165. data/lib/active_record/relation.rb +120 -214
  166. data/lib/active_record/relation/batches.rb +20 -5
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +45 -19
  169. data/lib/active_record/relation/delegation.rb +45 -27
  170. data/lib/active_record/relation/finder_methods.rb +75 -76
  171. data/lib/active_record/relation/from_clause.rb +2 -8
  172. data/lib/active_record/relation/merger.rb +53 -23
  173. data/lib/active_record/relation/predicate_builder.rb +60 -79
  174. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  175. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  176. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  177. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  178. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  179. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  180. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  181. data/lib/active_record/relation/query_attribute.rb +28 -2
  182. data/lib/active_record/relation/query_methods.rb +128 -99
  183. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  184. data/lib/active_record/relation/spawn_methods.rb +4 -2
  185. data/lib/active_record/relation/where_clause.rb +65 -68
  186. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  187. data/lib/active_record/result.rb +2 -0
  188. data/lib/active_record/runtime_registry.rb +2 -0
  189. data/lib/active_record/sanitization.rb +129 -121
  190. data/lib/active_record/schema.rb +4 -2
  191. data/lib/active_record/schema_dumper.rb +36 -26
  192. data/lib/active_record/schema_migration.rb +2 -0
  193. data/lib/active_record/scoping.rb +9 -8
  194. data/lib/active_record/scoping/default.rb +8 -9
  195. data/lib/active_record/scoping/named.rb +23 -7
  196. data/lib/active_record/secure_token.rb +2 -0
  197. data/lib/active_record/serialization.rb +2 -0
  198. data/lib/active_record/statement_cache.rb +23 -13
  199. data/lib/active_record/store.rb +3 -1
  200. data/lib/active_record/suppressor.rb +2 -0
  201. data/lib/active_record/table_metadata.rb +12 -3
  202. data/lib/active_record/tasks/database_tasks.rb +25 -14
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +6 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +33 -28
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type.rb +4 -1
  211. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  212. data/lib/active_record/type/date.rb +2 -0
  213. data/lib/active_record/type/date_time.rb +2 -0
  214. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  215. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  216. data/lib/active_record/type/internal/timezone.rb +2 -0
  217. data/lib/active_record/type/json.rb +30 -0
  218. data/lib/active_record/type/serialized.rb +2 -0
  219. data/lib/active_record/type/text.rb +2 -0
  220. data/lib/active_record/type/time.rb +2 -0
  221. data/lib/active_record/type/type_map.rb +2 -0
  222. data/lib/active_record/type/unsigned_integer.rb +2 -0
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/type_caster/connection.rb +2 -0
  225. data/lib/active_record/type_caster/map.rb +3 -1
  226. data/lib/active_record/validations.rb +2 -0
  227. data/lib/active_record/validations/absence.rb +2 -0
  228. data/lib/active_record/validations/associated.rb +2 -0
  229. data/lib/active_record/validations/length.rb +2 -0
  230. data/lib/active_record/validations/presence.rb +2 -0
  231. data/lib/active_record/validations/uniqueness.rb +35 -5
  232. data/lib/active_record/version.rb +2 -0
  233. data/lib/rails/generators/active_record.rb +3 -1
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration.rb +2 -0
  237. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  238. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  239. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  243. metadata +23 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute.rb +0 -240
  252. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -126
  256. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module Savepoints
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/strip"
2
4
 
3
5
  module ActiveRecord
@@ -22,7 +24,7 @@ module ActiveRecord
22
24
  private
23
25
 
24
26
  def visit_AlterTable(o)
25
- sql = "ALTER TABLE #{quote_table_name(o.name)} "
27
+ sql = "ALTER TABLE #{quote_table_name(o.name)} ".dup
26
28
  sql << o.adds.map { |col| accept col }.join(" ")
27
29
  sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
28
30
  sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
@@ -30,17 +32,17 @@ module ActiveRecord
30
32
 
31
33
  def visit_ColumnDefinition(o)
32
34
  o.sql_type = type_to_sql(o.type, o.options)
33
- column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
35
+ column_sql = "#{quote_column_name(o.name)} #{o.sql_type}".dup
34
36
  add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
35
37
  column_sql
36
38
  end
37
39
 
38
40
  def visit_AddColumnDefinition(o)
39
- "ADD #{accept(o.column)}"
41
+ "ADD #{accept(o.column)}".dup
40
42
  end
41
43
 
42
44
  def visit_TableDefinition(o)
43
- create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
45
+ create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} ".dup
44
46
 
45
47
  statements = o.columns.map { |c| accept c }
46
48
  statements << accept(o.primary_keys) if o.primary_keys
@@ -55,7 +57,7 @@ module ActiveRecord
55
57
 
56
58
  create_sql << "(#{statements.join(', ')})" if statements.present?
57
59
  add_table_options!(create_sql, table_options(o))
58
- create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
60
+ create_sql << " AS #{to_sql(o.as)}" if o.as
59
61
  create_sql
60
62
  end
61
63
 
@@ -93,6 +95,7 @@ module ActiveRecord
93
95
  if options_sql = options[:options]
94
96
  create_sql << " #{options_sql}"
95
97
  end
98
+ create_sql
96
99
  end
97
100
 
98
101
  def column_options(o)
@@ -114,6 +117,11 @@ module ActiveRecord
114
117
  sql
115
118
  end
116
119
 
120
+ def to_sql(sql)
121
+ sql = sql.to_sql if sql.respond_to?(:to_sql)
122
+ sql
123
+ end
124
+
117
125
  def foreign_key_in_create(from_table, to_table, options)
118
126
  options = foreign_key_options(from_table, to_table, options)
119
127
  accept ForeignKeyDefinition.new(from_table, to_table, options)
@@ -133,5 +141,6 @@ module ActiveRecord
133
141
  end
134
142
  end
135
143
  end
144
+ SchemaCreation = AbstractAdapter::SchemaCreation # :nodoc:
136
145
  end
137
146
  end
@@ -1,9 +1,47 @@
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
- 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
+ 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
44
+ end
7
45
 
8
46
  # Abstract representation of a column definition. Instances of this type
9
47
  # are typically created by methods in TableDefinition, and added to the
@@ -58,6 +96,11 @@ module ActiveRecord
58
96
  options[:primary_key] != default_primary_key
59
97
  end
60
98
 
99
+ def validate?
100
+ options.fetch(:validate, true)
101
+ end
102
+ alias validated? validate?
103
+
61
104
  def defined_for?(to_table_ord = nil, to_table: nil, **options)
62
105
  if to_table_ord
63
106
  self.to_table == to_table_ord.to_s
@@ -177,6 +220,7 @@ module ActiveRecord
177
220
  :decimal,
178
221
  :float,
179
222
  :integer,
223
+ :json,
180
224
  :string,
181
225
  :text,
182
226
  :time,
@@ -369,6 +413,9 @@ module ActiveRecord
369
413
  alias :belongs_to :references
370
414
 
371
415
  def new_column_definition(name, type, **options) # :nodoc:
416
+ if integer_like_primary_key?(type, options)
417
+ type = integer_like_primary_key_type(type, options)
418
+ end
372
419
  type = aliased_types(type.to_s, type)
373
420
  options[:primary_key] ||= type == :primary_key
374
421
  options[:null] = false if options[:primary_key]
@@ -383,6 +430,14 @@ module ActiveRecord
383
430
  def aliased_types(name, fallback)
384
431
  "timestamp" == name ? :datetime : fallback
385
432
  end
433
+
434
+ def integer_like_primary_key?(type, options)
435
+ options[:primary_key] && [:integer, :bigint].include?(type) && !options.key?(:default)
436
+ end
437
+
438
+ def integer_like_primary_key_type(type, options)
439
+ type
440
+ end
386
441
  end
387
442
 
388
443
  class AlterTable # :nodoc:
@@ -443,6 +498,9 @@ module ActiveRecord
443
498
  # t.date
444
499
  # t.binary
445
500
  # t.boolean
501
+ # t.foreign_key
502
+ # t.json
503
+ # t.virtual
446
504
  # t.remove
447
505
  # t.remove_references
448
506
  # t.remove_belongs_to
@@ -607,19 +665,19 @@ module ActiveRecord
607
665
 
608
666
  # Adds a foreign key.
609
667
  #
610
- # t.foreign_key(:authors)
668
+ # t.foreign_key(:authors)
611
669
  #
612
670
  # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
613
- def foreign_key(*args) # :nodoc:
671
+ def foreign_key(*args)
614
672
  @base.add_foreign_key(name, *args)
615
673
  end
616
674
 
617
675
  # Checks to see if a foreign key exists.
618
676
  #
619
- # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
677
+ # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
620
678
  #
621
679
  # See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
622
- def foreign_key_exists?(*args) # :nodoc:
680
+ def foreign_key_exists?(*args)
623
681
  @base.foreign_key_exists?(name, *args)
624
682
  end
625
683
  end
@@ -1,63 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/compact"
4
+
1
5
  module ActiveRecord
2
6
  module ConnectionAdapters # :nodoc:
3
- # The goal of this module is to move Adapter specific column
4
- # definitions to the Adapter instead of having it in the schema
5
- # dumper itself. This code represents the normal case.
6
- # We can then redefine how certain data types may be handled in the schema dumper on the
7
- # Adapter level by over-writing this code inside the database specific adapters
8
- module ColumnDumper
9
- def column_spec(column)
10
- [schema_type_with_virtual(column), prepare_column_options(column)]
7
+ class SchemaDumper < SchemaDumper # :nodoc:
8
+ def self.create(connection, options)
9
+ new(connection, options)
11
10
  end
12
11
 
13
- def column_spec_for_primary_key(column)
14
- return {} if default_primary_key?(column)
15
- spec = { id: schema_type(column).inspect }
16
- spec.merge!(prepare_column_options(column).except!(:null))
17
- spec[:default] ||= "nil" if explicit_primary_key_default?(column)
18
- spec
19
- end
20
-
21
- # This can be overridden on an Adapter level basis to support other
22
- # extended datatypes (Example: Adding an array option in the
23
- # PostgreSQL::ColumnDumper)
24
- def prepare_column_options(column)
25
- spec = {}
26
-
27
- if limit = schema_limit(column)
28
- spec[:limit] = limit
12
+ private
13
+ def column_spec(column)
14
+ [schema_type_with_virtual(column), prepare_column_options(column)]
29
15
  end
30
16
 
31
- if precision = schema_precision(column)
32
- spec[:precision] = precision
17
+ def column_spec_for_primary_key(column)
18
+ return {} if default_primary_key?(column)
19
+ spec = { id: schema_type(column).inspect }
20
+ spec.merge!(prepare_column_options(column).except!(:null))
21
+ spec[:default] ||= "nil" if explicit_primary_key_default?(column)
22
+ spec
33
23
  end
34
24
 
35
- if scale = schema_scale(column)
36
- spec[:scale] = scale
25
+ def prepare_column_options(column)
26
+ spec = {}
27
+ spec[:limit] = schema_limit(column)
28
+ spec[:precision] = schema_precision(column)
29
+ spec[:scale] = schema_scale(column)
30
+ spec[:default] = schema_default(column)
31
+ spec[:null] = "false" unless column.null
32
+ spec[:collation] = schema_collation(column)
33
+ spec[:comment] = column.comment.inspect if column.comment.present?
34
+ spec.compact!
35
+ spec
37
36
  end
38
37
 
39
- default = schema_default(column) if column.has_default?
40
- spec[:default] = default unless default.nil?
41
-
42
- spec[:null] = "false" unless column.null
43
-
44
- if collation = schema_collation(column)
45
- spec[:collation] = collation
46
- end
47
-
48
- spec[:comment] = column.comment.inspect if column.comment.present?
49
-
50
- spec
51
- end
52
-
53
- # Lists the valid migration options
54
- def migration_keys # :nodoc:
55
- column_options_keys
56
- end
57
- deprecate :migration_keys
58
-
59
- private
60
-
61
38
  def default_primary_key?(column)
62
39
  schema_type(column) == :bigint
63
40
  end
@@ -67,7 +44,7 @@ module ActiveRecord
67
44
  end
68
45
 
69
46
  def schema_type_with_virtual(column)
70
- if supports_virtual_columns? && column.virtual?
47
+ if @connection.supports_virtual_columns? && column.virtual?
71
48
  :virtual
72
49
  else
73
50
  schema_type(column)
@@ -84,7 +61,7 @@ module ActiveRecord
84
61
 
85
62
  def schema_limit(column)
86
63
  limit = column.limit unless column.bigint?
87
- limit.inspect if limit && limit != native_database_types[column.type][:limit]
64
+ limit.inspect if limit && limit != @connection.native_database_types[column.type][:limit]
88
65
  end
89
66
 
90
67
  def schema_precision(column)
@@ -96,7 +73,8 @@ module ActiveRecord
96
73
  end
97
74
 
98
75
  def schema_default(column)
99
- type = lookup_cast_type_from_column(column)
76
+ return unless column.has_default?
77
+ type = @connection.lookup_cast_type_from_column(column)
100
78
  default = type.deserialize(column.default)
101
79
  if default.nil?
102
80
  schema_expression(column)
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/migration/join_table"
2
4
  require "active_support/core_ext/string/access"
3
- require "digest"
5
+ require "digest/sha2"
4
6
 
5
7
  module ActiveRecord
6
8
  module ConnectionAdapters # :nodoc:
@@ -77,7 +79,7 @@ module ActiveRecord
77
79
  end
78
80
 
79
81
  # Returns an array of indexes for the given table.
80
- def indexes(table_name, name = nil)
82
+ def indexes(table_name)
81
83
  raise NotImplementedError, "#indexes is not implemented"
82
84
  end
83
85
 
@@ -98,17 +100,19 @@ module ActiveRecord
98
100
  def index_exists?(table_name, column_name, options = {})
99
101
  column_names = Array(column_name).map(&:to_s)
100
102
  checks = []
101
- checks << lambda { |i| i.columns == column_names }
103
+ checks << lambda { |i| Array(i.columns) == column_names }
102
104
  checks << lambda { |i| i.unique } if options[:unique]
103
105
  checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
104
106
 
105
107
  indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
106
108
  end
107
109
 
108
- # Returns an array of Column objects for the table specified by +table_name+.
109
- # See the concrete implementation for details on the expected parameter values.
110
+ # Returns an array of +Column+ objects for the table specified by +table_name+.
110
111
  def columns(table_name)
111
- raise NotImplementedError, "#columns is not implemented"
112
+ table_name = table_name.to_s
113
+ column_definitions(table_name).map do |field|
114
+ new_column_from_field(table_name, field)
115
+ end
112
116
  end
113
117
 
114
118
  # Checks to see if a column exists in a given table.
@@ -186,6 +190,8 @@ module ActiveRecord
186
190
  # The name of the primary key, if one is to be added automatically.
187
191
  # Defaults to +id+. If <tt>:id</tt> is false, then this option is ignored.
188
192
  #
193
+ # If an array is passed, a composite primary key will be created.
194
+ #
189
195
  # Note that Active Record models will automatically detect their
190
196
  # primary key. This can be avoided by using
191
197
  # {self.primary_key=}[rdoc-ref:AttributeMethods::PrimaryKey::ClassMethods#primary_key=] on the model
@@ -210,7 +216,7 @@ module ActiveRecord
210
216
  # generates:
211
217
  #
212
218
  # CREATE TABLE suppliers (
213
- # id int auto_increment PRIMARY KEY
219
+ # id bigint auto_increment PRIMARY KEY
214
220
  # ) ENGINE=InnoDB DEFAULT CHARSET=utf8
215
221
  #
216
222
  # ====== Rename the primary key column
@@ -222,7 +228,7 @@ module ActiveRecord
222
228
  # generates:
223
229
  #
224
230
  # CREATE TABLE objects (
225
- # guid int auto_increment PRIMARY KEY,
231
+ # guid bigint auto_increment PRIMARY KEY,
226
232
  # name varchar(80)
227
233
  # )
228
234
  #
@@ -239,18 +245,35 @@ module ActiveRecord
239
245
  # label varchar
240
246
  # )
241
247
  #
248
+ # ====== Create a composite primary key
249
+ #
250
+ # create_table(:orders, primary_key: [:product_id, :client_id]) do |t|
251
+ # t.belongs_to :product
252
+ # t.belongs_to :client
253
+ # end
254
+ #
255
+ # generates:
256
+ #
257
+ # CREATE TABLE order (
258
+ # product_id bigint NOT NULL,
259
+ # client_id bigint NOT NULL
260
+ # );
261
+ #
262
+ # ALTER TABLE ONLY "orders"
263
+ # ADD CONSTRAINT orders_pkey PRIMARY KEY (product_id, client_id);
264
+ #
242
265
  # ====== Do not add a primary key column
243
266
  #
244
267
  # create_table(:categories_suppliers, id: false) do |t|
245
- # t.column :category_id, :integer
246
- # t.column :supplier_id, :integer
268
+ # t.column :category_id, :bigint
269
+ # t.column :supplier_id, :bigint
247
270
  # end
248
271
  #
249
272
  # generates:
250
273
  #
251
274
  # CREATE TABLE categories_suppliers (
252
- # category_id int,
253
- # supplier_id int
275
+ # category_id bigint,
276
+ # supplier_id bigint
254
277
  # )
255
278
  #
256
279
  # ====== Create a temporary table based on a query
@@ -282,7 +305,7 @@ module ActiveRecord
282
305
  yield td if block_given?
283
306
 
284
307
  if options[:force]
285
- drop_table(table_name, **options, if_exists: true)
308
+ drop_table(table_name, options.merge(if_exists: true))
286
309
  end
287
310
 
288
311
  result = execute schema_creation.accept td
@@ -338,8 +361,8 @@ module ActiveRecord
338
361
  # generates:
339
362
  #
340
363
  # CREATE TABLE assemblies_parts (
341
- # assembly_id int NOT NULL,
342
- # part_id int NOT NULL,
364
+ # assembly_id bigint NOT NULL,
365
+ # part_id bigint NOT NULL,
343
366
  # ) ENGINE=InnoDB DEFAULT CHARSET=utf8
344
367
  #
345
368
  def create_join_table(table_1, table_2, column_options: {}, **options)
@@ -383,6 +406,8 @@ module ActiveRecord
383
406
  #
384
407
  # Defaults to false.
385
408
  #
409
+ # Only supported on the MySQL and PostgreSQL adapter, ignored elsewhere.
410
+ #
386
411
  # ====== Add a column
387
412
  #
388
413
  # change_table(:suppliers) do |t|
@@ -407,7 +432,7 @@ module ActiveRecord
407
432
  # t.references :company
408
433
  # end
409
434
  #
410
- # Creates a <tt>company_id(integer)</tt> column.
435
+ # Creates a <tt>company_id(bigint)</tt> column.
411
436
  #
412
437
  # ====== Add a polymorphic foreign key column
413
438
  #
@@ -415,7 +440,7 @@ module ActiveRecord
415
440
  # t.belongs_to :company, polymorphic: true
416
441
  # end
417
442
  #
418
- # Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns.
443
+ # Creates <tt>company_type(varchar)</tt> and <tt>company_id(bigint)</tt> columns.
419
444
  #
420
445
  # ====== Remove a column
421
446
  #
@@ -488,15 +513,17 @@ module ActiveRecord
488
513
  # * <tt>:limit</tt> -
489
514
  # Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
490
515
  # and number of bytes for <tt>:text</tt>, <tt>:binary</tt> and <tt>:integer</tt> columns.
516
+ # This option is ignored by some backends.
491
517
  # * <tt>:default</tt> -
492
518
  # The column's default value. Use +nil+ for +NULL+.
493
519
  # * <tt>:null</tt> -
494
- # Allows or disallows +NULL+ values in the column. This option could
495
- # have been named <tt>:null_allowed</tt>.
520
+ # Allows or disallows +NULL+ values in the column.
496
521
  # * <tt>:precision</tt> -
497
522
  # Specifies the precision for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
498
523
  # * <tt>:scale</tt> -
499
524
  # Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
525
+ # * <tt>:comment</tt> -
526
+ # Specifies the comment for the column. This option is ignored by some backends.
500
527
  #
501
528
  # Note: The precision is the total number of significant digits,
502
529
  # and the scale is the number of digits that can be stored following
@@ -573,7 +600,7 @@ module ActiveRecord
573
600
  # to provide these in a migration's +change+ method so it can be reverted.
574
601
  # In that case, +type+ and +options+ will be used by #add_column.
575
602
  def remove_column(table_name, column_name, type = nil, options = {})
576
- execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
603
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_for_alter(table_name, column_name, type, options)}"
577
604
  end
578
605
 
579
606
  # Changes the column's definition according to the new options.
@@ -688,7 +715,7 @@ module ActiveRecord
688
715
  #
689
716
  # CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
690
717
  #
691
- # Note: MySQL doesn't yet support index order (it accepts the syntax but ignores it).
718
+ # Note: MySQL only supports index order from 8.0.1 onwards (earlier versions accepted the syntax but ignored it).
692
719
  #
693
720
  # ====== Creating a partial index
694
721
  #
@@ -711,6 +738,19 @@ module ActiveRecord
711
738
  #
712
739
  # Note: only supported by PostgreSQL and MySQL
713
740
  #
741
+ # ====== Creating an index with a specific operator class
742
+ #
743
+ # add_index(:developers, :name, using: 'gist', opclass: :gist_trgm_ops)
744
+ # # CREATE INDEX developers_on_name ON developers USING gist (name gist_trgm_ops) -- PostgreSQL
745
+ #
746
+ # add_index(:developers, [:name, :city], using: 'gist', opclass: { city: :gist_trgm_ops })
747
+ # # CREATE INDEX developers_on_name_and_city ON developers USING gist (name, city gist_trgm_ops) -- PostgreSQL
748
+ #
749
+ # add_index(:developers, [:name, :city], using: 'gist', opclass: :gist_trgm_ops)
750
+ # # CREATE INDEX developers_on_name_and_city ON developers USING gist (name gist_trgm_ops, city gist_trgm_ops) -- PostgreSQL
751
+ #
752
+ # Note: only supported by PostgreSQL
753
+ #
714
754
  # ====== Creating an index with a specific type
715
755
  #
716
756
  # add_index(:developers, :name, type: :fulltext)
@@ -757,7 +797,7 @@ module ActiveRecord
757
797
  def rename_index(table_name, old_name, new_name)
758
798
  validate_index_length!(table_name, new_name)
759
799
 
760
- # this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
800
+ # this is a naive implementation; some DBs may support this more efficiently (PostgreSQL, for instance)
761
801
  old_index_def = indexes(table_name).detect { |i| i.name == old_name }
762
802
  return unless old_index_def
763
803
  add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique)
@@ -779,24 +819,19 @@ module ActiveRecord
779
819
  end
780
820
 
781
821
  # Verifies the existence of an index with a given name.
782
- def index_name_exists?(table_name, index_name, default = nil)
783
- unless default.nil?
784
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
785
- Passing default to #index_name_exists? is deprecated without replacement.
786
- MSG
787
- end
822
+ def index_name_exists?(table_name, index_name)
788
823
  index_name = index_name.to_s
789
824
  indexes(table_name).detect { |i| i.name == index_name }
790
825
  end
791
826
 
792
- # Adds a reference. The reference column is an integer by default,
827
+ # Adds a reference. The reference column is a bigint by default,
793
828
  # the <tt>:type</tt> option can be used to specify a different type.
794
829
  # Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
795
830
  # #add_reference and #add_belongs_to are acceptable.
796
831
  #
797
832
  # The +options+ hash can include the following keys:
798
833
  # [<tt>:type</tt>]
799
- # The reference column type. Defaults to +:integer+.
834
+ # The reference column type. Defaults to +:bigint+.
800
835
  # [<tt>:index</tt>]
801
836
  # Add an appropriate index. Defaults to true.
802
837
  # See #add_index for usage of this option.
@@ -807,7 +842,7 @@ module ActiveRecord
807
842
  # [<tt>:null</tt>]
808
843
  # Whether the column allows nulls. Defaults to true.
809
844
  #
810
- # ====== Create a user_id integer column
845
+ # ====== Create a user_id bigint column
811
846
  #
812
847
  # add_reference(:products, :user)
813
848
  #
@@ -864,7 +899,7 @@ module ActiveRecord
864
899
  foreign_key_options = { to_table: reference_name }
865
900
  end
866
901
  foreign_key_options[:column] ||= "#{ref_name}_id"
867
- remove_foreign_key(table_name, **foreign_key_options)
902
+ remove_foreign_key(table_name, foreign_key_options)
868
903
  end
869
904
 
870
905
  remove_column(table_name, "#{ref_name}_id")
@@ -920,6 +955,8 @@ module ActiveRecord
920
955
  # Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
921
956
  # [<tt>:on_update</tt>]
922
957
  # Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
958
+ # [<tt>:validate</tt>]
959
+ # (Postgres only) Specify whether or not the constraint should be validated. Defaults to +true+.
923
960
  def add_foreign_key(from_table, to_table, options = {})
924
961
  return unless supports_foreign_keys?
925
962
 
@@ -974,16 +1011,6 @@ module ActiveRecord
974
1011
  foreign_key_for(from_table, options_or_to_table).present?
975
1012
  end
976
1013
 
977
- def foreign_key_for(from_table, options_or_to_table = {}) # :nodoc:
978
- return unless supports_foreign_keys?
979
- foreign_keys(from_table).detect { |fk| fk.defined_for? options_or_to_table }
980
- end
981
-
982
- def foreign_key_for!(from_table, options_or_to_table = {}) # :nodoc:
983
- foreign_key_for(from_table, options_or_to_table) || \
984
- raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}")
985
- end
986
-
987
1014
  def foreign_key_column_for(table_name) # :nodoc:
988
1015
  prefix = Base.table_name_prefix
989
1016
  suffix = Base.table_name_suffix
@@ -1003,29 +1030,6 @@ module ActiveRecord
1003
1030
  insert_versions_sql(versions) if versions.any?
1004
1031
  end
1005
1032
 
1006
- def insert_versions_sql(versions) # :nodoc:
1007
- sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
1008
-
1009
- if versions.is_a?(Array)
1010
- sql = "INSERT INTO #{sm_table} (version) VALUES\n"
1011
- sql << versions.map { |v| "(#{quote(v)})" }.join(",\n")
1012
- sql << ";\n\n"
1013
- sql
1014
- else
1015
- "INSERT INTO #{sm_table} (version) VALUES (#{quote(versions)});"
1016
- end
1017
- end
1018
-
1019
- def initialize_schema_migrations_table # :nodoc:
1020
- ActiveRecord::SchemaMigration.create_table
1021
- end
1022
- deprecate :initialize_schema_migrations_table
1023
-
1024
- def initialize_internal_metadata_table # :nodoc:
1025
- ActiveRecord::InternalMetadata.create_table
1026
- end
1027
- deprecate :initialize_internal_metadata_table
1028
-
1029
1033
  def internal_string_options_for_primary_key # :nodoc:
1030
1034
  { primary_key: true }
1031
1035
  end
@@ -1036,8 +1040,8 @@ module ActiveRecord
1036
1040
  sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
1037
1041
 
1038
1042
  migrated = ActiveRecord::SchemaMigration.all_versions.map(&:to_i)
1039
- versions = ActiveRecord::Migrator.migration_files(migrations_paths).map do |file|
1040
- ActiveRecord::Migrator.parse_migration_filename(file).first.to_i
1043
+ versions = migration_context.migration_files.map do |file|
1044
+ migration_context.parse_migration_filename(file).first.to_i
1041
1045
  end
1042
1046
 
1043
1047
  unless migrated.include?(version)
@@ -1131,7 +1135,7 @@ module ActiveRecord
1131
1135
  def add_index_options(table_name, column_name, comment: nil, **options) # :nodoc:
1132
1136
  column_names = index_column_names(column_name)
1133
1137
 
1134
- options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
1138
+ options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type, :opclass)
1135
1139
 
1136
1140
  index_type = options[:type].to_s if options.key?(:type)
1137
1141
  index_type ||= options[:unique] ? "UNIQUE" : ""
@@ -1170,30 +1174,36 @@ module ActiveRecord
1170
1174
  end
1171
1175
 
1172
1176
  # Changes the comment for a column or removes it if +nil+.
1173
- def change_column_comment(table_name, column_name, comment) #:nodoc:
1177
+ def change_column_comment(table_name, column_name, comment)
1174
1178
  raise NotImplementedError, "#{self.class} does not support changing column comments"
1175
1179
  end
1176
1180
 
1181
+ def create_schema_dumper(options) # :nodoc:
1182
+ SchemaDumper.create(self, options)
1183
+ end
1184
+
1177
1185
  private
1178
1186
  def column_options_keys
1179
1187
  [:limit, :precision, :scale, :default, :null, :collation, :comment]
1180
1188
  end
1181
1189
 
1182
1190
  def add_index_sort_order(quoted_columns, **options)
1183
- if order = options[:order]
1184
- case order
1185
- when Hash
1186
- order = order.symbolize_keys
1187
- quoted_columns.each { |name, column| column << " #{order[name].upcase}" if order[name].present? }
1188
- when String
1189
- quoted_columns.each { |name, column| column << " #{order.upcase}" if order.present? }
1190
- end
1191
+ orders = options_for_index_columns(options[:order])
1192
+ quoted_columns.each do |name, column|
1193
+ column << " #{orders[name].upcase}" if orders[name].present?
1191
1194
  end
1195
+ end
1192
1196
 
1193
- quoted_columns
1197
+ def options_for_index_columns(options)
1198
+ if options.is_a?(Hash)
1199
+ options.symbolize_keys
1200
+ else
1201
+ Hash.new { |hash, column| hash[column] = options }
1202
+ end
1194
1203
  end
1195
1204
 
1196
- # Overridden by the MySQL adapter for supporting index lengths
1205
+ # Overridden by the MySQL adapter for supporting index lengths and by
1206
+ # the PostgreSQL adapter for supporting operator classes.
1197
1207
  def add_options_for_index_columns(quoted_columns, **options)
1198
1208
  if supports_index_sort_order?
1199
1209
  quoted_columns = add_index_sort_order(quoted_columns, options)
@@ -1261,6 +1271,10 @@ module ActiveRecord
1261
1271
  end
1262
1272
  end
1263
1273
 
1274
+ def schema_creation
1275
+ SchemaCreation.new(self)
1276
+ end
1277
+
1264
1278
  def create_table_definition(*args)
1265
1279
  TableDefinition.new(*args)
1266
1280
  end
@@ -1269,6 +1283,17 @@ module ActiveRecord
1269
1283
  AlterTable.new create_table_definition(name)
1270
1284
  end
1271
1285
 
1286
+ def fetch_type_metadata(sql_type)
1287
+ cast_type = lookup_cast_type(sql_type)
1288
+ SqlTypeMetadata.new(
1289
+ sql_type: sql_type,
1290
+ type: cast_type.type,
1291
+ limit: cast_type.limit,
1292
+ precision: cast_type.precision,
1293
+ scale: cast_type.scale,
1294
+ )
1295
+ end
1296
+
1272
1297
  def index_column_names(column_names)
1273
1298
  if column_names.is_a?(String) && /\W/.match?(column_names)
1274
1299
  column_names
@@ -1286,13 +1311,32 @@ module ActiveRecord
1286
1311
  end
1287
1312
 
1288
1313
  def foreign_key_name(table_name, options)
1289
- identifier = "#{table_name}_#{options.fetch(:column)}_fk"
1290
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
1291
1314
  options.fetch(:name) do
1315
+ identifier = "#{table_name}_#{options.fetch(:column)}_fk"
1316
+ hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
1317
+
1292
1318
  "fk_rails_#{hashed_identifier}"
1293
1319
  end
1294
1320
  end
1295
1321
 
1322
+ def foreign_key_for(from_table, options_or_to_table = {})
1323
+ return unless supports_foreign_keys?
1324
+ foreign_keys(from_table).detect { |fk| fk.defined_for? options_or_to_table }
1325
+ end
1326
+
1327
+ def foreign_key_for!(from_table, options_or_to_table = {})
1328
+ foreign_key_for(from_table, options_or_to_table) || \
1329
+ raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}")
1330
+ end
1331
+
1332
+ def extract_foreign_key_action(specifier)
1333
+ case specifier
1334
+ when "CASCADE"; :cascade
1335
+ when "SET NULL"; :nullify
1336
+ when "RESTRICT"; :restrict
1337
+ end
1338
+ end
1339
+
1296
1340
  def validate_index_length!(table_name, new_name, internal = false)
1297
1341
  max_index_length = internal ? index_name_length : allowed_index_name_length
1298
1342
 
@@ -1313,6 +1357,33 @@ module ActiveRecord
1313
1357
  options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
1314
1358
  end
1315
1359
 
1360
+ def add_column_for_alter(table_name, column_name, type, options = {})
1361
+ td = create_table_definition(table_name)
1362
+ cd = td.new_column_definition(column_name, type, options)
1363
+ schema_creation.accept(AddColumnDefinition.new(cd))
1364
+ end
1365
+
1366
+ def remove_column_for_alter(table_name, column_name, type = nil, options = {})
1367
+ "DROP COLUMN #{quote_column_name(column_name)}"
1368
+ end
1369
+
1370
+ def remove_columns_for_alter(table_name, *column_names)
1371
+ column_names.map { |column_name| remove_column_for_alter(table_name, column_name) }
1372
+ end
1373
+
1374
+ def insert_versions_sql(versions)
1375
+ sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
1376
+
1377
+ if versions.is_a?(Array)
1378
+ sql = "INSERT INTO #{sm_table} (version) VALUES\n".dup
1379
+ sql << versions.map { |v| "(#{quote(v)})" }.join(",\n")
1380
+ sql << ";\n\n"
1381
+ sql
1382
+ else
1383
+ "INSERT INTO #{sm_table} (version) VALUES (#{quote(versions)});"
1384
+ end
1385
+ end
1386
+
1316
1387
  def data_source_sql(name = nil, type: nil)
1317
1388
  raise NotImplementedError
1318
1389
  end