fix artifact import: preload queries, handle symbol keys

This commit is contained in:
Justin Edmund 2025-12-14 01:42:06 -08:00
parent 5666ee300c
commit 371f2a29dd

View file

@ -115,7 +115,13 @@ class ArtifactImportService
# @return [Result] Import result with counts and errors # @return [Result] Import result with counts and errors
def import def import
items = extract_items items = extract_items
return Result.new(success?: false, errors: ['No artifact items found in data']) if items.empty? if items.empty?
return Result.new(success?: false, created: [], updated: [], skipped: [], errors: ['No artifact items found in data'])
end
# Preload artifacts and existing collection artifacts to avoid N+1 queries
preload_artifacts(items)
preload_existing_collection_artifacts(items)
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
items.each_with_index do |item, index| items.each_with_index do |item, index|
@ -143,30 +149,45 @@ class ArtifactImportService
[] []
end end
def preload_artifacts(items)
artifact_ids = items.map { |item| (item['artifact_id'] || item[:artifact_id]).to_s }.uniq
artifacts = Artifact.where(granblue_id: artifact_ids).index_by(&:granblue_id)
@artifacts_cache = artifacts
end
def preload_existing_collection_artifacts(items)
game_ids = items.map { |item| (item['id'] || item[:id]).to_s }.uniq
existing = @user.collection_artifacts.where(game_id: game_ids).index_by(&:game_id)
@existing_cache = existing
end
def import_item(item, _index) def import_item(item, _index)
artifact = find_artifact(item['artifact_id']) # Handle both string and symbol keys from params
data = item.is_a?(Hash) ? item.with_indifferent_access : item
artifact = find_artifact(data['artifact_id'])
unless artifact unless artifact
@errors << { game_id: item['id'], artifact_id: item['artifact_id'], error: 'Artifact not found' } @errors << { game_id: data['id'], artifact_id: data['artifact_id'], error: 'Artifact not found' }
return return
end end
# Check for existing collection artifact with same game ID # Check for existing collection artifact with same game ID
existing = @user.collection_artifacts.find_by(game_id: item['id'].to_s) existing = @existing_cache[data['id'].to_s]
if existing if existing
if @update_existing if @update_existing
update_existing_artifact(existing, item, artifact) update_existing_artifact(existing, data, artifact)
else else
@skipped << { game_id: item['id'], reason: 'Already exists' } @skipped << { game_id: data['id'], reason: 'Already exists' }
end end
return return
end end
create_collection_artifact(item, artifact) create_collection_artifact(data, artifact)
end end
def find_artifact(artifact_id) def find_artifact(artifact_id)
Artifact.find_by(granblue_id: artifact_id.to_s) @artifacts_cache[artifact_id.to_s]
end end
def create_collection_artifact(item, artifact) def create_collection_artifact(item, artifact)
@ -200,16 +221,19 @@ class ArtifactImportService
end end
def build_collection_artifact_attrs(item, artifact) def build_collection_artifact_attrs(item, artifact)
# Handle both string and symbol keys from params
data = item.is_a?(Hash) ? item.with_indifferent_access : item
{ {
artifact: artifact, artifact: artifact,
game_id: item['id'].to_s, game_id: data['id'].to_s,
element: map_element(item['attribute']), element: map_element(data['attribute']),
proficiency: artifact.quirk? ? map_proficiency(item['kind']) : nil, proficiency: artifact.quirk? ? map_proficiency(data['kind']) : nil,
level: item['level'].to_i, level: data['level'].to_i,
skill1: parse_skill(item['skill1_info']), skill1: parse_skill(data['skill1_info']),
skill2: parse_skill(item['skill2_info']), skill2: parse_skill(data['skill2_info']),
skill3: parse_skill(item['skill3_info']), skill3: parse_skill(data['skill3_info']),
skill4: parse_skill(item['skill4_info']) skill4: parse_skill(data['skill4_info'])
} }
end end
@ -225,9 +249,12 @@ class ArtifactImportService
def parse_skill(skill_info) def parse_skill(skill_info)
return {} if skill_info.blank? return {} if skill_info.blank?
skill_id = skill_info['skill_id'] # Handle both string and symbol keys from params
quality = skill_info['skill_quality'] || skill_info['level'] info = skill_info.is_a?(Hash) ? skill_info.with_indifferent_access : skill_info
level = skill_info['level'] || 1
skill_id = info['skill_id']
quality = info['skill_quality'] || info['level']
level = info['level'] || 1
group, modifier = decode_skill_id(skill_id) group, modifier = decode_skill_id(skill_id)
return {} unless group && modifier return {} unless group && modifier
@ -266,7 +293,7 @@ class ArtifactImportService
return nil unless skill return nil unless skill
base_values = skill.base_values base_values = skill.base_values
return nil if base_values.blank? return nil if base_values.nil? || !base_values.is_a?(Array) || base_values.empty?
# Quality 1-5 maps to index 0-4 # Quality 1-5 maps to index 0-4
index = (quality - 1).clamp(0, base_values.size - 1) index = (quality - 1).clamp(0, base_values.size - 1)