package main import ( _ "embed" "encoding/json" "fmt" "regexp" "strings" ) //go:embed products_export.json var productsJSON []byte // SeedDatabase fügt Seed-Daten in die Datenbank ein func SeedDatabase() error { // Prüfen ob bereits Seeds vorhanden sind var count int err := db.Get(&count, "SELECT COUNT(*) FROM allergens") if err != nil { return fmt.Errorf("failed to check for existing allergens: %w", err) } // Nur seeden wenn noch keine Daten vorhanden sind if count > 0 { return nil // Bereits geseedet } // Allergene seeden if err := seedAllergens(); err != nil { return fmt.Errorf("failed to seed allergens: %w", err) } // Zusatzstoffe seeden if err := seedAdditives(); err != nil { return fmt.Errorf("failed to seed additives: %w", err) } // Produkte seeden if err := seedProducts(); err != nil { return fmt.Errorf("failed to seed products: %w", err) } return nil } // seedAllergens fügt die 14 EU-Allergene ein func seedAllergens() error { allergens := []Allergen{ {"a", "glutenhaltiges Getreide (Weizen, Roggen, Gerste, Hafer, Dinkel, Kamut)", "allergen"}, {"b", "Krebstiere", "allergen"}, {"c", "Eier", "allergen"}, {"d", "Fisch", "allergen"}, {"e", "Erdnüsse", "allergen"}, {"f", "Soja(bohnen)", "allergen"}, {"g", "Milch (einschließlich Laktose)", "allergen"}, {"h", "Schalenfrüchte (Mandeln, Haselnüsse, Walnüsse, Cashew, Pecan, Paranüsse, Pistazien, Macadamia)", "allergen"}, {"i", "Sellerie", "allergen"}, {"j", "Senf", "allergen"}, {"k", "Sesamsamen", "allergen"}, {"l", "Schwefeldioxid und Sulfite (> 10 mg/kg oder mg/l)", "allergen"}, {"m", "Lupine", "allergen"}, {"n", "Weichtiere", "allergen"}, } for _, allergen := range allergens { _, err := db.NamedExec( "INSERT OR IGNORE INTO allergens (id, name, category) VALUES (:id, :name, :category)", allergen, ) if err != nil { return fmt.Errorf("failed to insert allergen %s: %w", allergen.ID, err) } } return nil } // seedAdditives fügt die deutschen Zusatzstoffe ein func seedAdditives() error { additives := []Additive{ {"A", "Antioxidationsmittel"}, {"B", "Backtriebmittel"}, {"E", "Emulgator"}, {"F", "Farbstoff"}, {"FM", "Festigungsmittel"}, {"FH", "Feuchthaltemittel"}, {"FÜ", "Füllstoff"}, {"G", "Geliermittel"}, {"GV", "Geschmacksverstärker"}, {"K", "Konservierungsstoff"}, {"M", "Mehlbehandlungsmittel"}, {"MS", "Modifizierte Stärke"}, {"R", "Rieselhilfe"}, {"S", "Säuerungsmittel"}, {"SR", "Säureregulator"}, {"SV", "Schaumverhüter"}, {"SCH", "Schmelzsalz"}, {"ST", "Stabilisator"}, {"SÜ", "Süßungsmittel"}, {"T", "Trägerstoff"}, {"TG", "Treibgas"}, {"TM", "Trennmittel"}, {"Ü", "Überzugsmittel"}, {"V", "Verdickungsmittel"}, } for _, additive := range additives { _, err := db.NamedExec( "INSERT OR IGNORE INTO additives (id, name) VALUES (:id, :name)", additive, ) if err != nil { return fmt.Errorf("failed to insert additive %s: %w", additive.ID, err) } } return nil } // seedProducts importiert Produkte aus der JSON-Datei func seedProducts() error { var imports []ProductImport if err := json.Unmarshal(productsJSON, &imports); err != nil { return fmt.Errorf("failed to parse products JSON: %w", err) } tx, err := db.Beginx() if err != nil { return fmt.Errorf("failed to begin transaction: %w", err) } defer tx.Rollback() for _, product := range imports { // Produkt einfügen result, err := tx.NamedExec( "INSERT OR IGNORE INTO products (name, multiline) VALUES (:name, :multiline)", map[string]interface{}{ "name": product.Name, "multiline": product.Multiline, }, ) if err != nil { return fmt.Errorf("failed to insert product %s: %w", product.Name, err) } // Produkt-ID ermitteln var productID int64 productID, err = result.LastInsertId() if err != nil || productID == 0 { // Wenn INSERT OR IGNORE nichts eingefügt hat, ID über SELECT holen err = tx.Get(&productID, "SELECT id FROM products WHERE name = ?", product.Name) if err != nil { return fmt.Errorf("failed to get product ID for %s: %w", product.Name, err) } } // Allergene und Zusatzstoffe parsen und zuordnen allergenIDs, additiveIDs := parseAllergenData(product.Allergens1, product.Allergens2) // Allergene zuordnen for _, allergenID := range allergenIDs { _, err := tx.Exec( "INSERT OR IGNORE INTO product_allergens (product_id, allergen_id) VALUES (?, ?)", productID, allergenID, ) if err != nil { return fmt.Errorf("failed to link allergen %s to product %s: %w", allergenID, product.Name, err) } } // Zusatzstoffe zuordnen for _, additiveID := range additiveIDs { _, err := tx.Exec( "INSERT OR IGNORE INTO product_additives (product_id, additive_id) VALUES (?, ?)", productID, additiveID, ) if err != nil { return fmt.Errorf("failed to link additive %s to product %s: %w", additiveID, product.Name, err) } } } return tx.Commit() } // parseAllergenData parst Allergen- und Zusatzstoff-Daten aus den Import-Feldern func parseAllergenData(allergens1, allergens2 string) ([]string, []string) { // Beide Felder zusammenführen combined := strings.TrimSpace(allergens1 + ", " + allergens2) if combined == ", " { return nil, nil } // Regex für Allergene (einzelne Kleinbuchstaben a-n) allergenRegex := regexp.MustCompile(`\b[a-n]\b`) // Regex für Zusatzstoffe (Großbuchstaben und Kürzel) additiveRegex := regexp.MustCompile(`\b[A-Z]{1,3}\b`) allergenMatches := allergenRegex.FindAllString(combined, -1) additiveMatches := additiveRegex.FindAllString(combined, -1) // Duplikate entfernen allergenIDs := removeDuplicates(allergenMatches) additiveIDs := removeDuplicates(additiveMatches) return allergenIDs, additiveIDs } // removeDuplicates entfernt Duplikate aus einem String-Slice func removeDuplicates(slice []string) []string { seen := make(map[string]bool) result := []string{} for _, item := range slice { if !seen[item] { seen[item] = true result = append(result, item) } } return result }