activerecord 6.0.0.beta1 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +455 -9
- data/README.rdoc +3 -1
- data/lib/active_record/associations/association.rb +18 -1
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +5 -6
- data/lib/active_record/associations/collection_proxy.rb +13 -42
- data/lib/active_record/associations/has_many_association.rb +1 -9
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +21 -7
- data/lib/active_record/associations/join_dependency.rb +10 -9
- data/lib/active_record/associations/preloader/association.rb +37 -34
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +11 -6
- data/lib/active_record/associations.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +47 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attribute_methods.rb +3 -53
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +15 -5
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/callbacks.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +124 -23
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +101 -70
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +51 -40
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +95 -30
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +108 -39
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +93 -134
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +66 -5
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -3
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +98 -89
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +47 -63
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +91 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +69 -118
- data/lib/active_record/connection_handling.rb +32 -16
- data/lib/active_record/core.rb +27 -20
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +21 -16
- data/lib/active_record/database_configurations.rb +99 -50
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +15 -0
- data/lib/active_record/errors.rb +18 -13
- data/lib/active_record/fixtures.rb +11 -6
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +72 -63
- data/lib/active_record/migration.rb +62 -44
- data/lib/active_record/persistence.rb +212 -19
- data/lib/active_record/querying.rb +18 -14
- data/lib/active_record/railtie.rb +9 -1
- data/lib/active_record/railties/collection_cache_association_loading.rb +3 -3
- data/lib/active_record/railties/databases.rake +124 -25
- data/lib/active_record/reflection.rb +18 -32
- data/lib/active_record/relation/calculations.rb +40 -44
- data/lib/active_record/relation/delegation.rb +23 -31
- data/lib/active_record/relation/finder_methods.rb +13 -13
- data/lib/active_record/relation/merger.rb +11 -16
- data/lib/active_record/relation/query_attribute.rb +5 -3
- data/lib/active_record/relation/query_methods.rb +217 -68
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +10 -10
- data/lib/active_record/relation.rb +184 -35
- data/lib/active_record/sanitization.rb +33 -4
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +10 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +7 -15
- data/lib/active_record/scoping/named.rb +10 -2
- data/lib/active_record/scoping.rb +6 -7
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +9 -13
- data/lib/active_record/tasks/database_tasks.rb +109 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
- data/lib/active_record/test_databases.rb +1 -16
- data/lib/active_record/test_fixtures.rb +2 -2
- data/lib/active_record/timestamp.rb +35 -19
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +55 -45
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -1
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes/and.rb +1 -1
- data/lib/arel/nodes/case.rb +1 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +7 -2
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +107 -131
- data/lib/arel/visitors/visitor.rb +9 -5
- data/lib/arel.rb +7 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +17 -13
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -15,7 +15,7 @@ module ActiveRecord
|
|
15
15
|
end
|
16
16
|
|
17
17
|
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
18
|
-
:options_include_default?, :supports_indexes_in_create?, :
|
18
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options,
|
19
19
|
to: :@conn, private: true
|
20
20
|
|
21
21
|
private
|
@@ -50,7 +50,7 @@ module ActiveRecord
|
|
50
50
|
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
51
51
|
end
|
52
52
|
|
53
|
-
if
|
53
|
+
if supports_foreign_keys?
|
54
54
|
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
55
55
|
end
|
56
56
|
|
@@ -127,6 +127,9 @@ module ActiveRecord
|
|
127
127
|
end
|
128
128
|
|
129
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}"
|
130
133
|
options = foreign_key_options(from_table, to_table, options)
|
131
134
|
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
132
135
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/deprecation"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
module ConnectionAdapters #:nodoc:
|
7
5
|
# Abstract representation of an index definition on a table. Instances of
|
@@ -104,16 +102,12 @@ module ActiveRecord
|
|
104
102
|
alias validated? validate?
|
105
103
|
|
106
104
|
def export_name_on_schema_dump?
|
107
|
-
|
105
|
+
!ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
|
108
106
|
end
|
109
107
|
|
110
|
-
def defined_for?(
|
111
|
-
|
112
|
-
self.
|
113
|
-
else
|
114
|
-
(to_table.nil? || to_table.to_s == self.to_table) &&
|
115
|
-
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
116
|
-
end
|
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 }
|
117
111
|
end
|
118
112
|
|
119
113
|
private
|
@@ -200,41 +194,44 @@ module ActiveRecord
|
|
200
194
|
end
|
201
195
|
|
202
196
|
module ColumnMethods
|
197
|
+
extend ActiveSupport::Concern
|
198
|
+
|
203
199
|
# Appends a primary key definition to the table definition.
|
204
200
|
# Can be called multiple times, but this is probably not a good idea.
|
205
201
|
def primary_key(name, type = :primary_key, **options)
|
206
202
|
column(name, type, options.merge(primary_key: true))
|
207
203
|
end
|
208
204
|
|
205
|
+
##
|
206
|
+
# :method: column
|
207
|
+
# :call-seq: column(name, type, **options)
|
208
|
+
#
|
209
209
|
# Appends a column or columns of a specified type.
|
210
210
|
#
|
211
211
|
# t.string(:goat)
|
212
212
|
# t.string(:goat, :sheep)
|
213
213
|
#
|
214
214
|
# See TableDefinition#column
|
215
|
-
|
216
|
-
|
217
|
-
:binary,
|
218
|
-
|
219
|
-
|
220
|
-
:
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
:
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
def #{column_type}(*args, **options)
|
233
|
-
args.each { |name| column(name, :#{column_type}, options) }
|
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
|
234
232
|
end
|
235
|
-
|
233
|
+
end
|
236
234
|
end
|
237
|
-
alias_method :numeric, :decimal
|
238
235
|
end
|
239
236
|
|
240
237
|
# Represents the schema of an SQL table in an abstract way. This class
|
@@ -259,10 +256,9 @@ module ActiveRecord
|
|
259
256
|
include ColumnMethods
|
260
257
|
|
261
258
|
attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys
|
262
|
-
attr_writer :indexes
|
263
|
-
deprecate :indexes=
|
264
259
|
|
265
260
|
def initialize(
|
261
|
+
conn,
|
266
262
|
name,
|
267
263
|
temporary: false,
|
268
264
|
if_not_exists: false,
|
@@ -271,6 +267,7 @@ module ActiveRecord
|
|
271
267
|
comment: nil,
|
272
268
|
**
|
273
269
|
)
|
270
|
+
@conn = conn
|
274
271
|
@columns_hash = {}
|
275
272
|
@indexes = []
|
276
273
|
@foreign_keys = []
|
@@ -363,7 +360,7 @@ module ActiveRecord
|
|
363
360
|
# t.references :tagger, polymorphic: true
|
364
361
|
# t.references :taggable, polymorphic: { default: 'Photo' }, index: false
|
365
362
|
# end
|
366
|
-
def column(name, type, options
|
363
|
+
def column(name, type, **options)
|
367
364
|
name = name.to_s
|
368
365
|
type = type.to_sym if type
|
369
366
|
options = options.dup
|
@@ -397,10 +394,7 @@ module ActiveRecord
|
|
397
394
|
end
|
398
395
|
|
399
396
|
def foreign_key(table_name, options = {}) # :nodoc:
|
400
|
-
|
401
|
-
table_name_suffix = ActiveRecord::Base.table_name_suffix
|
402
|
-
table_name = "#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
403
|
-
foreign_keys.push([table_name, options])
|
397
|
+
foreign_keys << [table_name, options]
|
404
398
|
end
|
405
399
|
|
406
400
|
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
@@ -410,6 +404,10 @@ module ActiveRecord
|
|
410
404
|
def timestamps(**options)
|
411
405
|
options[:null] = false if options[:null].nil?
|
412
406
|
|
407
|
+
if !options.key?(:precision) && @conn.supports_datetime_with_precision?
|
408
|
+
options[:precision] = 6
|
409
|
+
end
|
410
|
+
|
413
411
|
column(:created_at, :datetime, options)
|
414
412
|
column(:updated_at, :datetime, options)
|
415
413
|
end
|
@@ -418,6 +416,7 @@ module ActiveRecord
|
|
418
416
|
#
|
419
417
|
# t.references(:user)
|
420
418
|
# t.belongs_to(:supplier, foreign_key: true)
|
419
|
+
# t.belongs_to(:supplier, foreign_key: true, type: :integer)
|
421
420
|
#
|
422
421
|
# See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
|
423
422
|
def references(*args, **options)
|
@@ -517,6 +516,7 @@ module ActiveRecord
|
|
517
516
|
# t.json
|
518
517
|
# t.virtual
|
519
518
|
# t.remove
|
519
|
+
# t.remove_foreign_key
|
520
520
|
# t.remove_references
|
521
521
|
# t.remove_belongs_to
|
522
522
|
# t.remove_index
|
@@ -538,7 +538,7 @@ module ActiveRecord
|
|
538
538
|
# t.column(:name, :string)
|
539
539
|
#
|
540
540
|
# See TableDefinition#column for details of the options you can use.
|
541
|
-
def column(column_name, type, options
|
541
|
+
def column(column_name, type, **options)
|
542
542
|
index_options = options.delete(:index)
|
543
543
|
@base.add_column(name, column_name, type, options)
|
544
544
|
index(column_name, index_options.is_a?(Hash) ? index_options : {}) if index_options
|
@@ -680,15 +680,26 @@ module ActiveRecord
|
|
680
680
|
end
|
681
681
|
alias :remove_belongs_to :remove_references
|
682
682
|
|
683
|
-
# Adds a foreign key.
|
683
|
+
# Adds a foreign key to the table using a supplied table name.
|
684
684
|
#
|
685
685
|
# t.foreign_key(:authors)
|
686
|
+
# t.foreign_key(:authors, column: :author_id, primary_key: "id")
|
686
687
|
#
|
687
688
|
# See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
|
688
689
|
def foreign_key(*args)
|
689
690
|
@base.add_foreign_key(name, *args)
|
690
691
|
end
|
691
692
|
|
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
|
+
|
692
703
|
# Checks to see if a foreign key exists.
|
693
704
|
#
|
694
705
|
# t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
|
@@ -15,7 +15,7 @@ module ActiveRecord
|
|
15
15
|
def column_spec_for_primary_key(column)
|
16
16
|
return {} if default_primary_key?(column)
|
17
17
|
spec = { id: schema_type(column).inspect }
|
18
|
-
spec.merge!(prepare_column_options(column).except!(:null))
|
18
|
+
spec.merge!(prepare_column_options(column).except!(:null, :comment))
|
19
19
|
spec[:default] ||= "nil" if explicit_primary_key_default?(column)
|
20
20
|
spec
|
21
21
|
end
|
@@ -101,7 +101,7 @@ module ActiveRecord
|
|
101
101
|
def index_exists?(table_name, column_name, options = {})
|
102
102
|
column_names = Array(column_name).map(&:to_s)
|
103
103
|
checks = []
|
104
|
-
checks << lambda { |i| i.columns == column_names }
|
104
|
+
checks << lambda { |i| Array(i.columns) == column_names }
|
105
105
|
checks << lambda { |i| i.unique } if options[:unique]
|
106
106
|
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
|
107
107
|
|
@@ -130,11 +130,11 @@ module ActiveRecord
|
|
130
130
|
# column_exists?(:suppliers, :name, :string, null: false)
|
131
131
|
# column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
|
132
132
|
#
|
133
|
-
def column_exists?(table_name, column_name, type = nil, options
|
133
|
+
def column_exists?(table_name, column_name, type = nil, **options)
|
134
134
|
column_name = column_name.to_s
|
135
135
|
checks = []
|
136
136
|
checks << lambda { |c| c.name == column_name }
|
137
|
-
checks << lambda { |c| c.type == type } if type
|
137
|
+
checks << lambda { |c| c.type == type.to_sym rescue nil } if type
|
138
138
|
column_options_keys.each do |attr|
|
139
139
|
checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr)
|
140
140
|
end
|
@@ -302,7 +302,7 @@ module ActiveRecord
|
|
302
302
|
if pk.is_a?(Array)
|
303
303
|
td.primary_keys pk
|
304
304
|
else
|
305
|
-
td.primary_key pk, options.fetch(:id, :primary_key), options
|
305
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options.except(:comment)
|
306
306
|
end
|
307
307
|
end
|
308
308
|
|
@@ -518,14 +518,15 @@ module ActiveRecord
|
|
518
518
|
# Available options are (none of these exists by default):
|
519
519
|
# * <tt>:limit</tt> -
|
520
520
|
# Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
|
521
|
-
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt
|
521
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
|
522
522
|
# This option is ignored by some backends.
|
523
523
|
# * <tt>:default</tt> -
|
524
524
|
# The column's default value. Use +nil+ for +NULL+.
|
525
525
|
# * <tt>:null</tt> -
|
526
526
|
# Allows or disallows +NULL+ values in the column.
|
527
527
|
# * <tt>:precision</tt> -
|
528
|
-
# Specifies the precision for the <tt>:decimal</tt
|
528
|
+
# Specifies the precision for the <tt>:decimal</tt>, <tt>:numeric</tt>,
|
529
|
+
# <tt>:datetime</tt>, and <tt>:time</tt> columns.
|
529
530
|
# * <tt>:scale</tt> -
|
530
531
|
# Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
|
531
532
|
# * <tt>:collation</tt> -
|
@@ -584,7 +585,7 @@ module ActiveRecord
|
|
584
585
|
# # Defines a column with a database-specific type.
|
585
586
|
# add_column(:shapes, :triangle, 'polygon')
|
586
587
|
# # ALTER TABLE "shapes" ADD "triangle" polygon
|
587
|
-
def add_column(table_name, column_name, type, options
|
588
|
+
def add_column(table_name, column_name, type, **options)
|
588
589
|
at = create_alter_table table_name
|
589
590
|
at.add_column(column_name, type, options)
|
590
591
|
execute schema_creation.accept at
|
@@ -770,6 +771,17 @@ module ActiveRecord
|
|
770
771
|
# CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
|
771
772
|
#
|
772
773
|
# Note: only supported by MySQL.
|
774
|
+
#
|
775
|
+
# ====== Creating an index with a specific algorithm
|
776
|
+
#
|
777
|
+
# add_index(:developers, :name, algorithm: :concurrently)
|
778
|
+
# # CREATE INDEX CONCURRENTLY developers_on_name on developers (name)
|
779
|
+
#
|
780
|
+
# Note: only supported by PostgreSQL.
|
781
|
+
#
|
782
|
+
# Concurrently adding an index is not supported in a transaction.
|
783
|
+
#
|
784
|
+
# For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
|
773
785
|
def add_index(table_name, column_name, options = {})
|
774
786
|
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
|
775
787
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
|
@@ -793,6 +805,15 @@ module ActiveRecord
|
|
793
805
|
#
|
794
806
|
# remove_index :accounts, name: :by_branch_party
|
795
807
|
#
|
808
|
+
# Removes the index named +by_branch_party+ in the +accounts+ table +concurrently+.
|
809
|
+
#
|
810
|
+
# remove_index :accounts, name: :by_branch_party, algorithm: :concurrently
|
811
|
+
#
|
812
|
+
# Note: only supported by PostgreSQL.
|
813
|
+
#
|
814
|
+
# Concurrently removing an index is not supported in a transaction.
|
815
|
+
#
|
816
|
+
# For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
|
796
817
|
def remove_index(table_name, options = {})
|
797
818
|
index_name = index_name_for_remove(table_name, options)
|
798
819
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
@@ -852,7 +873,7 @@ module ActiveRecord
|
|
852
873
|
# [<tt>:null</tt>]
|
853
874
|
# Whether the column allows nulls. Defaults to true.
|
854
875
|
#
|
855
|
-
# ====== Create a user_id bigint column without
|
876
|
+
# ====== Create a user_id bigint column without an index
|
856
877
|
#
|
857
878
|
# add_reference(:products, :user, index: false)
|
858
879
|
#
|
@@ -966,7 +987,7 @@ module ActiveRecord
|
|
966
987
|
# [<tt>:on_update</tt>]
|
967
988
|
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
968
989
|
# [<tt>:validate</tt>]
|
969
|
-
# (
|
990
|
+
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
970
991
|
def add_foreign_key(from_table, to_table, options = {})
|
971
992
|
return unless supports_foreign_keys?
|
972
993
|
|
@@ -1002,10 +1023,10 @@ module ActiveRecord
|
|
1002
1023
|
# with an addition of
|
1003
1024
|
# [<tt>:to_table</tt>]
|
1004
1025
|
# The name of the table that contains the referenced primary key.
|
1005
|
-
def remove_foreign_key(from_table,
|
1026
|
+
def remove_foreign_key(from_table, to_table = nil, **options)
|
1006
1027
|
return unless supports_foreign_keys?
|
1007
1028
|
|
1008
|
-
fk_name_to_delete = foreign_key_for!(from_table,
|
1029
|
+
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
|
1009
1030
|
|
1010
1031
|
at = create_alter_table from_table
|
1011
1032
|
at.drop_foreign_key fk_name_to_delete
|
@@ -1024,14 +1045,12 @@ module ActiveRecord
|
|
1024
1045
|
# # Checks to see if a foreign key with a custom name exists.
|
1025
1046
|
# foreign_key_exists?(:accounts, name: "special_fk_name")
|
1026
1047
|
#
|
1027
|
-
def foreign_key_exists?(from_table,
|
1028
|
-
foreign_key_for(from_table,
|
1048
|
+
def foreign_key_exists?(from_table, to_table = nil, **options)
|
1049
|
+
foreign_key_for(from_table, to_table: to_table, **options).present?
|
1029
1050
|
end
|
1030
1051
|
|
1031
1052
|
def foreign_key_column_for(table_name) # :nodoc:
|
1032
|
-
|
1033
|
-
suffix = Base.table_name_suffix
|
1034
|
-
name = table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
|
1053
|
+
name = strip_table_name_prefix_and_suffix(table_name)
|
1035
1054
|
"#{name.singularize}_id"
|
1036
1055
|
end
|
1037
1056
|
|
@@ -1042,8 +1061,8 @@ module ActiveRecord
|
|
1042
1061
|
options
|
1043
1062
|
end
|
1044
1063
|
|
1045
|
-
def dump_schema_information
|
1046
|
-
versions =
|
1064
|
+
def dump_schema_information # :nodoc:
|
1065
|
+
versions = schema_migration.all_versions
|
1047
1066
|
insert_versions_sql(versions) if versions.any?
|
1048
1067
|
end
|
1049
1068
|
|
@@ -1053,13 +1072,13 @@ module ActiveRecord
|
|
1053
1072
|
|
1054
1073
|
def assume_migrated_upto_version(version, migrations_paths = nil)
|
1055
1074
|
unless migrations_paths.nil?
|
1056
|
-
ActiveSupport::Deprecation.warn(<<~MSG)
|
1075
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
1057
1076
|
Passing migrations_paths to #assume_migrated_upto_version is deprecated and will be removed in Rails 6.1.
|
1058
1077
|
MSG
|
1059
1078
|
end
|
1060
1079
|
|
1061
1080
|
version = version.to_i
|
1062
|
-
sm_table = quote_table_name(
|
1081
|
+
sm_table = quote_table_name(schema_migration.table_name)
|
1063
1082
|
|
1064
1083
|
migrated = migration_context.get_all_versions
|
1065
1084
|
versions = migration_context.migrations.map(&:version)
|
@@ -1099,7 +1118,7 @@ module ActiveRecord
|
|
1099
1118
|
if (0..6) === precision
|
1100
1119
|
column_type_sql << "(#{precision})"
|
1101
1120
|
else
|
1102
|
-
raise
|
1121
|
+
raise ArgumentError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6"
|
1103
1122
|
end
|
1104
1123
|
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
|
1105
1124
|
column_type_sql << "(#{limit})"
|
@@ -1129,6 +1148,10 @@ module ActiveRecord
|
|
1129
1148
|
def add_timestamps(table_name, options = {})
|
1130
1149
|
options[:null] = false if options[:null].nil?
|
1131
1150
|
|
1151
|
+
if !options.key?(:precision) && supports_datetime_with_precision?
|
1152
|
+
options[:precision] = 6
|
1153
|
+
end
|
1154
|
+
|
1132
1155
|
add_column table_name, :created_at, :datetime, options
|
1133
1156
|
add_column table_name, :updated_at, :datetime, options
|
1134
1157
|
end
|
@@ -1183,12 +1206,22 @@ module ActiveRecord
|
|
1183
1206
|
end
|
1184
1207
|
|
1185
1208
|
# Changes the comment for a table or removes it if +nil+.
|
1186
|
-
|
1209
|
+
#
|
1210
|
+
# Passing a hash containing +:from+ and +:to+ will make this change
|
1211
|
+
# reversible in migration:
|
1212
|
+
#
|
1213
|
+
# change_table_comment(:posts, from: "old_comment", to: "new_comment")
|
1214
|
+
def change_table_comment(table_name, comment_or_changes)
|
1187
1215
|
raise NotImplementedError, "#{self.class} does not support changing table comments"
|
1188
1216
|
end
|
1189
1217
|
|
1190
1218
|
# Changes the comment for a column or removes it if +nil+.
|
1191
|
-
|
1219
|
+
#
|
1220
|
+
# Passing a hash containing +:from+ and +:to+ will make this change
|
1221
|
+
# reversible in migration:
|
1222
|
+
#
|
1223
|
+
# change_column_comment(:posts, :state, from: "old_comment", to: "new_comment")
|
1224
|
+
def change_column_comment(table_name, column_name, comment_or_changes)
|
1192
1225
|
raise NotImplementedError, "#{self.class} does not support changing column comments"
|
1193
1226
|
end
|
1194
1227
|
|
@@ -1290,7 +1323,7 @@ module ActiveRecord
|
|
1290
1323
|
end
|
1291
1324
|
|
1292
1325
|
def create_table_definition(*args)
|
1293
|
-
TableDefinition.new(*args)
|
1326
|
+
TableDefinition.new(self, *args)
|
1294
1327
|
end
|
1295
1328
|
|
1296
1329
|
def create_alter_table(name)
|
@@ -1324,6 +1357,12 @@ module ActiveRecord
|
|
1324
1357
|
{ column: column_names }
|
1325
1358
|
end
|
1326
1359
|
|
1360
|
+
def strip_table_name_prefix_and_suffix(table_name)
|
1361
|
+
prefix = Base.table_name_prefix
|
1362
|
+
suffix = Base.table_name_suffix
|
1363
|
+
table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
|
1364
|
+
end
|
1365
|
+
|
1327
1366
|
def foreign_key_name(table_name, options)
|
1328
1367
|
options.fetch(:name) do
|
1329
1368
|
identifier = "#{table_name}_#{options.fetch(:column)}_fk"
|
@@ -1333,14 +1372,14 @@ module ActiveRecord
|
|
1333
1372
|
end
|
1334
1373
|
end
|
1335
1374
|
|
1336
|
-
def foreign_key_for(from_table,
|
1375
|
+
def foreign_key_for(from_table, **options)
|
1337
1376
|
return unless supports_foreign_keys?
|
1338
|
-
foreign_keys(from_table).detect { |fk| fk.defined_for?
|
1377
|
+
foreign_keys(from_table).detect { |fk| fk.defined_for?(options) }
|
1339
1378
|
end
|
1340
1379
|
|
1341
|
-
def foreign_key_for!(from_table,
|
1342
|
-
foreign_key_for(from_table,
|
1343
|
-
raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{
|
1380
|
+
def foreign_key_for!(from_table, to_table: nil, **options)
|
1381
|
+
foreign_key_for(from_table, to_table: to_table, **options) ||
|
1382
|
+
raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
|
1344
1383
|
end
|
1345
1384
|
|
1346
1385
|
def extract_foreign_key_action(specifier)
|
@@ -1366,11 +1405,37 @@ module ActiveRecord
|
|
1366
1405
|
default_or_changes
|
1367
1406
|
end
|
1368
1407
|
end
|
1408
|
+
alias :extract_new_comment_value :extract_new_default_value
|
1369
1409
|
|
1370
1410
|
def can_remove_index_by_name?(options)
|
1371
1411
|
options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
|
1372
1412
|
end
|
1373
1413
|
|
1414
|
+
def bulk_change_table(table_name, operations)
|
1415
|
+
sql_fragments = []
|
1416
|
+
non_combinable_operations = []
|
1417
|
+
|
1418
|
+
operations.each do |command, args|
|
1419
|
+
table, arguments = args.shift, args
|
1420
|
+
method = :"#{command}_for_alter"
|
1421
|
+
|
1422
|
+
if respond_to?(method, true)
|
1423
|
+
sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
|
1424
|
+
sql_fragments << sqls
|
1425
|
+
non_combinable_operations.concat(procs)
|
1426
|
+
else
|
1427
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
1428
|
+
non_combinable_operations.each(&:call)
|
1429
|
+
sql_fragments = []
|
1430
|
+
non_combinable_operations = []
|
1431
|
+
send(command, table, *arguments)
|
1432
|
+
end
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
1436
|
+
non_combinable_operations.each(&:call)
|
1437
|
+
end
|
1438
|
+
|
1374
1439
|
def add_column_for_alter(table_name, column_name, type, options = {})
|
1375
1440
|
td = create_table_definition(table_name)
|
1376
1441
|
cd = td.new_column_definition(column_name, type, options)
|
@@ -1386,7 +1451,7 @@ module ActiveRecord
|
|
1386
1451
|
end
|
1387
1452
|
|
1388
1453
|
def insert_versions_sql(versions)
|
1389
|
-
sm_table = quote_table_name(
|
1454
|
+
sm_table = quote_table_name(schema_migration.table_name)
|
1390
1455
|
|
1391
1456
|
if versions.is_a?(Array)
|
1392
1457
|
sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
|
@@ -98,9 +98,13 @@ module ActiveRecord
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def rollback_records
|
101
|
-
ite = records.uniq
|
101
|
+
ite = records.uniq(&:object_id)
|
102
|
+
already_run_callbacks = {}
|
102
103
|
while record = ite.shift
|
103
|
-
record.
|
104
|
+
trigger_callbacks = record.trigger_transactional_callbacks?
|
105
|
+
should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
|
106
|
+
already_run_callbacks[record] ||= trigger_callbacks
|
107
|
+
record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks)
|
104
108
|
end
|
105
109
|
ensure
|
106
110
|
ite.each do |i|
|
@@ -113,10 +117,14 @@ module ActiveRecord
|
|
113
117
|
end
|
114
118
|
|
115
119
|
def commit_records
|
116
|
-
ite = records.uniq
|
120
|
+
ite = records.uniq(&:object_id)
|
121
|
+
already_run_callbacks = {}
|
117
122
|
while record = ite.shift
|
118
123
|
if @run_commit_callbacks
|
119
|
-
record.
|
124
|
+
trigger_callbacks = record.trigger_transactional_callbacks?
|
125
|
+
should_run_callbacks = !already_run_callbacks[record] && trigger_callbacks
|
126
|
+
already_run_callbacks[record] ||= trigger_callbacks
|
127
|
+
record.committed!(should_run_callbacks: should_run_callbacks)
|
120
128
|
else
|
121
129
|
# if not running callbacks, only adds the record to the parent transaction
|
122
130
|
connection.add_transaction_record(record)
|
@@ -205,9 +213,12 @@ module ActiveRecord
|
|
205
213
|
run_commit_callbacks: run_commit_callbacks)
|
206
214
|
end
|
207
215
|
|
208
|
-
|
216
|
+
if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && options[:_lazy] != false
|
217
|
+
@has_unmaterialized_transactions = true
|
218
|
+
else
|
219
|
+
transaction.materialize!
|
220
|
+
end
|
209
221
|
@stack.push(transaction)
|
210
|
-
@has_unmaterialized_transactions = true if @connection.supports_lazy_transactions?
|
211
222
|
transaction
|
212
223
|
end
|
213
224
|
end
|