activerecord 7.0.4.3 → 7.0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +318 -7
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/associations/collection_association.rb +1 -1
  5. data/lib/active_record/associations/collection_proxy.rb +5 -0
  6. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  7. data/lib/active_record/associations.rb +15 -6
  8. data/lib/active_record/attribute_methods/read.rb +1 -1
  9. data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -4
  10. data/lib/active_record/attribute_methods.rb +5 -7
  11. data/lib/active_record/callbacks.rb +12 -14
  12. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +20 -16
  13. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +2 -1
  14. data/lib/active_record/connection_adapters/abstract_adapter.rb +4 -17
  15. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +15 -9
  16. data/lib/active_record/connection_adapters/mysql/database_statements.rb +1 -1
  17. data/lib/active_record/connection_adapters/mysql/quoting.rb +13 -2
  18. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
  19. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  20. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -5
  21. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  22. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
  23. data/lib/active_record/connection_adapters/postgresql/quoting.rb +5 -2
  24. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +3 -2
  25. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  26. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -1
  27. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -2
  28. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
  29. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
  30. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -4
  31. data/lib/active_record/disable_joins_association_relation.rb +1 -1
  32. data/lib/active_record/explain_subscriber.rb +1 -1
  33. data/lib/active_record/gem_version.rb +2 -2
  34. data/lib/active_record/locking/optimistic.rb +32 -18
  35. data/lib/active_record/middleware/database_selector.rb +3 -3
  36. data/lib/active_record/migration/command_recorder.rb +1 -2
  37. data/lib/active_record/migration/compatibility.rb +19 -54
  38. data/lib/active_record/migration.rb +53 -4
  39. data/lib/active_record/persistence.rb +7 -5
  40. data/lib/active_record/railties/controller_runtime.rb +3 -4
  41. data/lib/active_record/reflection.rb +8 -0
  42. data/lib/active_record/relation/calculations.rb +50 -23
  43. data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
  44. data/lib/active_record/relation/query_attribute.rb +23 -0
  45. data/lib/active_record/relation/query_methods.rb +35 -8
  46. data/lib/active_record/result.rb +6 -4
  47. data/lib/active_record/schema_dumper.rb +4 -0
  48. data/lib/active_record/store.rb +1 -1
  49. data/lib/active_record/table_metadata.rb +6 -2
  50. data/lib/active_record/transactions.rb +3 -3
  51. data/lib/active_record/type/serialized.rb +8 -4
  52. data/lib/arel/filter_predications.rb +1 -1
  53. data/lib/arel/nodes/and.rb +4 -0
  54. data/lib/arel/nodes/filter.rb +1 -1
  55. metadata +13 -13
@@ -138,11 +138,6 @@ module ActiveRecord
138
138
  true
139
139
  end
140
140
 
141
- def field_ordered_value(column, values) # :nodoc:
142
- field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse.map { |value| Arel::Nodes.build_quoted(value) }])
143
- Arel::Nodes::Descending.new(field)
144
- end
145
-
146
141
  def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
147
142
  query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
148
143
  end
@@ -403,7 +398,7 @@ module ActiveRecord
403
398
 
404
399
  fk_info.map do |row|
405
400
  options = {
406
- column: row["column"],
401
+ column: unquote_identifier(row["column"]),
407
402
  name: row["name"],
408
403
  primary_key: row["primary_key"]
409
404
  }
@@ -411,7 +406,7 @@ module ActiveRecord
411
406
  options[:on_update] = extract_foreign_key_action(row["on_update"])
412
407
  options[:on_delete] = extract_foreign_key_action(row["on_delete"])
413
408
 
414
- ForeignKeyDefinition.new(table_name, row["to_table"], options)
409
+ ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
415
410
  end
416
411
  end
417
412
 
@@ -438,7 +433,8 @@ module ActiveRecord
438
433
  name: row["name"]
439
434
  }
440
435
  expression = row["expression"]
441
- expression = expression[1..-2] unless mariadb? # remove parentheses added by mysql
436
+ expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
437
+ expression = strip_whitespace_characters(expression)
442
438
  CheckConstraintDefinition.new(table_name, expression, options)
443
439
  end
444
440
  else
@@ -619,6 +615,16 @@ module ActiveRecord
619
615
  end
620
616
 
621
617
  private
618
+ def strip_whitespace_characters(expression)
619
+ expression = expression.gsub(/\\n|\\\\/, "")
620
+ expression = expression.gsub(/\s{2,}/, " ")
621
+ expression
622
+ end
623
+
624
+ def text_type?(type)
625
+ TYPE_MAP.lookup(type).is_a?(Type::String) || TYPE_MAP.lookup(type).is_a?(Type::Text)
626
+ end
627
+
622
628
  def type_map
623
629
  emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
624
630
  end
@@ -712,7 +718,7 @@ module ActiveRecord
712
718
  end
713
719
 
714
720
  unless options.key?(:collation)
715
- options[:collation] = column.collation
721
+ options[:collation] = column.collation if text_type?(type)
716
722
  end
717
723
 
718
724
  unless options.key?(:auto_increment)
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  end
21
21
 
22
22
  READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
23
- :desc, :describe, :set, :show, :use
23
+ :desc, :describe, :set, :show, :use, :kill
24
24
  ) # :nodoc:
25
25
  private_constant :READ_QUERY
26
26
 
@@ -6,6 +6,9 @@ module ActiveRecord
6
6
  module ConnectionAdapters
7
7
  module MySQL
8
8
  module Quoting # :nodoc:
9
+ QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
10
+ QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
11
+
9
12
  def quote_bound_value(value)
10
13
  case value
11
14
  when Rational
@@ -24,11 +27,11 @@ module ActiveRecord
24
27
  end
25
28
 
26
29
  def quote_column_name(name)
27
- self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
30
+ QUOTED_COLUMN_NAMES[name] ||= "`#{super.gsub('`', '``')}`"
28
31
  end
29
32
 
30
33
  def quote_table_name(name)
31
- self.class.quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
34
+ QUOTED_TABLE_NAMES[name] ||= super.gsub(".", "`.`").freeze
32
35
  end
33
36
 
34
37
  def unquoted_true
@@ -51,6 +54,14 @@ module ActiveRecord
51
54
  "x'#{value.hex}'"
52
55
  end
53
56
 
57
+ def unquote_identifier(identifier)
58
+ if identifier && identifier.start_with?("`")
59
+ identifier[1..-2]
60
+ else
61
+ identifier
62
+ end
63
+ end
64
+
54
65
  # Override +type_cast+ we pass to mysql2 Date and Time objects instead
55
66
  # of Strings since mysql2 is able to handle those classes more efficiently.
56
67
  def type_cast(value) # :nodoc:
@@ -90,7 +90,10 @@ module ActiveRecord
90
90
  end
91
91
 
92
92
  def integer_like_primary_key_type(type, options)
93
- options[:auto_increment] = true
93
+ unless options[:auto_increment] == false
94
+ options[:auto_increment] = true
95
+ end
96
+
94
97
  type
95
98
  end
96
99
  end
@@ -42,11 +42,13 @@ module ActiveRecord
42
42
 
43
43
  def init_with(coder)
44
44
  @serial = coder["serial"]
45
+ @generated = coder["generated"]
45
46
  super
46
47
  end
47
48
 
48
49
  def encode_with(coder)
49
50
  coder["serial"] = @serial
51
+ coder["generated"] = @generated
50
52
  super
51
53
  end
52
54
 
@@ -57,11 +57,7 @@ module ActiveRecord
57
57
  fields.each_with_index do |fname, i|
58
58
  ftype = result.ftype i
59
59
  fmod = result.fmod i
60
- case type = get_oid_type(ftype, fmod, fname)
61
- when Type::Integer, Type::Float, OID::Decimal, Type::String, Type::DateTime, Type::Boolean
62
- # skip if a column has already been type casted by pg decoders
63
- else types[fname] = type
64
- end
60
+ types[fname] = types[i] = get_oid_type(ftype, fmod, fname)
65
61
  end
66
62
  build_result(columns: fields, rows: result.values, column_types: types)
67
63
  end
@@ -65,7 +65,7 @@ module ActiveRecord
65
65
  end
66
66
 
67
67
  def map(value, &block)
68
- value.map(&block)
68
+ value.map { |v| subtype.map(v, &block) }
69
69
  end
70
70
 
71
71
  def changed_in_place?(raw_old_value, new_value)
@@ -13,7 +13,7 @@ module ActiveRecord
13
13
  return if value.blank?
14
14
 
15
15
  time = super
16
- return time if time.is_a?(ActiveSupport::TimeWithZone)
16
+ return time if time.is_a?(ActiveSupport::TimeWithZone) || !time.acts_like?(:time)
17
17
 
18
18
  # While in UTC mode, the PG gem may not return times back in "UTC" even if they were provided to Postgres in UTC.
19
19
  # We prefer times always in UTC, so here we convert back.
@@ -4,6 +4,9 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module PostgreSQL
6
6
  module Quoting
7
+ QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
8
+ QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
9
+
7
10
  class IntegerOutOf64BitRange < StandardError
8
11
  def initialize(msg)
9
12
  super(msg)
@@ -81,7 +84,7 @@ module ActiveRecord
81
84
  # - "schema.name".table_name
82
85
  # - "schema.name"."table.name"
83
86
  def quote_table_name(name) # :nodoc:
84
- self.class.quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
87
+ QUOTED_TABLE_NAMES[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
85
88
  end
86
89
 
87
90
  # Quotes schema names for use in SQL queries.
@@ -95,7 +98,7 @@ module ActiveRecord
95
98
 
96
99
  # Quotes column names for use in SQL queries.
97
100
  def quote_column_name(name) # :nodoc:
98
- self.class.quoted_column_names[name] ||= PG::Connection.quote_ident(super).freeze
101
+ QUOTED_COLUMN_NAMES[name] ||= PG::Connection.quote_ident(super).freeze
99
102
  end
100
103
 
101
104
  # Quote date/time values for use in SQL input.
@@ -498,7 +498,7 @@ module ActiveRecord
498
498
 
499
499
  fk_info.map do |row|
500
500
  options = {
501
- column: row["column"],
501
+ column: Utils.unquote_identifier(row["column"]),
502
502
  name: row["name"],
503
503
  primary_key: row["primary_key"]
504
504
  }
@@ -508,8 +508,9 @@ module ActiveRecord
508
508
  options[:deferrable] = extract_foreign_key_deferrable(row["deferrable"], row["deferred"])
509
509
 
510
510
  options[:validate] = row["valid"]
511
+ to_table = Utils.unquote_identifier(row["to_table"])
511
512
 
512
- ForeignKeyDefinition.new(table_name, row["to_table"], options)
513
+ ForeignKeyDefinition.new(table_name, to_table, options)
513
514
  end
514
515
  end
515
516
 
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  attr_reader :schema, :identifier
13
13
 
14
14
  def initialize(schema, identifier)
15
- @schema, @identifier = unquote(schema), unquote(identifier)
15
+ @schema, @identifier = Utils.unquote_identifier(schema), Utils.unquote_identifier(identifier)
16
16
  end
17
17
 
18
18
  def to_s
@@ -40,15 +40,6 @@ module ActiveRecord
40
40
  def parts
41
41
  @parts ||= [@schema, @identifier].compact
42
42
  end
43
-
44
- private
45
- def unquote(part)
46
- if part && part.start_with?('"')
47
- part[1..-2]
48
- else
49
- part
50
- end
51
- end
52
43
  end
53
44
 
54
45
  module Utils # :nodoc:
@@ -74,6 +65,14 @@ module ActiveRecord
74
65
  end
75
66
  PostgreSQL::Name.new(schema, table)
76
67
  end
68
+
69
+ def unquote_identifier(identifier)
70
+ if identifier && identifier.start_with?('"')
71
+ identifier[1..-2]
72
+ else
73
+ identifier
74
+ end
75
+ end
77
76
  end
78
77
  end
79
78
  end
@@ -977,7 +977,7 @@ module ActiveRecord
977
977
  PG::TextDecoder::TimestampUtc :
978
978
  PG::TextDecoder::TimestampWithoutTimeZone
979
979
 
980
- @timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
980
+ @timestamp_decoder = decoder_class.new(**@timestamp_decoder.to_h)
981
981
  @connection.type_map_for_results.add_coder(@timestamp_decoder)
982
982
 
983
983
  @default_timezone = ActiveRecord.default_timezone
@@ -4,6 +4,9 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLite3
6
6
  module Quoting # :nodoc:
7
+ QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
8
+ QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
9
+
7
10
  def quote_string(s)
8
11
  @connection.class.quote(s)
9
12
  end
@@ -13,11 +16,11 @@ module ActiveRecord
13
16
  end
14
17
 
15
18
  def quote_table_name(name)
16
- self.class.quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze
19
+ QUOTED_TABLE_NAMES[name] ||= super.gsub(".", "\".\"").freeze
17
20
  end
18
21
 
19
22
  def quote_column_name(name)
20
- self.class.quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
23
+ QUOTED_COLUMN_NAMES[name] ||= %Q("#{super.gsub('"', '""')}")
21
24
  end
22
25
 
23
26
  def quoted_time(value)
@@ -4,6 +4,12 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLite3
6
6
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
7
+ def change_column(column_name, type, **options)
8
+ name = column_name.to_s
9
+ @columns_hash[name] = nil
10
+ column(name, type, **options)
11
+ end
12
+
7
13
  def references(*args, **options)
8
14
  super(*args, type: :integer, **options)
9
15
  end
@@ -84,11 +84,11 @@ module ActiveRecord
84
84
  table_sql = query_value(<<-SQL, "SCHEMA")
85
85
  SELECT sql
86
86
  FROM sqlite_master
87
- WHERE name = #{quote_table_name(table_name)} AND type = 'table'
87
+ WHERE name = #{quote(table_name)} AND type = 'table'
88
88
  UNION ALL
89
89
  SELECT sql
90
90
  FROM sqlite_temp_master
91
- WHERE name = #{quote_table_name(table_name)} AND type = 'table'
91
+ WHERE name = #{quote(table_name)} AND type = 'table'
92
92
  SQL
93
93
 
94
94
  table_sql.to_s.scan(/CONSTRAINT\s+(?<name>\w+)\s+CHECK\s+\((?<expression>(:?[^()]|\(\g<expression>\))+)\)/i).map do |name, expression|
@@ -287,10 +287,7 @@ module ActiveRecord
287
287
 
288
288
  def change_column(table_name, column_name, type, **options) # :nodoc:
289
289
  alter_table(table_name) do |definition|
290
- definition[column_name].instance_eval do
291
- self.type = aliased_types(type.to_s, type)
292
- self.options.merge!(options)
293
- end
290
+ definition.change_column(column_name, type, **options)
294
291
  end
295
292
  end
296
293
 
@@ -480,6 +477,7 @@ module ActiveRecord
480
477
  if column.has_default?
481
478
  type = lookup_cast_type_from_column(column)
482
479
  default = type.deserialize(column.default)
480
+ default = -> { column.default_function } if default.nil?
483
481
  end
484
482
 
485
483
  @definition.column(column_name, column.type,
@@ -30,7 +30,7 @@ module ActiveRecord
30
30
  record[key]
31
31
  end
32
32
 
33
- records = ids.flat_map { |id| records_by_id[id.to_i] }
33
+ records = ids.flat_map { |id| records_by_id[id] }
34
34
  records.compact!
35
35
 
36
36
  @records = records
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # On the other hand, we want to monitor the performance of our real database
22
22
  # queries, not the performance of the access to the query cache.
23
23
  IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN)
24
- EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
24
+ EXPLAINED_SQLS = /\A\s*(\/\*.*\*\/)?\s*(with|select|update|delete|insert)\b/i
25
25
  def ignore_payload?(payload)
26
26
  payload[:exception] ||
27
27
  payload[:cached] ||
@@ -9,8 +9,8 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
- TINY = 4
13
- PRE = "3"
12
+ TINY = 8
13
+ PRE = "6"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Locking
5
- # == What is Optimistic Locking
5
+ # == What is \Optimistic \Locking
6
6
  #
7
7
  # Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of
8
8
  # conflicts with the data. It does this by checking whether another process has made changes to a record since
9
- # it was opened, an <tt>ActiveRecord::StaleObjectError</tt> exception is thrown if that has occurred
9
+ # it was opened, an ActiveRecord::StaleObjectError exception is thrown if that has occurred
10
10
  # and the update is ignored.
11
11
  #
12
- # Check out <tt>ActiveRecord::Locking::Pessimistic</tt> for an alternative.
12
+ # Check out +ActiveRecord::Locking::Pessimistic+ for an alternative.
13
13
  #
14
14
  # == Usage
15
15
  #
@@ -69,6 +69,11 @@ module ActiveRecord
69
69
  end
70
70
  end
71
71
 
72
+ def initialize_dup(other) # :nodoc:
73
+ super
74
+ _clear_locking_column if locking_enabled?
75
+ end
76
+
72
77
  private
73
78
  def _create_record(attribute_names = self.attribute_names)
74
79
  if locking_enabled?
@@ -91,8 +96,7 @@ module ActiveRecord
91
96
  locking_column = self.class.locking_column
92
97
  lock_attribute_was = @attributes[locking_column]
93
98
 
94
- update_constraints = _primary_key_constraints_hash
95
- update_constraints[locking_column] = _lock_value_for_database(locking_column)
99
+ update_constraints = _query_constraints_hash
96
100
 
97
101
  attribute_names = attribute_names.dup if attribute_names.frozen?
98
102
  attribute_names << locking_column
@@ -118,16 +122,9 @@ module ActiveRecord
118
122
  end
119
123
 
120
124
  def destroy_row
121
- return super unless locking_enabled?
122
-
123
- locking_column = self.class.locking_column
125
+ affected_rows = super
124
126
 
125
- delete_constraints = _primary_key_constraints_hash
126
- delete_constraints[locking_column] = _lock_value_for_database(locking_column)
127
-
128
- affected_rows = self.class._delete_record(delete_constraints)
129
-
130
- if affected_rows != 1
127
+ if locking_enabled? && affected_rows != 1
131
128
  raise ActiveRecord::StaleObjectError.new(self, "destroy")
132
129
  end
133
130
 
@@ -142,6 +139,18 @@ module ActiveRecord
142
139
  end
143
140
  end
144
141
 
142
+ def _clear_locking_column
143
+ self[self.class.locking_column] = nil
144
+ clear_attribute_change(self.class.locking_column)
145
+ end
146
+
147
+ def _query_constraints_hash
148
+ return super unless locking_enabled?
149
+
150
+ locking_column = self.class.locking_column
151
+ super.merge(locking_column => _lock_value_for_database(locking_column))
152
+ end
153
+
145
154
  module ClassMethods
146
155
  DEFAULT_LOCKING_COLUMN = "lock_version"
147
156
 
@@ -159,10 +168,7 @@ module ActiveRecord
159
168
  end
160
169
 
161
170
  # The version column used for optimistic locking. Defaults to +lock_version+.
162
- def locking_column
163
- @locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column)
164
- @locking_column
165
- end
171
+ attr_reader :locking_column
166
172
 
167
173
  # Reset the column used for optimistic locking back to the +lock_version+ default.
168
174
  def reset_locking_column
@@ -182,6 +188,14 @@ module ActiveRecord
182
188
  end
183
189
  super
184
190
  end
191
+
192
+ private
193
+ def inherited(base)
194
+ super
195
+ base.class_eval do
196
+ @locking_column = DEFAULT_LOCKING_COLUMN
197
+ end
198
+ end
185
199
  end
186
200
  end
187
201
 
@@ -43,9 +43,9 @@ module ActiveRecord
43
43
  # config.active_record.database_resolver = MyResolver
44
44
  # config.active_record.database_resolver_context = MyResolver::MySession
45
45
  #
46
- # Note: If you are using `rails new my_app --minimal` you will need to call
47
- # `require "active_support/core_ext/integer/time"` to load the libraries
48
- # for +Time+.
46
+ # Note: If you are using <tt>rails new my_app --minimal</tt> you will need
47
+ # to call <tt>require "active_support/core_ext/integer/time"</tt> to load
48
+ # the core extension in order to use +2.seconds+
49
49
  class DatabaseSelector
50
50
  def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
51
51
  @app = app
@@ -12,7 +12,6 @@ module ActiveRecord
12
12
  # * add_index
13
13
  # * add_reference
14
14
  # * add_timestamps
15
- # * change_column
16
15
  # * change_column_default (must supply a +:from+ and +:to+ option)
17
16
  # * change_column_null
18
17
  # * change_column_comment (must supply a +:from+ and +:to+ option)
@@ -24,7 +23,7 @@ module ActiveRecord
24
23
  # * drop_table (must supply a block)
25
24
  # * enable_extension
26
25
  # * remove_column (must supply a type)
27
- # * remove_columns (must specify at least one column name or more)
26
+ # * remove_columns (must supply a +:type+ option)
28
27
  # * remove_foreign_key (must supply a second table)
29
28
  # * remove_check_constraint
30
29
  # * remove_index
@@ -56,12 +56,13 @@ module ActiveRecord
56
56
  super
57
57
  end
58
58
 
59
- def create_table(table_name, **options)
60
- if block_given?
61
- super { |t| yield compatible_table_definition(t) }
62
- else
63
- super
59
+ def change_column(table_name, column_name, type, **options)
60
+ if type == :datetime
61
+ options[:precision] ||= nil
64
62
  end
63
+
64
+ type = PostgreSQLCompat.compatible_timestamp_type(type, connection)
65
+ super
65
66
  end
66
67
 
67
68
  module TableDefinition
@@ -70,6 +71,11 @@ module ActiveRecord
70
71
  super
71
72
  end
72
73
 
74
+ def change(name, type, index: nil, **options)
75
+ options[:precision] ||= nil
76
+ super
77
+ end
78
+
73
79
  def column(name, type, index: nil, **options)
74
80
  options[:precision] ||= nil
75
81
  super
@@ -81,7 +87,7 @@ module ActiveRecord
81
87
  class << t
82
88
  prepend TableDefinition
83
89
  end
84
- t
90
+ super
85
91
  end
86
92
  end
87
93
 
@@ -105,30 +111,6 @@ module ActiveRecord
105
111
  end
106
112
  end
107
113
 
108
- def create_table(table_name, **options)
109
- if block_given?
110
- super { |t| yield compatible_table_definition(t) }
111
- else
112
- super
113
- end
114
- end
115
-
116
- def change_table(table_name, **options)
117
- if block_given?
118
- super { |t| yield compatible_table_definition(t) }
119
- else
120
- super
121
- end
122
- end
123
-
124
- def create_join_table(table_1, table_2, **options)
125
- if block_given?
126
- super { |t| yield compatible_table_definition(t) }
127
- else
128
- super
129
- end
130
- end
131
-
132
114
  def add_reference(table_name, ref_name, **options)
133
115
  if connection.adapter_name == "SQLite"
134
116
  options[:type] = :integer
@@ -159,6 +141,13 @@ module ActiveRecord
159
141
  options[:precision] ||= nil
160
142
  super
161
143
  end
144
+
145
+ private
146
+ def raise_on_if_exist_options(options)
147
+ end
148
+
149
+ def raise_on_duplicate_column(name)
150
+ end
162
151
  end
163
152
 
164
153
  module CommandRecorder
@@ -175,30 +164,6 @@ module ActiveRecord
175
164
  end
176
165
  end
177
166
 
178
- def create_table(table_name, **options)
179
- if block_given?
180
- super { |t| yield compatible_table_definition(t) }
181
- else
182
- super
183
- end
184
- end
185
-
186
- def change_table(table_name, **options)
187
- if block_given?
188
- super { |t| yield compatible_table_definition(t) }
189
- else
190
- super
191
- end
192
- end
193
-
194
- def create_join_table(table_1, table_2, **options)
195
- if block_given?
196
- super { |t| yield compatible_table_definition(t) }
197
- else
198
- super
199
- end
200
- end
201
-
202
167
  def add_timestamps(table_name, **options)
203
168
  options[:precision] ||= nil
204
169
  super