Allow ReferenceExtractor to efficiently load references from multiple texts at once
This commit is contained in:
parent
251e13666d
commit
93fcddd7a7
4 changed files with 36 additions and 19 deletions
|
@ -12,7 +12,14 @@ module Gitlab
|
||||||
# :project (required) - Current project, ignored if reference is cross-project.
|
# :project (required) - Current project, ignored if reference is cross-project.
|
||||||
# :only_path - Generate path-only links.
|
# :only_path - Generate path-only links.
|
||||||
class ReferenceFilter < HTML::Pipeline::Filter
|
class ReferenceFilter < HTML::Pipeline::Filter
|
||||||
LazyReference = Struct.new(:klass, :ids)
|
LazyReference = Struct.new(:klass, :ids) do
|
||||||
|
def self.load(refs)
|
||||||
|
refs.group_by(&:klass).flat_map do |klass, refs|
|
||||||
|
ids = refs.flat_map(&:ids)
|
||||||
|
klass.where(id: ids)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.user_can_reference?(user, node, context)
|
def self.user_can_reference?(user, node, context)
|
||||||
if node.has_attribute?('data-project')
|
if node.has_attribute?('data-project')
|
||||||
|
|
|
@ -21,7 +21,7 @@ module Gitlab
|
||||||
gather_references(node)
|
gather_references(node)
|
||||||
end
|
end
|
||||||
|
|
||||||
load_lazy_references
|
load_lazy_references unless context[:load_lazy_references] == false
|
||||||
|
|
||||||
doc
|
doc
|
||||||
end
|
end
|
||||||
|
@ -56,11 +56,8 @@ module Gitlab
|
||||||
# Will load all references of one type using one query.
|
# Will load all references of one type using one query.
|
||||||
def load_lazy_references
|
def load_lazy_references
|
||||||
result[:lazy_references].each do |type, refs|
|
result[:lazy_references].each do |type, refs|
|
||||||
refs.group_by(&:klass).each do |klass, refs|
|
values = ReferenceFilter::LazyReference.load(refs)
|
||||||
ids = refs.map(&:ids).flatten
|
result[:references][type].concat(values)
|
||||||
values = klass.find(ids)
|
|
||||||
result[:references][type].push(*values)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,10 @@ module Gitlab
|
||||||
@current_user = current_user
|
@current_user = current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
def analyze(text)
|
def analyze(texts)
|
||||||
references.clear
|
references.clear
|
||||||
@text = Gitlab::Markdown.render_without_gfm(text)
|
texts = Array(texts)
|
||||||
|
@texts = texts.map { |text| Gitlab::Markdown.render_without_gfm(text) }
|
||||||
end
|
end
|
||||||
|
|
||||||
%i(user label issue merge_request snippet commit commit_range).each do |type|
|
%i(user label issue merge_request snippet commit commit_range).each do |type|
|
||||||
|
@ -47,13 +48,25 @@ module Gitlab
|
||||||
current_user: current_user,
|
current_user: current_user,
|
||||||
# We don't actually care about the links generated
|
# We don't actually care about the links generated
|
||||||
only_path: true,
|
only_path: true,
|
||||||
ignore_blockquotes: true
|
ignore_blockquotes: true,
|
||||||
|
load_lazy_references: false
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline = HTML::Pipeline.new([filter, Gitlab::Markdown::ReferenceGathererFilter], context)
|
pipeline = HTML::Pipeline.new([filter, Gitlab::Markdown::ReferenceGathererFilter], context)
|
||||||
result = pipeline.call(@text)
|
|
||||||
|
|
||||||
result[:references][filter_type]
|
values = []
|
||||||
|
lazy_references = []
|
||||||
|
|
||||||
|
@texts.each do |text|
|
||||||
|
result = pipeline.call(text)
|
||||||
|
|
||||||
|
values.concat(result[:references][filter_type])
|
||||||
|
lazy_references.concat(result[:lazy_references][filter_type])
|
||||||
|
end
|
||||||
|
|
||||||
|
lazy_values = Gitlab::Markdown::ReferenceFilter::LazyReference.load(lazy_references)
|
||||||
|
values.concat(lazy_values)
|
||||||
|
values
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe Gitlab::ReferenceExtractor do
|
||||||
project.team << [@u_bar, :guest]
|
project.team << [@u_bar, :guest]
|
||||||
|
|
||||||
subject.analyze('@foo, @baduser, @bar, and @offteam')
|
subject.analyze('@foo, @baduser, @bar, and @offteam')
|
||||||
expect(subject.users).to eq([@u_foo, @u_bar, @u_offteam])
|
expect(subject.users).to match_array([@u_foo, @u_bar, @u_offteam])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'ignores user mentions inside specific elements' do
|
it 'ignores user mentions inside specific elements' do
|
||||||
|
@ -37,7 +37,7 @@ describe Gitlab::ReferenceExtractor do
|
||||||
|
|
||||||
> @offteam
|
> @offteam
|
||||||
})
|
})
|
||||||
expect(subject.users).to eq([])
|
expect(subject.users).to match_array([])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accesses valid issue objects' do
|
it 'accesses valid issue objects' do
|
||||||
|
@ -45,7 +45,7 @@ describe Gitlab::ReferenceExtractor do
|
||||||
@i1 = create(:issue, project: project)
|
@i1 = create(:issue, project: project)
|
||||||
|
|
||||||
subject.analyze("#{@i0.to_reference}, #{@i1.to_reference}, and #{Issue.reference_prefix}999.")
|
subject.analyze("#{@i0.to_reference}, #{@i1.to_reference}, and #{Issue.reference_prefix}999.")
|
||||||
expect(subject.issues).to eq([@i0, @i1])
|
expect(subject.issues).to match_array([@i0, @i1])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accesses valid merge requests' do
|
it 'accesses valid merge requests' do
|
||||||
|
@ -53,7 +53,7 @@ describe Gitlab::ReferenceExtractor do
|
||||||
@m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'feature_conflict')
|
@m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'feature_conflict')
|
||||||
|
|
||||||
subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.")
|
subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.")
|
||||||
expect(subject.merge_requests).to eq([@m1, @m0])
|
expect(subject.merge_requests).to match_array([@m1, @m0])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accesses valid labels' do
|
it 'accesses valid labels' do
|
||||||
|
@ -62,7 +62,7 @@ describe Gitlab::ReferenceExtractor do
|
||||||
@l2 = create(:label)
|
@l2 = create(:label)
|
||||||
|
|
||||||
subject.analyze("~#{@l0.id}, ~999, ~#{@l2.id}, ~#{@l1.id}")
|
subject.analyze("~#{@l0.id}, ~999, ~#{@l2.id}, ~#{@l1.id}")
|
||||||
expect(subject.labels).to eq([@l0, @l1])
|
expect(subject.labels).to match_array([@l0, @l1])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accesses valid snippets' do
|
it 'accesses valid snippets' do
|
||||||
|
@ -71,7 +71,7 @@ describe Gitlab::ReferenceExtractor do
|
||||||
@s2 = create(:project_snippet)
|
@s2 = create(:project_snippet)
|
||||||
|
|
||||||
subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}")
|
subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}")
|
||||||
expect(subject.snippets).to eq([@s0, @s1])
|
expect(subject.snippets).to match_array([@s0, @s1])
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'accesses valid commits' do
|
it 'accesses valid commits' do
|
||||||
|
@ -109,7 +109,7 @@ describe Gitlab::ReferenceExtractor do
|
||||||
subject.analyze("this refers issue #{issue.to_reference(project)}")
|
subject.analyze("this refers issue #{issue.to_reference(project)}")
|
||||||
extracted = subject.issues
|
extracted = subject.issues
|
||||||
expect(extracted.size).to eq(1)
|
expect(extracted.size).to eq(1)
|
||||||
expect(extracted).to eq([issue])
|
expect(extracted).to match_array([issue])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue