activerecord 7.1.0.beta1 → 7.1.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +85 -4
- data/lib/active_record/associations/collection_association.rb +1 -3
- data/lib/active_record/associations/collection_proxy.rb +1 -1
- data/lib/active_record/associations.rb +110 -110
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +20 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -9
- data/lib/active_record/connection_adapters/abstract_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +7 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/pool_manager.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +0 -16
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -5
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -8
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +25 -29
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -6
- data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -4
- data/lib/active_record/core.rb +7 -9
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +1 -1
- data/lib/active_record/errors.rb +19 -0
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +8 -8
- data/lib/active_record/nested_attributes.rb +0 -5
- data/lib/active_record/normalization.rb +2 -1
- data/lib/active_record/persistence.rb +1 -1
- data/lib/active_record/querying.rb +2 -2
- data/lib/active_record/railtie.rb +1 -1
- data/lib/active_record/reflection.rb +10 -16
- data/lib/active_record/relation/calculations.rb +8 -8
- data/lib/active_record/relation/finder_methods.rb +3 -12
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/schema_dumper.rb +9 -4
- data/lib/active_record/tasks/sqlite_database_tasks.rb +1 -0
- metadata +9 -9
@@ -16,7 +16,7 @@ module ActiveRecord
|
|
16
16
|
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
17
17
|
:options_include_default?, :supports_indexes_in_create?, :use_foreign_keys?,
|
18
18
|
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
|
19
|
-
:supports_index_include?, :supports_exclusion_constraints?, :
|
19
|
+
:supports_index_include?, :supports_exclusion_constraints?, :supports_unique_constraints?,
|
20
20
|
:supports_nulls_not_distinct?,
|
21
21
|
to: :@conn, private: true
|
22
22
|
|
@@ -65,8 +65,8 @@ module ActiveRecord
|
|
65
65
|
statements.concat(o.exclusion_constraints.map { |exc| accept exc })
|
66
66
|
end
|
67
67
|
|
68
|
-
if
|
69
|
-
statements.concat(o.
|
68
|
+
if supports_unique_constraints?
|
69
|
+
statements.concat(o.unique_constraints.map { |exc| accept exc })
|
70
70
|
end
|
71
71
|
|
72
72
|
create_sql << "(#{statements.join(', ')})" if statements.present?
|
@@ -78,21 +78,24 @@ module ActiveRecord
|
|
78
78
|
def initialize(payload = {})
|
79
79
|
@handle = nil
|
80
80
|
@started = false
|
81
|
-
@payload =
|
81
|
+
@payload = nil
|
82
|
+
@base_payload = payload
|
82
83
|
end
|
83
84
|
|
84
85
|
def start
|
85
86
|
return if @started
|
86
87
|
@started = true
|
87
88
|
|
89
|
+
@payload = @base_payload.dup
|
88
90
|
@handle = ActiveSupport::Notifications.instrumenter.build_handle("transaction.active_record", @payload)
|
89
91
|
@handle.start
|
90
92
|
end
|
91
93
|
|
92
|
-
def finish
|
94
|
+
def finish(outcome)
|
93
95
|
return unless @started
|
94
96
|
@started = false
|
95
97
|
|
98
|
+
@payload[:outcome] = outcome
|
96
99
|
@handle.finish
|
97
100
|
end
|
98
101
|
end
|
@@ -163,7 +166,7 @@ module ActiveRecord
|
|
163
166
|
end
|
164
167
|
|
165
168
|
def incomplete!
|
166
|
-
@instrumenter.finish
|
169
|
+
@instrumenter.finish(:incomplete)
|
167
170
|
end
|
168
171
|
|
169
172
|
def materialize!
|
@@ -334,7 +337,7 @@ module ActiveRecord
|
|
334
337
|
def restart
|
335
338
|
return unless materialized?
|
336
339
|
|
337
|
-
@instrumenter.finish
|
340
|
+
@instrumenter.finish(:restart)
|
338
341
|
@instrumenter.start
|
339
342
|
|
340
343
|
connection.rollback_to_savepoint(savepoint_name)
|
@@ -345,13 +348,13 @@ module ActiveRecord
|
|
345
348
|
connection.rollback_to_savepoint(savepoint_name) if materialized?
|
346
349
|
end
|
347
350
|
@state.rollback!
|
348
|
-
@instrumenter.finish
|
351
|
+
@instrumenter.finish(:rollback)
|
349
352
|
end
|
350
353
|
|
351
354
|
def commit
|
352
355
|
connection.release_savepoint(savepoint_name) if materialized?
|
353
356
|
@state.commit!
|
354
|
-
@instrumenter.finish
|
357
|
+
@instrumenter.finish(:commit)
|
355
358
|
end
|
356
359
|
|
357
360
|
def full_rollback?; false; end
|
@@ -372,7 +375,7 @@ module ActiveRecord
|
|
372
375
|
def restart
|
373
376
|
return unless materialized?
|
374
377
|
|
375
|
-
@instrumenter.finish
|
378
|
+
@instrumenter.finish(:restart)
|
376
379
|
|
377
380
|
if connection.supports_restart_db_transaction?
|
378
381
|
@instrumenter.start
|
@@ -386,13 +389,13 @@ module ActiveRecord
|
|
386
389
|
def rollback
|
387
390
|
connection.rollback_db_transaction if materialized?
|
388
391
|
@state.full_rollback!
|
389
|
-
@instrumenter.finish
|
392
|
+
@instrumenter.finish(:rollback)
|
390
393
|
end
|
391
394
|
|
392
395
|
def commit
|
393
396
|
connection.commit_db_transaction if materialized?
|
394
397
|
@state.full_commit!
|
395
|
-
@instrumenter.finish
|
398
|
+
@instrumenter.finish(:commit)
|
396
399
|
end
|
397
400
|
end
|
398
401
|
|
@@ -531,6 +531,13 @@ module ActiveRecord
|
|
531
531
|
expression = row["expression"]
|
532
532
|
expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
|
533
533
|
expression = strip_whitespace_characters(expression)
|
534
|
+
|
535
|
+
unless mariadb?
|
536
|
+
# MySQL returns check constraints expression in an already escaped form.
|
537
|
+
# This leads to duplicate escaping later (e.g. when the expression is used in the SchemaDumper).
|
538
|
+
expression = expression.gsub("\\'", "'")
|
539
|
+
end
|
540
|
+
|
534
541
|
CheckConstraintDefinition.new(table_name, expression, options)
|
535
542
|
end
|
536
543
|
else
|
@@ -36,7 +36,7 @@ module ActiveRecord
|
|
36
36
|
end
|
37
37
|
|
38
38
|
if row[:Expression]
|
39
|
-
expression = row[:Expression]
|
39
|
+
expression = row[:Expression].gsub("\\'", "'")
|
40
40
|
expression = +"(#{expression})" unless expression.start_with?("(")
|
41
41
|
indexes.last[-2] << expression
|
42
42
|
indexes.last[-1][:expressions] ||= {}
|
@@ -75,22 +75,6 @@ module ActiveRecord
|
|
75
75
|
end
|
76
76
|
alias :exec_update :exec_delete
|
77
77
|
|
78
|
-
def sql_for_insert(sql, pk, binds, returning) # :nodoc:
|
79
|
-
if pk.nil?
|
80
|
-
# Extract the table from the insert sql. Yuck.
|
81
|
-
table_ref = extract_table_ref_from_insert_sql(sql)
|
82
|
-
pk = primary_key(table_ref) if table_ref
|
83
|
-
end
|
84
|
-
|
85
|
-
returning_columns = returning || Array(pk)
|
86
|
-
|
87
|
-
returning_columns_statement = returning_columns.map { |c| quote_column_name(c) }.join(", ")
|
88
|
-
sql = "#{sql} RETURNING #{returning_columns_statement}" if returning_columns.any?
|
89
|
-
|
90
|
-
super
|
91
|
-
end
|
92
|
-
private :sql_for_insert
|
93
|
-
|
94
78
|
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) # :nodoc:
|
95
79
|
if use_insert_returning? || pk == false
|
96
80
|
super
|
@@ -12,8 +12,8 @@ module ActiveRecord
|
|
12
12
|
sql << o.constraint_validations.map { |fk| visit_ValidateConstraint fk }.join(" ")
|
13
13
|
sql << o.exclusion_constraint_adds.map { |con| visit_AddExclusionConstraint con }.join(" ")
|
14
14
|
sql << o.exclusion_constraint_drops.map { |con| visit_DropExclusionConstraint con }.join(" ")
|
15
|
-
sql << o.
|
16
|
-
sql << o.
|
15
|
+
sql << o.unique_constraint_adds.map { |con| visit_AddUniqueConstraint con }.join(" ")
|
16
|
+
sql << o.unique_constraint_drops.map { |con| visit_DropUniqueConstraint con }.join(" ")
|
17
17
|
end
|
18
18
|
|
19
19
|
def visit_AddForeignKey(o)
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
sql.join(" ")
|
50
50
|
end
|
51
51
|
|
52
|
-
def
|
52
|
+
def visit_UniqueConstraintDefinition(o)
|
53
53
|
column_name = Array(o.column).map { |column| quote_column_name(column) }.join(", ")
|
54
54
|
|
55
55
|
sql = ["CONSTRAINT"]
|
@@ -77,11 +77,11 @@ module ActiveRecord
|
|
77
77
|
"DROP CONSTRAINT #{quote_column_name(name)}"
|
78
78
|
end
|
79
79
|
|
80
|
-
def
|
80
|
+
def visit_AddUniqueConstraint(o)
|
81
81
|
"ADD #{accept(o)}"
|
82
82
|
end
|
83
83
|
|
84
|
-
def
|
84
|
+
def visit_DropUniqueConstraint(name)
|
85
85
|
"DROP CONSTRAINT #{quote_column_name(name)}"
|
86
86
|
end
|
87
87
|
|
@@ -211,7 +211,7 @@ module ActiveRecord
|
|
211
211
|
end
|
212
212
|
end
|
213
213
|
|
214
|
-
|
214
|
+
UniqueConstraintDefinition = Struct.new(:table_name, :column, :options) do
|
215
215
|
def name
|
216
216
|
options[:name]
|
217
217
|
end
|
@@ -239,12 +239,12 @@ module ActiveRecord
|
|
239
239
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
240
240
|
include ColumnMethods
|
241
241
|
|
242
|
-
attr_reader :exclusion_constraints, :
|
242
|
+
attr_reader :exclusion_constraints, :unique_constraints, :unlogged
|
243
243
|
|
244
244
|
def initialize(*, **)
|
245
245
|
super
|
246
246
|
@exclusion_constraints = []
|
247
|
-
@
|
247
|
+
@unique_constraints = []
|
248
248
|
@unlogged = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables
|
249
249
|
end
|
250
250
|
|
@@ -252,8 +252,8 @@ module ActiveRecord
|
|
252
252
|
exclusion_constraints << new_exclusion_constraint_definition(expression, options)
|
253
253
|
end
|
254
254
|
|
255
|
-
def
|
256
|
-
|
255
|
+
def unique_constraint(column_name, **options)
|
256
|
+
unique_constraints << new_unique_constraint_definition(column_name, options)
|
257
257
|
end
|
258
258
|
|
259
259
|
def new_exclusion_constraint_definition(expression, options) # :nodoc:
|
@@ -261,9 +261,9 @@ module ActiveRecord
|
|
261
261
|
ExclusionConstraintDefinition.new(name, expression, options)
|
262
262
|
end
|
263
263
|
|
264
|
-
def
|
265
|
-
options = @conn.
|
266
|
-
|
264
|
+
def new_unique_constraint_definition(column_name, options) # :nodoc:
|
265
|
+
options = @conn.unique_constraint_options(name, column_name, options)
|
266
|
+
UniqueConstraintDefinition.new(name, column_name, options)
|
267
267
|
end
|
268
268
|
|
269
269
|
def new_column_definition(name, type, **options) # :nodoc:
|
@@ -315,36 +315,36 @@ module ActiveRecord
|
|
315
315
|
@base.remove_exclusion_constraint(name, *args)
|
316
316
|
end
|
317
317
|
|
318
|
-
# Adds
|
318
|
+
# Adds a unique constraint.
|
319
319
|
#
|
320
|
-
# t.
|
320
|
+
# t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred)
|
321
321
|
#
|
322
|
-
# See {connection.
|
323
|
-
def
|
324
|
-
@base.
|
322
|
+
# See {connection.add_unique_constraint}[rdoc-ref:SchemaStatements#add_unique_constraint]
|
323
|
+
def unique_constraint(*args)
|
324
|
+
@base.add_unique_constraint(name, *args)
|
325
325
|
end
|
326
326
|
|
327
327
|
# Removes the given unique constraint from the table.
|
328
328
|
#
|
329
|
-
# t.
|
329
|
+
# t.remove_unique_constraint(name: "unique_position")
|
330
330
|
#
|
331
|
-
# See {connection.
|
332
|
-
def
|
333
|
-
@base.
|
331
|
+
# See {connection.remove_unique_constraint}[rdoc-ref:SchemaStatements#remove_unique_constraint]
|
332
|
+
def remove_unique_constraint(*args)
|
333
|
+
@base.remove_unique_constraint(name, *args)
|
334
334
|
end
|
335
335
|
end
|
336
336
|
|
337
337
|
# = Active Record PostgreSQL Adapter Alter \Table
|
338
338
|
class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
|
339
|
-
attr_reader :constraint_validations, :exclusion_constraint_adds, :exclusion_constraint_drops, :
|
339
|
+
attr_reader :constraint_validations, :exclusion_constraint_adds, :exclusion_constraint_drops, :unique_constraint_adds, :unique_constraint_drops
|
340
340
|
|
341
341
|
def initialize(td)
|
342
342
|
super
|
343
343
|
@constraint_validations = []
|
344
344
|
@exclusion_constraint_adds = []
|
345
345
|
@exclusion_constraint_drops = []
|
346
|
-
@
|
347
|
-
@
|
346
|
+
@unique_constraint_adds = []
|
347
|
+
@unique_constraint_drops = []
|
348
348
|
end
|
349
349
|
|
350
350
|
def validate_constraint(name)
|
@@ -359,12 +359,12 @@ module ActiveRecord
|
|
359
359
|
@exclusion_constraint_drops << constraint_name
|
360
360
|
end
|
361
361
|
|
362
|
-
def
|
363
|
-
@
|
362
|
+
def add_unique_constraint(column_name, options)
|
363
|
+
@unique_constraint_adds << @td.new_unique_constraint_definition(column_name, options)
|
364
364
|
end
|
365
365
|
|
366
|
-
def
|
367
|
-
@
|
366
|
+
def drop_unique_constraint(unique_constraint_name)
|
367
|
+
@unique_constraint_drops << unique_constraint_name
|
368
368
|
end
|
369
369
|
end
|
370
370
|
end
|
@@ -28,6 +28,17 @@ module ActiveRecord
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
def schemas(stream)
|
32
|
+
schema_names = @connection.schema_names - ["public"]
|
33
|
+
|
34
|
+
if schema_names.any?
|
35
|
+
schema_names.sort.each do |name|
|
36
|
+
stream.puts " create_schema #{name.inspect}"
|
37
|
+
end
|
38
|
+
stream.puts
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
31
42
|
def exclusion_constraints_in_create(table, stream)
|
32
43
|
if (exclusion_constraints = @connection.exclusion_constraints(table)).any?
|
33
44
|
add_exclusion_constraint_statements = exclusion_constraints.map do |exclusion_constraint|
|
@@ -50,23 +61,23 @@ module ActiveRecord
|
|
50
61
|
end
|
51
62
|
end
|
52
63
|
|
53
|
-
def
|
54
|
-
if (
|
55
|
-
|
64
|
+
def unique_constraints_in_create(table, stream)
|
65
|
+
if (unique_constraints = @connection.unique_constraints(table)).any?
|
66
|
+
add_unique_constraint_statements = unique_constraints.map do |unique_constraint|
|
56
67
|
parts = [
|
57
|
-
"t.
|
68
|
+
"t.unique_constraint #{unique_constraint.column.inspect}"
|
58
69
|
]
|
59
70
|
|
60
|
-
parts << "deferrable: #{
|
71
|
+
parts << "deferrable: #{unique_constraint.deferrable.inspect}" if unique_constraint.deferrable
|
61
72
|
|
62
|
-
if
|
63
|
-
parts << "name: #{
|
73
|
+
if unique_constraint.export_name_on_schema_dump?
|
74
|
+
parts << "name: #{unique_constraint.name.inspect}"
|
64
75
|
end
|
65
76
|
|
66
77
|
" #{parts.join(', ')}"
|
67
78
|
end
|
68
79
|
|
69
|
-
stream.puts
|
80
|
+
stream.puts add_unique_constraint_statements.sort.join("\n")
|
70
81
|
end
|
71
82
|
end
|
72
83
|
|
@@ -640,12 +640,12 @@ module ActiveRecord
|
|
640
640
|
end
|
641
641
|
|
642
642
|
# Returns an array of unique constraints for the given table.
|
643
|
-
# The unique constraints are represented as
|
644
|
-
def
|
643
|
+
# The unique constraints are represented as UniqueConstraintDefinition objects.
|
644
|
+
def unique_constraints(table_name)
|
645
645
|
scope = quoted_scope(table_name)
|
646
646
|
|
647
647
|
unique_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
|
648
|
-
SELECT c.conname, c.
|
648
|
+
SELECT c.conname, c.conrelid, c.conkey, c.condeferrable, c.condeferred
|
649
649
|
FROM pg_constraint c
|
650
650
|
JOIN pg_class t ON c.conrelid = t.oid
|
651
651
|
JOIN pg_namespace n ON n.oid = c.connamespace
|
@@ -655,21 +655,17 @@ module ActiveRecord
|
|
655
655
|
SQL
|
656
656
|
|
657
657
|
unique_info.map do |row|
|
658
|
-
|
658
|
+
conkey = row["conkey"].delete("{}").split(",").map(&:to_i)
|
659
|
+
columns = column_names_from_column_numbers(row["conrelid"], conkey)
|
659
660
|
|
660
|
-
|
661
|
-
SELECT a.attname
|
662
|
-
FROM pg_attribute a
|
663
|
-
WHERE a.attrelid = #{row['conindid']}
|
664
|
-
ORDER BY a.attnum
|
665
|
-
SQL
|
661
|
+
deferrable = extract_constraint_deferrable(row["condeferrable"], row["condeferred"])
|
666
662
|
|
667
663
|
options = {
|
668
664
|
name: row["conname"],
|
669
665
|
deferrable: deferrable
|
670
666
|
}
|
671
667
|
|
672
|
-
|
668
|
+
UniqueConstraintDefinition.new(table_name, columns, options)
|
673
669
|
end
|
674
670
|
end
|
675
671
|
|
@@ -721,7 +717,7 @@ module ActiveRecord
|
|
721
717
|
|
722
718
|
# Adds a new unique constraint to the table.
|
723
719
|
#
|
724
|
-
#
|
720
|
+
# add_unique_constraint :sections, [:position], deferrable: :deferred, name: "unique_position"
|
725
721
|
#
|
726
722
|
# generates:
|
727
723
|
#
|
@@ -729,7 +725,7 @@ module ActiveRecord
|
|
729
725
|
#
|
730
726
|
# If you want to change an existing unique index to deferrable, you can use :using_index to create deferrable unique constraints.
|
731
727
|
#
|
732
|
-
#
|
728
|
+
# add_unique_constraint :sections, deferrable: :deferred, name: "unique_position", using_index: "index_sections_on_position"
|
733
729
|
#
|
734
730
|
# The +options+ hash can include the following keys:
|
735
731
|
# [<tt>:name</tt>]
|
@@ -738,15 +734,15 @@ module ActiveRecord
|
|
738
734
|
# Specify whether or not the unique constraint should be deferrable. Valid values are +false+ or +:immediate+ or +:deferred+ to specify the default behavior. Defaults to +false+.
|
739
735
|
# [<tt>:using_index</tt>]
|
740
736
|
# To specify an existing unique index name. Defaults to +nil+.
|
741
|
-
def
|
742
|
-
options =
|
737
|
+
def add_unique_constraint(table_name, column_name = nil, **options)
|
738
|
+
options = unique_constraint_options(table_name, column_name, options)
|
743
739
|
at = create_alter_table(table_name)
|
744
|
-
at.
|
740
|
+
at.add_unique_constraint(column_name, options)
|
745
741
|
|
746
742
|
execute schema_creation.accept(at)
|
747
743
|
end
|
748
744
|
|
749
|
-
def
|
745
|
+
def unique_constraint_options(table_name, column_name, options) # :nodoc:
|
750
746
|
assert_valid_deferrable(options[:deferrable])
|
751
747
|
|
752
748
|
if column_name && options[:using_index]
|
@@ -754,22 +750,22 @@ module ActiveRecord
|
|
754
750
|
end
|
755
751
|
|
756
752
|
options = options.dup
|
757
|
-
options[:name] ||=
|
753
|
+
options[:name] ||= unique_constraint_name(table_name, column: column_name, **options)
|
758
754
|
options
|
759
755
|
end
|
760
756
|
|
761
757
|
# Removes the given unique constraint from the table.
|
762
758
|
#
|
763
|
-
#
|
759
|
+
# remove_unique_constraint :sections, name: "unique_position"
|
764
760
|
#
|
765
761
|
# The +column_name+ parameter will be ignored if present. It can be helpful
|
766
762
|
# to provide this in a migration's +change+ method so it can be reverted.
|
767
|
-
# In that case, +column_name+ will be used by #
|
768
|
-
def
|
769
|
-
unique_name_to_delete =
|
763
|
+
# In that case, +column_name+ will be used by #add_unique_constraint.
|
764
|
+
def remove_unique_constraint(table_name, column_name = nil, **options)
|
765
|
+
unique_name_to_delete = unique_constraint_for!(table_name, column: column_name, **options).name
|
770
766
|
|
771
767
|
at = create_alter_table(table_name)
|
772
|
-
at.
|
768
|
+
at.drop_unique_constraint(unique_name_to_delete)
|
773
769
|
|
774
770
|
execute schema_creation.accept(at)
|
775
771
|
end
|
@@ -1042,7 +1038,7 @@ module ActiveRecord
|
|
1042
1038
|
raise(ArgumentError, "Table '#{table_name}' has no exclusion constraint for #{expression || options}")
|
1043
1039
|
end
|
1044
1040
|
|
1045
|
-
def
|
1041
|
+
def unique_constraint_name(table_name, **options)
|
1046
1042
|
options.fetch(:name) do
|
1047
1043
|
column_or_index = Array(options[:column] || options[:using_index]).map(&:to_s)
|
1048
1044
|
identifier = "#{table_name}_#{column_or_index * '_and_'}_unique"
|
@@ -1052,13 +1048,13 @@ module ActiveRecord
|
|
1052
1048
|
end
|
1053
1049
|
end
|
1054
1050
|
|
1055
|
-
def
|
1056
|
-
name =
|
1057
|
-
|
1051
|
+
def unique_constraint_for(table_name, **options)
|
1052
|
+
name = unique_constraint_name(table_name, **options) unless options.key?(:column)
|
1053
|
+
unique_constraints(table_name).detect { |unique_constraint| unique_constraint.defined_for?(name: name, **options) }
|
1058
1054
|
end
|
1059
1055
|
|
1060
|
-
def
|
1061
|
-
|
1056
|
+
def unique_constraint_for!(table_name, column: nil, **options)
|
1057
|
+
unique_constraint_for(table_name, column: column, **options) ||
|
1062
1058
|
raise(ArgumentError, "Table '#{table_name}' has no unique constraint for #{column || options}")
|
1063
1059
|
end
|
1064
1060
|
|
@@ -226,7 +226,7 @@ module ActiveRecord
|
|
226
226
|
true
|
227
227
|
end
|
228
228
|
|
229
|
-
def
|
229
|
+
def supports_unique_constraints?
|
230
230
|
true
|
231
231
|
end
|
232
232
|
|
@@ -1089,11 +1089,6 @@ module ActiveRecord
|
|
1089
1089
|
SQL
|
1090
1090
|
end
|
1091
1091
|
|
1092
|
-
def extract_table_ref_from_insert_sql(sql)
|
1093
|
-
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
1094
|
-
$1.strip if $1
|
1095
|
-
end
|
1096
|
-
|
1097
1092
|
def arel_visitor
|
1098
1093
|
Arel::Visitors::PostgreSQL.new(self)
|
1099
1094
|
end
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
cache(connection).indexes(connection, table_name)
|
67
67
|
end
|
68
68
|
|
69
|
-
def database_version(connection)
|
69
|
+
def database_version(connection) # :nodoc:
|
70
70
|
cache(connection).database_version(connection)
|
71
71
|
end
|
72
72
|
|
@@ -196,7 +196,7 @@ module ActiveRecord
|
|
196
196
|
@schema_reflection.indexes(@connection, table_name)
|
197
197
|
end
|
198
198
|
|
199
|
-
def database_version
|
199
|
+
def database_version # :nodoc:
|
200
200
|
@schema_reflection.database_version(@connection)
|
201
201
|
end
|
202
202
|
|
@@ -138,10 +138,6 @@ module ActiveRecord
|
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
|
-
def last_inserted_id(result)
|
142
|
-
@raw_connection.last_insert_row_id
|
143
|
-
end
|
144
|
-
|
145
141
|
def build_fixture_statements(fixture_set)
|
146
142
|
fixture_set.flat_map do |table_name, fixtures|
|
147
143
|
next if fixtures.empty?
|
@@ -152,6 +148,10 @@ module ActiveRecord
|
|
152
148
|
def build_truncate_statement(table_name)
|
153
149
|
"DELETE FROM #{quote_table_name(table_name)}"
|
154
150
|
end
|
151
|
+
|
152
|
+
def returning_column_values(result)
|
153
|
+
result.rows.first
|
154
|
+
end
|
155
155
|
end
|
156
156
|
end
|
157
157
|
end
|