Files
bamort/backend/importero/importer.go
T

310 lines
9.4 KiB
Go

package importero
import (
"bamort/models"
"encoding/csv"
"fmt"
"os"
"strconv"
"strings"
)
// sourceIDCache stores cached source ID lookups to avoid repeated database queries
var sourceIDCache = make(map[string]uint)
// ClearSourceCache clears the cached source ID lookups
// Useful for testing or when working with different databases
func ClearSourceCache() {
sourceIDCache = make(map[string]uint)
}
// lookupSourceID retrieves the source ID from the database based on the source code
// Uses caching to avoid repeated database calls
// If the source doesn't exist, it creates a new one automatically
func lookupSourceID(sourceCode string) (uint, error) {
if sourceCode == "" {
return 0, fmt.Errorf("source code is empty")
}
// Check cache first
if sourceID, cached := sourceIDCache[sourceCode]; cached {
return sourceID, nil
}
// Not in cache, look up from database
var source models.Source
if err := source.FirstByCode(sourceCode); err != nil {
// Source not found, create it automatically
newSource := models.Source{
Code: sourceCode,
Name: sourceCode, // Use code as name initially
GameSystemId: models.GetGameSystem(0, "").ID, // Default game system
IsActive: true, // Set as active by default
}
if createErr := newSource.Create(); createErr != nil {
return 0, fmt.Errorf("source with code '%s' not found and could not be created: %w", sourceCode, createErr)
}
// Cache the newly created source
sourceIDCache[sourceCode] = newSource.ID
return newSource.ID, nil
}
// Cache the result for future use
sourceIDCache[sourceCode] = source.ID
return source.ID, nil
}
func ImportChar(char CharacterImport) (*models.Char, error) {
return nil, fmt.Errorf("char could not be imported %s", "Weil Wegen Kommt noch")
}
func CheckSkill(fertigkeit *Fertigkeit, autocreate bool) (*models.Skill, error) {
stammF := models.Skill{}
//err := database.DB.First(&stammF, "system=? AND name = ?", gameSystem, fertigkeit.Name).Error
gs := models.GetGameSystem(0, "midgard")
err := stammF.FirstwGS(fertigkeit.Name, gs.ID)
if err == nil {
// Fertigkeit found
return &stammF, nil
}
if !autocreate {
return nil, fmt.Errorf("does not exist in Fertigkeit importer")
}
stammF.GameSystemId = models.GetGameSystem(0, "midgard").ID
stammF.Name = fertigkeit.Name
if stammF.Name != "Sprache" {
stammF.Beschreibung = fertigkeit.Beschreibung
}
if fertigkeit.Fertigkeitswert < 12 {
stammF.Initialwert = 5
} else {
stammF.Initialwert = 12
}
stammF.Bonuseigenschaft = "keine"
stammF.Quelle = fertigkeit.Quelle
//fmt.Println(stammF)
err = stammF.Create()
if err != nil {
// Fertigkeit found
return nil, err
}
//err = database.DB.First(&stammF, "system=? AND name = ?", gameSystem, fertigkeit.Name).Error
err = stammF.FirstwGS(fertigkeit.Name, gs.ID)
if err != nil {
// Fertigkeit found
return nil, err
}
return &stammF, nil
}
func CheckSpell(zauber *Zauber, autocreate bool) (*models.Spell, error) {
stammF := models.Spell{}
//err := database.DB.First(&stammF, "system=? AND name = ?", gameSystem, zauber.Name).Error
gs := models.GetGameSystem(0, "midgard")
err := stammF.FirstwGS(zauber.Name, gs.ID)
if err == nil {
// zauber found
return &stammF, nil
}
if !autocreate {
return nil, fmt.Errorf("does not exist in zauber importer")
}
stammF.GameSystemId = models.GetGameSystem(0, "midgard").ID
stammF.Name = zauber.Name
stammF.Beschreibung = zauber.Beschreibung
stammF.AP = "1"
stammF.Stufe = 1
stammF.Wirkungsziel = "Zauberer"
stammF.Reichweite = "15 m"
stammF.Quelle = zauber.Quelle
//fmt.Println(stammF)
err = stammF.Create()
if err != nil {
// spell found
return nil, err
}
//err = database.DB.First(&stammF, "system=? AND name = ?", gameSystem, zauber.Name).Error
err = stammF.FirstwGS(zauber.Name, gs.ID)
if err != nil {
// spell found
return nil, err
}
return &stammF, nil
}
func ImportCsv2Spell(filepath string) error {
// Open the CSV file
file, err := os.Open(filepath)
if err != nil {
return fmt.Errorf("error opening file %s: %w", filepath, err)
}
defer file.Close()
// Create CSV reader
reader := csv.NewReader(file)
// Read all records
records, err := reader.ReadAll()
if err != nil {
return fmt.Errorf("error reading CSV file: %w", err)
}
if len(records) == 0 {
return fmt.Errorf("CSV file is empty")
}
// Get headers from first row
headers := records[0]
// Create a map for field name mapping to handle case variations
fieldMap := make(map[string]int)
for i, header := range headers {
// Normalize header names for mapping
normalizedHeader := strings.ToLower(strings.TrimSpace(header))
fieldMap[normalizedHeader] = i
}
// Process each record (skip header row)
for i, record := range records[1:] {
if len(record) == 0 {
continue // Skip empty rows
}
// Create spell struct
spell := models.Spell{
GameSystemId: models.GetGameSystem(0, "midgard").ID, // Default value
}
// Map CSV fields to struct fields
if idx, exists := fieldMap["name"]; exists && idx < len(record) {
spell.Name = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["beschreibung"]; exists && idx < len(record) {
spell.Beschreibung = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["quelle"]; exists && idx < len(record) {
quelleCode := strings.ToUpper(strings.TrimSpace(record[idx]))
spell.Quelle = quelleCode
// Look up source_id from database based on quelle code using cached lookup
if quelleCode != "" {
if sourceID, err := lookupSourceID(quelleCode); err == nil {
spell.SourceID = sourceID
}
// If source lookup fails, keep the existing source_id from CSV if present
}
}
if idx, exists := fieldMap["game_system"]; exists && idx < len(record) && strings.TrimSpace(record[idx]) != "" {
//spell.GameSystem = strings.ToLower(strings.TrimSpace(record[idx]))
spell.GameSystemId = models.GetGameSystem(0, strings.ToLower(strings.TrimSpace(record[idx]))).ID
}
/*
if idx, exists := fieldMap["source_id"]; exists && idx < len(record) {
if sourceID, err := strconv.Atoi(strings.TrimSpace(record[idx])); err == nil {
spell.SourceID = uint(sourceID)
}
}
*/
if idx, exists := fieldMap["page_number"]; exists && idx < len(record) {
if pageNum, err := strconv.Atoi(strings.TrimSpace(record[idx])); err == nil {
spell.PageNumber = pageNum
}
}
if idx, exists := fieldMap["bonus"]; exists && idx < len(record) {
if bonus, err := strconv.Atoi(strings.TrimSpace(record[idx])); err == nil {
spell.Bonus = bonus
}
}
if idx, exists := fieldMap["stufe"]; exists && idx < len(record) {
if level, err := strconv.Atoi(strings.TrimSpace(record[idx])); err == nil {
spell.Stufe = level
}
}
if idx, exists := fieldMap["ap"]; exists && idx < len(record) {
spell.AP = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["art"]; exists && idx < len(record) {
spell.Art = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["zauberdauer"]; exists && idx < len(record) {
spell.Zauberdauer = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["reichweite"]; exists && idx < len(record) {
spell.Reichweite = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["wirkungsziel"]; exists && idx < len(record) {
spell.Wirkungsziel = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["wirkungsbereich"]; exists && idx < len(record) {
spell.Wirkungsbereich = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["wirkungsdauer"]; exists && idx < len(record) {
spell.Wirkungsdauer = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["ursprung"]; exists && idx < len(record) {
spell.Ursprung = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["category"]; exists && idx < len(record) {
spell.Category = strings.TrimSpace(record[idx])
}
if idx, exists := fieldMap["learning_category"]; exists && idx < len(record) {
spell.LearningCategory = strings.TrimSpace(record[idx])
}
// Skip if name is empty
if spell.Name == "" {
continue
}
// Try to find existing spell by name
existingSpell := models.Spell{}
err := existingSpell.FirstwGS(spell.Name, spell.GameSystemId)
if err == nil {
// Spell exists, update it
existingSpell.Beschreibung = spell.Beschreibung
existingSpell.Quelle = spell.Quelle
existingSpell.GameSystem = spell.GameSystem
// Update SourceID if we found one from quelle lookup
if spell.SourceID != 0 {
existingSpell.SourceID = spell.SourceID
}
if spell.PageNumber != 0 {
existingSpell.PageNumber = spell.PageNumber
}
existingSpell.Bonus = spell.Bonus
existingSpell.Stufe = spell.Stufe
existingSpell.AP = spell.AP
existingSpell.Art = spell.Art
existingSpell.Zauberdauer = spell.Zauberdauer
existingSpell.Reichweite = spell.Reichweite
existingSpell.Wirkungsziel = spell.Wirkungsziel
existingSpell.Wirkungsbereich = spell.Wirkungsbereich
existingSpell.Wirkungsdauer = spell.Wirkungsdauer
existingSpell.Ursprung = spell.Ursprung
existingSpell.Category = spell.Category
existingSpell.LearningCategory = spell.LearningCategory
err = existingSpell.Save()
if err != nil {
return fmt.Errorf("error updating spell '%s' at row %d: %w", spell.Name, i+2, err)
}
} else {
// Spell doesn't exist, create new one
err = spell.Create()
if err != nil {
return fmt.Errorf("error creating spell '%s' at row %d: %w", spell.Name, i+2, err)
}
}
}
return nil
}