Skip to content

Commit

Permalink
Rename back unique keys to unique constraints
Browse files Browse the repository at this point in the history
As we (I and @yahonda) talked about the naming in person, naming unique
constraints as unique keys is very confusing to me.
All documents and descriptions says it's unique constraints, but naming
unique keys leads to misunderstanding it's a short-hand of unique
indexes.
Just naming it unique constraints is not misleading.
  • Loading branch information
kamipo committed Sep 26, 2023
1 parent c32813d commit b2790b6
Show file tree
Hide file tree
Showing 17 changed files with 332 additions and 332 deletions.
14 changes: 7 additions & 7 deletions activerecord/CHANGELOG.md
Expand Up @@ -503,7 +503,7 @@

Because `deferrable: true` and `deferrable: :deferred` are hard to understand.
Both true and :deferred are truthy values.
This behavior is the same as the deferrable option of the add_unique_key method, added in #46192.
This behavior is the same as the deferrable option of the add_unique_constraint method, added in #46192.

*Hiroyuki Ishii*

Expand Down Expand Up @@ -720,8 +720,8 @@
* Add support for unique constraints (PostgreSQL-only).

```ruby
add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
remove_unique_key :sections, name: "unique_section_position"
add_unique_constraint :sections, [:position], deferrable: :deferred, name: "unique_section_position"
remove_unique_constraint :sections, name: "unique_section_position"
```

See PostgreSQL's [Unique Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS) documentation for more on unique constraints.
Expand All @@ -746,11 +746,11 @@
Using the default behavior, the transaction would fail when executing the
first `UPDATE` statement.

By passing the `:deferrable` option to the `add_unique_key` statement in
By passing the `:deferrable` option to the `add_unique_constraint` statement in
migrations, it's possible to defer this check.

```ruby
add_unique_key :items, [:position], deferrable: :immediate
add_unique_constraint :items, [:position], deferrable: :immediate
```

Passing `deferrable: :immediate` does not change the behaviour of the previous example,
Expand All @@ -761,14 +761,14 @@
check (after the statement), to a deferred check (after the transaction):

```ruby
add_unique_key :items, [:position], deferrable: :deferred
add_unique_constraint :items, [:position], deferrable: :deferred
```

If you want to change an existing unique index to deferrable, you can use :using_index
to create deferrable unique constraints.

```ruby
add_unique_key :items, deferrable: :deferred, using_index: "index_items_on_position"
add_unique_constraint :items, deferrable: :deferred, using_index: "index_items_on_position"
```

*Hiroyuki Ishii*
Expand Down
Expand Up @@ -16,7 +16,7 @@ def accept(o)
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
:options_include_default?, :supports_indexes_in_create?, :use_foreign_keys?,
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
:supports_index_include?, :supports_exclusion_constraints?, :supports_unique_keys?,
:supports_index_include?, :supports_exclusion_constraints?, :supports_unique_constraints?,
:supports_nulls_not_distinct?,
to: :@conn, private: true

Expand Down Expand Up @@ -65,8 +65,8 @@ def visit_TableDefinition(o)
statements.concat(o.exclusion_constraints.map { |exc| accept exc })
end

if supports_unique_keys?
statements.concat(o.unique_keys.map { |exc| accept exc })
if supports_unique_constraints?
statements.concat(o.unique_constraints.map { |exc| accept exc })
end

create_sql << "(#{statements.join(', ')})" if statements.present?
Expand Down
Expand Up @@ -498,7 +498,7 @@ def supports_exclusion_constraints?
end

# Does this adapter support creating unique constraints?
def supports_unique_keys?
def supports_unique_constraints?
false
end

Expand Down
Expand Up @@ -12,8 +12,8 @@ def visit_AlterTable(o)
sql << o.constraint_validations.map { |fk| visit_ValidateConstraint fk }.join(" ")
sql << o.exclusion_constraint_adds.map { |con| visit_AddExclusionConstraint con }.join(" ")
sql << o.exclusion_constraint_drops.map { |con| visit_DropExclusionConstraint con }.join(" ")
sql << o.unique_key_adds.map { |con| visit_AddUniqueKey con }.join(" ")
sql << o.unique_key_drops.map { |con| visit_DropUniqueKey con }.join(" ")
sql << o.unique_constraint_adds.map { |con| visit_AddUniqueConstraint con }.join(" ")
sql << o.unique_constraint_drops.map { |con| visit_DropUniqueConstraint con }.join(" ")
end

def visit_AddForeignKey(o)
Expand Down Expand Up @@ -49,7 +49,7 @@ def visit_ExclusionConstraintDefinition(o)
sql.join(" ")
end

def visit_UniqueKeyDefinition(o)
def visit_UniqueConstraintDefinition(o)
column_name = Array(o.column).map { |column| quote_column_name(column) }.join(", ")

sql = ["CONSTRAINT"]
Expand Down Expand Up @@ -77,11 +77,11 @@ def visit_DropExclusionConstraint(name)
"DROP CONSTRAINT #{quote_column_name(name)}"
end

def visit_AddUniqueKey(o)
def visit_AddUniqueConstraint(o)
"ADD #{accept(o)}"
end

def visit_DropUniqueKey(name)
def visit_DropUniqueConstraint(name)
"DROP CONSTRAINT #{quote_column_name(name)}"
end

Expand Down
Expand Up @@ -211,7 +211,7 @@ def export_name_on_schema_dump?
end
end

UniqueKeyDefinition = Struct.new(:table_name, :column, :options) do
UniqueConstraintDefinition = Struct.new(:table_name, :column, :options) do
def name
options[:name]
end
Expand Down Expand Up @@ -239,31 +239,31 @@ def defined_for?(name: nil, column: nil, **options)
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
include ColumnMethods

attr_reader :exclusion_constraints, :unique_keys, :unlogged
attr_reader :exclusion_constraints, :unique_constraints, :unlogged

def initialize(*, **)
super
@exclusion_constraints = []
@unique_keys = []
@unique_constraints = []
@unlogged = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables
end

def exclusion_constraint(expression, **options)
exclusion_constraints << new_exclusion_constraint_definition(expression, options)
end

def unique_key(column_name, **options)
unique_keys << new_unique_key_definition(column_name, options)
def unique_constraint(column_name, **options)
unique_constraints << new_unique_constraint_definition(column_name, options)
end

def new_exclusion_constraint_definition(expression, options) # :nodoc:
options = @conn.exclusion_constraint_options(name, expression, options)
ExclusionConstraintDefinition.new(name, expression, options)
end

def new_unique_key_definition(column_name, options) # :nodoc:
options = @conn.unique_key_options(name, column_name, options)
UniqueKeyDefinition.new(name, column_name, options)
def new_unique_constraint_definition(column_name, options) # :nodoc:
options = @conn.unique_constraint_options(name, column_name, options)
UniqueConstraintDefinition.new(name, column_name, options)
end

def new_column_definition(name, type, **options) # :nodoc:
Expand Down Expand Up @@ -317,34 +317,34 @@ def remove_exclusion_constraint(*args)

# Adds an unique constraint.
#
# t.unique_key(:position, name: 'unique_position', deferrable: :deferred)
# t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred)
#
# See {connection.add_unique_key}[rdoc-ref:SchemaStatements#add_unique_key]
def unique_key(*args)
@base.add_unique_key(name, *args)
# See {connection.add_unique_constraint}[rdoc-ref:SchemaStatements#add_unique_constraint]
def unique_constraint(*args)
@base.add_unique_constraint(name, *args)
end

# Removes the given unique constraint from the table.
#
# t.remove_unique_key(name: "unique_position")
# t.remove_unique_constraint(name: "unique_position")
#
# See {connection.remove_unique_key}[rdoc-ref:SchemaStatements#remove_unique_key]
def remove_unique_key(*args)
@base.remove_unique_key(name, *args)
# See {connection.remove_unique_constraint}[rdoc-ref:SchemaStatements#remove_unique_constraint]
def remove_unique_constraint(*args)
@base.remove_unique_constraint(name, *args)
end
end

# = Active Record PostgreSQL Adapter Alter \Table
class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
attr_reader :constraint_validations, :exclusion_constraint_adds, :exclusion_constraint_drops, :unique_key_adds, :unique_key_drops
attr_reader :constraint_validations, :exclusion_constraint_adds, :exclusion_constraint_drops, :unique_constraint_adds, :unique_constraint_drops

def initialize(td)
super
@constraint_validations = []
@exclusion_constraint_adds = []
@exclusion_constraint_drops = []
@unique_key_adds = []
@unique_key_drops = []
@unique_constraint_adds = []
@unique_constraint_drops = []
end

def validate_constraint(name)
Expand All @@ -359,12 +359,12 @@ def drop_exclusion_constraint(constraint_name)
@exclusion_constraint_drops << constraint_name
end

def add_unique_key(column_name, options)
@unique_key_adds << @td.new_unique_key_definition(column_name, options)
def add_unique_constraint(column_name, options)
@unique_constraint_adds << @td.new_unique_constraint_definition(column_name, options)
end

def drop_unique_key(unique_key_name)
@unique_key_drops << unique_key_name
def drop_unique_constraint(unique_constraint_name)
@unique_constraint_drops << unique_constraint_name
end
end
end
Expand Down
Expand Up @@ -61,23 +61,23 @@ def exclusion_constraints_in_create(table, stream)
end
end

def unique_keys_in_create(table, stream)
if (unique_keys = @connection.unique_keys(table)).any?
add_unique_key_statements = unique_keys.map do |unique_key|
def unique_constraints_in_create(table, stream)
if (unique_constraints = @connection.unique_constraints(table)).any?
add_unique_constraint_statements = unique_constraints.map do |unique_constraint|
parts = [
"t.unique_key #{unique_key.column.inspect}"
"t.unique_constraint #{unique_constraint.column.inspect}"
]

parts << "deferrable: #{unique_key.deferrable.inspect}" if unique_key.deferrable
parts << "deferrable: #{unique_constraint.deferrable.inspect}" if unique_constraint.deferrable

if unique_key.export_name_on_schema_dump?
parts << "name: #{unique_key.name.inspect}"
if unique_constraint.export_name_on_schema_dump?
parts << "name: #{unique_constraint.name.inspect}"
end

" #{parts.join(', ')}"
end

stream.puts add_unique_key_statements.sort.join("\n")
stream.puts add_unique_constraint_statements.sort.join("\n")
end
end

Expand Down
Expand Up @@ -640,8 +640,8 @@ def exclusion_constraints(table_name)
end

# Returns an array of unique constraints for the given table.
# The unique constraints are represented as UniqueKeyDefinition objects.
def unique_keys(table_name)
# The unique constraints are represented as UniqueConstraintDefinition objects.
def unique_constraints(table_name)
scope = quoted_scope(table_name)

unique_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
Expand All @@ -665,7 +665,7 @@ def unique_keys(table_name)
deferrable: deferrable
}

UniqueKeyDefinition.new(table_name, columns, options)
UniqueConstraintDefinition.new(table_name, columns, options)
end
end

Expand Down Expand Up @@ -717,15 +717,15 @@ def remove_exclusion_constraint(table_name, expression = nil, **options)

# Adds a new unique constraint to the table.
#
# add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_position"
# add_unique_constraint :sections, [:position], deferrable: :deferred, name: "unique_position"
#
# generates:
#
# ALTER TABLE "sections" ADD CONSTRAINT unique_position UNIQUE (position) DEFERRABLE INITIALLY DEFERRED
#
# If you want to change an existing unique index to deferrable, you can use :using_index to create deferrable unique constraints.
#
# add_unique_key :sections, deferrable: :deferred, name: "unique_position", using_index: "index_sections_on_position"
# add_unique_constraint :sections, deferrable: :deferred, name: "unique_position", using_index: "index_sections_on_position"
#
# The +options+ hash can include the following keys:
# [<tt>:name</tt>]
Expand All @@ -734,38 +734,38 @@ def remove_exclusion_constraint(table_name, expression = nil, **options)
# 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+.
# [<tt>:using_index</tt>]
# To specify an existing unique index name. Defaults to +nil+.
def add_unique_key(table_name, column_name = nil, **options)
options = unique_key_options(table_name, column_name, options)
def add_unique_constraint(table_name, column_name = nil, **options)
options = unique_constraint_options(table_name, column_name, options)
at = create_alter_table(table_name)
at.add_unique_key(column_name, options)
at.add_unique_constraint(column_name, options)

execute schema_creation.accept(at)
end

def unique_key_options(table_name, column_name, options) # :nodoc:
def unique_constraint_options(table_name, column_name, options) # :nodoc:
assert_valid_deferrable(options[:deferrable])

if column_name && options[:using_index]
raise ArgumentError, "Cannot specify both column_name and :using_index options."
end

options = options.dup
options[:name] ||= unique_key_name(table_name, column: column_name, **options)
options[:name] ||= unique_constraint_name(table_name, column: column_name, **options)
options
end

# Removes the given unique constraint from the table.
#
# remove_unique_key :sections, name: "unique_position"
# remove_unique_constraint :sections, name: "unique_position"
#
# The +column_name+ parameter will be ignored if present. It can be helpful
# to provide this in a migration's +change+ method so it can be reverted.
# In that case, +column_name+ will be used by #add_unique_key.
def remove_unique_key(table_name, column_name = nil, **options)
unique_name_to_delete = unique_key_for!(table_name, column: column_name, **options).name
# In that case, +column_name+ will be used by #add_unique_constraint.
def remove_unique_constraint(table_name, column_name = nil, **options)
unique_name_to_delete = unique_constraint_for!(table_name, column: column_name, **options).name

at = create_alter_table(table_name)
at.drop_unique_key(unique_name_to_delete)
at.drop_unique_constraint(unique_name_to_delete)

execute schema_creation.accept(at)
end
Expand Down Expand Up @@ -1038,7 +1038,7 @@ def exclusion_constraint_for!(table_name, expression: nil, **options)
raise(ArgumentError, "Table '#{table_name}' has no exclusion constraint for #{expression || options}")
end

def unique_key_name(table_name, **options)
def unique_constraint_name(table_name, **options)
options.fetch(:name) do
column_or_index = Array(options[:column] || options[:using_index]).map(&:to_s)
identifier = "#{table_name}_#{column_or_index * '_and_'}_unique"
Expand All @@ -1048,13 +1048,13 @@ def unique_key_name(table_name, **options)
end
end

def unique_key_for(table_name, **options)
name = unique_key_name(table_name, **options) unless options.key?(:column)
unique_keys(table_name).detect { |unique_key| unique_key.defined_for?(name: name, **options) }
def unique_constraint_for(table_name, **options)
name = unique_constraint_name(table_name, **options) unless options.key?(:column)
unique_constraints(table_name).detect { |unique_constraint| unique_constraint.defined_for?(name: name, **options) }
end

def unique_key_for!(table_name, column: nil, **options)
unique_key_for(table_name, column: column, **options) ||
def unique_constraint_for!(table_name, column: nil, **options)
unique_constraint_for(table_name, column: column, **options) ||
raise(ArgumentError, "Table '#{table_name}' has no unique constraint for #{column || options}")
end

Expand Down
Expand Up @@ -226,7 +226,7 @@ def supports_exclusion_constraints?
true
end

def supports_unique_keys?
def supports_unique_constraints?
true
end

Expand Down

0 comments on commit b2790b6

Please sign in to comment.