debian-mirror-gitlab/lib/gitlab/ci/tags/bulk_insert.rb
2022-01-26 12:08:38 +05:30

91 lines
2.4 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Ci
module Tags
class BulkInsert
TAGGINGS_BATCH_SIZE = 1000
TAGS_BATCH_SIZE = 500
def initialize(statuses, tag_list_by_status)
@statuses = statuses
@tag_list_by_status = tag_list_by_status
end
def insert!
return false if tag_list_by_status.empty?
persist_build_tags!
end
private
attr_reader :statuses, :tag_list_by_status
def persist_build_tags!
all_tags = tag_list_by_status.values.flatten.uniq.reject(&:blank?)
tag_records_by_name = create_tags(all_tags).index_by(&:name)
taggings = build_taggings_attributes(tag_records_by_name)
return false if taggings.empty?
taggings.each_slice(TAGGINGS_BATCH_SIZE) do |taggings_slice|
ActsAsTaggableOn::Tagging.insert_all!(taggings)
end
true
end
# rubocop: disable CodeReuse/ActiveRecord
def create_tags(tags)
existing_tag_records = ActsAsTaggableOn::Tag.where(name: tags).to_a
missing_tags = detect_missing_tags(tags, existing_tag_records)
return existing_tag_records if missing_tags.empty?
missing_tags
.map { |tag| { name: tag } }
.each_slice(TAGS_BATCH_SIZE) do |tags_attributes|
ActsAsTaggableOn::Tag.insert_all!(tags_attributes)
end
ActsAsTaggableOn::Tag.where(name: tags).to_a
end
# rubocop: enable CodeReuse/ActiveRecord
def build_taggings_attributes(tag_records_by_name)
taggings = statuses.flat_map do |status|
tag_list = tag_list_by_status[status.name]
next unless tag_list
tags = tag_records_by_name.values_at(*tag_list)
taggings_for(tags, status)
end
taggings.compact!
taggings
end
def taggings_for(tags, status)
tags.map do |tag|
{
tag_id: tag.id,
taggable_type: CommitStatus.name,
taggable_id: status.id,
created_at: Time.current,
context: 'tags'
}
end
end
def detect_missing_tags(tags, tag_records)
if tags.size != tag_records.size
tags - tag_records.map(&:name)
else
[]
end
end
end
end
end
end