Commit 27625dec authored by Robert Speicher's avatar Robert Speicher Committed by Robert Speicher

Merge branch 'fix-project-find-with-namespace-order' into 'master'

Fixed ordering in Project.find_with_namespace

This MR fixes the ordering of `Project.find_with_namespace` to ensure that it returns rows that match literally first.

Closes #18603

See merge request !4682
parent 601a4232
...@@ -262,7 +262,23 @@ class Project < ActiveRecord::Base ...@@ -262,7 +262,23 @@ class Project < ActiveRecord::Base
# #
# Returns a Project, or nil if no project could be found. # Returns a Project, or nil if no project could be found.
def find_with_namespace(path) def find_with_namespace(path)
where_paths_in([path]).reorder(nil).take namespace_path, project_path = path.split('/', 2)
return unless namespace_path && project_path
namespace_path = connection.quote(namespace_path)
project_path = connection.quote(project_path)
# On MySQL we want to ensure the ORDER BY uses a case-sensitive match so
# any literal matches come first, for this we have to use "BINARY".
# Without this there's still no guarantee in what order MySQL will return
# rows.
binary = Gitlab::Database.mysql? ? 'BINARY' : ''
order_sql = "(CASE WHEN #{binary} namespaces.path = #{namespace_path} " \
"AND #{binary} projects.path = #{project_path} THEN 0 ELSE 1 END)"
where_paths_in([path]).reorder(order_sql).take
end end
# Builds a relation to find multiple projects by their full paths. # Builds a relation to find multiple projects by their full paths.
......
...@@ -220,7 +220,7 @@ describe Project, models: true do ...@@ -220,7 +220,7 @@ describe Project, models: true do
end end
end end
describe :find_with_namespace do describe '.find_with_namespace' do
context 'with namespace' do context 'with namespace' do
before do before do
@group = create :group, name: 'gitlab' @group = create :group, name: 'gitlab'
...@@ -231,6 +231,22 @@ describe Project, models: true do ...@@ -231,6 +231,22 @@ describe Project, models: true do
it { expect(Project.find_with_namespace('GitLab/GitlabHQ')).to eq(@project) } it { expect(Project.find_with_namespace('GitLab/GitlabHQ')).to eq(@project) }
it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil } it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil }
end end
context 'when multiple projects using a similar name exist' do
let(:group) { create(:group, name: 'gitlab') }
let!(:project1) do
create(:empty_project, name: 'gitlab1', path: 'gitlab', namespace: group)
end
let!(:project2) do
create(:empty_project, name: 'gitlab2', path: 'GITLAB', namespace: group)
end
it 'returns the row where the path matches literally' do
expect(Project.find_with_namespace('gitlab/GITLAB')).to eq(project2)
end
end
end end
describe :to_param do describe :to_param do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment