diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 37374044551da69fe9a5e3f8d75ca06c4035c304..f0479d94986619cdf19ba1733bc74fd3915223ce 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -17,14 +17,13 @@ class Namespace < ActiveRecord::Base validates :owner, presence: true, unless: ->(n) { n.type == "Group" } validates :name, presence: true, - uniqueness: true, + uniqueness: { scope: :parent_id }, length: { maximum: 255 }, namespace_name: true validates :description, length: { maximum: 255 } validates :path, presence: true, - uniqueness: { case_sensitive: false }, length: { maximum: 255 }, namespace: true diff --git a/db/migrate/20161206153749_remove_uniq_path_index_from_namespace.rb b/db/migrate/20161206153749_remove_uniq_path_index_from_namespace.rb new file mode 100644 index 0000000000000000000000000000000000000000..2977917f2d10585c2a1e0e68053d1d92f1c44a89 --- /dev/null +++ b/db/migrate/20161206153749_remove_uniq_path_index_from_namespace.rb @@ -0,0 +1,36 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class RemoveUniqPathIndexFromNamespace < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + DOWNTIME = false + + def up + constraint_name = 'namespaces_path_key' + + transaction do + if index_exists?(:namespaces, :path) + remove_index(:namespaces, :path) + end + + # In some bizarre cases PostgreSQL might have a separate unique constraint + # that we'll need to drop. + if constraint_exists?(constraint_name) && Gitlab::Database.postgresql? + execute("ALTER TABLE namespaces DROP CONSTRAINT IF EXISTS #{constraint_name};") + end + end + end + + def down + unless index_exists?(:namespaces, :path) + add_concurrent_index(:namespaces, :path, unique: true) + end + end + + def constraint_exists?(name) + indexes(:namespaces).map(&:name).include?(name) + end +end diff --git a/db/migrate/20161206153751_add_path_index_to_namespace.rb b/db/migrate/20161206153751_add_path_index_to_namespace.rb new file mode 100644 index 0000000000000000000000000000000000000000..b0bac7d121e3763be9e104511b205c9265777db1 --- /dev/null +++ b/db/migrate/20161206153751_add_path_index_to_namespace.rb @@ -0,0 +1,20 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddPathIndexToNamespace < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + DOWNTIME = false + + def up + add_concurrent_index :namespaces, :path + end + + def down + if index_exists?(:namespaces, :path) + remove_index :namespaces, :path + end + end +end diff --git a/db/migrate/20161206153753_remove_uniq_name_index_from_namespace.rb b/db/migrate/20161206153753_remove_uniq_name_index_from_namespace.rb new file mode 100644 index 0000000000000000000000000000000000000000..cc9d4974baaffb85f24ac9871bd042c4f66bd1d0 --- /dev/null +++ b/db/migrate/20161206153753_remove_uniq_name_index_from_namespace.rb @@ -0,0 +1,36 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class RemoveUniqNameIndexFromNamespace < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + DOWNTIME = false + + def up + constraint_name = 'namespaces_name_key' + + transaction do + if index_exists?(:namespaces, :name) + remove_index(:namespaces, :name) + end + + # In some bizarre cases PostgreSQL might have a separate unique constraint + # that we'll need to drop. + if constraint_exists?(constraint_name) && Gitlab::Database.postgresql? + execute("ALTER TABLE namespaces DROP CONSTRAINT IF EXISTS #{constraint_name};") + end + end + end + + def down + unless index_exists?(:namespaces, :name) + add_concurrent_index(:namespaces, :name, unique: true) + end + end + + def constraint_exists?(name) + indexes(:namespaces).map(&:name).include?(name) + end +end diff --git a/db/migrate/20161206153754_add_name_index_to_namespace.rb b/db/migrate/20161206153754_add_name_index_to_namespace.rb new file mode 100644 index 0000000000000000000000000000000000000000..aaa35ed6f0ae0605b8c4544a4293cda25effe200 --- /dev/null +++ b/db/migrate/20161206153754_add_name_index_to_namespace.rb @@ -0,0 +1,20 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddNameIndexToNamespace < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + DOWNTIME = false + + def up + add_concurrent_index(:namespaces, [:name, :parent_id], unique: true) + end + + def down + if index_exists?(:namespaces, :name) + remove_index :namespaces, [:name, :parent_id] + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 9c46f573719a6fa4e440eca47af96eeb441a2321..08b1590e48455c0fda51b852c0b9ac26dfd9bf0a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20161202152035) do +ActiveRecord::Schema.define(version: 20161206153754) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -744,11 +744,11 @@ ActiveRecord::Schema.define(version: 20161202152035) do add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree add_index "namespaces", ["deleted_at"], name: "index_namespaces_on_deleted_at", using: :btree - add_index "namespaces", ["name"], name: "index_namespaces_on_name", unique: true, using: :btree + add_index "namespaces", ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree add_index "namespaces", ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree add_index "namespaces", ["parent_id", "id"], name: "index_namespaces_on_parent_id_and_id", unique: true, using: :btree - add_index "namespaces", ["path"], name: "index_namespaces_on_path", unique: true, using: :btree + add_index "namespaces", ["path"], name: "index_namespaces_on_path", using: :btree add_index "namespaces", ["path"], name: "index_namespaces_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"} add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 1613a586a2c428ca79c8c114670dea717c378e06..40f1cf92e0074ae2a0ce7c86025b0879d30582e0 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -50,9 +50,8 @@ describe Group, models: true do describe 'validations' do it { is_expected.to validate_presence_of :name } - it { is_expected.to validate_uniqueness_of(:name) } + it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) } it { is_expected.to validate_presence_of :path } - it { is_expected.to validate_uniqueness_of(:path) } it { is_expected.not_to validate_presence_of :owner } end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 7f82e85563bcfe02fb2ce342ac3204aefa9b1cd6..069c59fb5ca1e39f61a150df229a7bdb4ffc2b13 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -6,20 +6,16 @@ describe Namespace, models: true do it { is_expected.to have_many :projects } it { is_expected.to validate_presence_of(:name) } - it { is_expected.to validate_uniqueness_of(:name) } + it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) } it { is_expected.to validate_length_of(:name).is_at_most(255) } it { is_expected.to validate_length_of(:description).is_at_most(255) } it { is_expected.to validate_presence_of(:path) } - it { is_expected.to validate_uniqueness_of(:path) } it { is_expected.to validate_length_of(:path).is_at_most(255) } it { is_expected.to validate_presence_of(:owner) } - describe "Mass assignment" do - end - describe "Respond to" do it { is_expected.to respond_to(:human_name) } it { is_expected.to respond_to(:to_param) }