""" Seed-Daten: Globale Pflanzenfamilien, Pflanzen und Kompatibilitäten. Idempotent – kann mehrfach ausgeführt werden ohne Fehler. """ import asyncio import uuid from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.db.session import AsyncSessionLocal from app.models.plant import ( CompatibilityRating, NutrientDemand, Plant, PlantCompatibility, PlantFamily, WaterDemand, ) FAMILIES = [ {"name": "Solanaceae", "latin_name": "Solanaceae"}, {"name": "Kreuzblütler", "latin_name": "Brassicaceae"}, {"name": "Doldenblütler", "latin_name": "Apiaceae"}, {"name": "Hülsenfrüchtler", "latin_name": "Fabaceae"}, {"name": "Kürbisgewächse", "latin_name": "Cucurbitaceae"}, {"name": "Korbblütler", "latin_name": "Asteraceae"}, {"name": "Lauchgewächse", "latin_name": "Alliaceae"}, {"name": "Gänsefußgewächse", "latin_name": "Amaranthaceae"}, {"name": "Lippenblütler", "latin_name": "Lamiaceae"}, {"name": "Süßgräser", "latin_name": "Poaceae"}, ] # (name, latin_name, family_name, nutrient, water, spacing_cm, sow_start, sow_end, rest_years) PLANTS = [ # Solanaceae ("Tomate", "Solanum lycopersicum", "Solanaceae", NutrientDemand.STARK, WaterDemand.MITTEL, 60, 3, 4, 3), ("Paprika", "Capsicum annuum", "Solanaceae", NutrientDemand.STARK, WaterDemand.MITTEL, 45, 2, 3, 3), ("Aubergine", "Solanum melongena", "Solanaceae", NutrientDemand.STARK, WaterDemand.MITTEL, 50, 2, 3, 3), # Kreuzblütler ("Brokkoli", "Brassica oleracea var. italica", "Kreuzblütler", NutrientDemand.STARK, WaterDemand.MITTEL, 45, 3, 4, 4), ("Weißkohl", "Brassica oleracea var. capitata", "Kreuzblütler", NutrientDemand.STARK, WaterDemand.MITTEL, 50, 3, 4, 4), ("Kohlrabi", "Brassica oleracea var. gongylodes", "Kreuzblütler", NutrientDemand.MITTEL, WaterDemand.MITTEL, 22, 3, 7, 3), ("Radieschen", "Raphanus sativus", "Kreuzblütler", NutrientDemand.SCHWACH, WaterDemand.MITTEL, 5, 3, 8, 2), # Doldenblütler ("Möhre", "Daucus carota", "Doldenblütler", NutrientDemand.MITTEL, WaterDemand.WENIG, 5, 3, 7, 3), ("Petersilie", "Petroselinum crispum", "Doldenblütler", NutrientDemand.MITTEL, WaterDemand.MITTEL, 18, 3, 5, 2), ("Sellerie", "Apium graveolens", "Doldenblütler", NutrientDemand.STARK, WaterDemand.VIEL, 28, 2, 3, 3), # Hülsenfrüchtler ("Buschbohne", "Phaseolus vulgaris", "Hülsenfrüchtler", NutrientDemand.SCHWACH, WaterDemand.MITTEL, 12, 5, 7, 3), ("Erbse", "Pisum sativum", "Hülsenfrüchtler", NutrientDemand.SCHWACH, WaterDemand.MITTEL, 8, 3, 5, 3), # Kürbisgewächse ("Gurke", "Cucumis sativus", "Kürbisgewächse", NutrientDemand.STARK, WaterDemand.VIEL, 60, 4, 5, 2), ("Zucchini", "Cucurbita pepo", "Kürbisgewächse", NutrientDemand.STARK, WaterDemand.VIEL, 90, 4, 5, 2), ("Kürbis", "Cucurbita maxima", "Kürbisgewächse", NutrientDemand.STARK, WaterDemand.VIEL, 180, 4, 5, 2), # Korbblütler ("Kopfsalat", "Lactuca sativa", "Korbblütler", NutrientDemand.SCHWACH, WaterDemand.MITTEL, 22, 3, 8, 2), ("Feldsalat", "Valerianella locusta", "Korbblütler", NutrientDemand.SCHWACH, WaterDemand.WENIG, 8, 8, 9, 2), # Lauchgewächse ("Zwiebel", "Allium cepa", "Lauchgewächse", NutrientDemand.MITTEL, WaterDemand.WENIG, 12, 3, 4, 3), ("Lauch", "Allium porrum", "Lauchgewächse", NutrientDemand.MITTEL, WaterDemand.MITTEL, 12, 2, 3, 3), ("Knoblauch", "Allium sativum", "Lauchgewächse", NutrientDemand.SCHWACH, WaterDemand.WENIG, 10, 10, 11, 4), ("Schnittlauch", "Allium schoenoprasum", "Lauchgewächse", NutrientDemand.SCHWACH, WaterDemand.WENIG, 10, 3, 4, 3), # Gänsefußgewächse ("Mangold", "Beta vulgaris var. cicla", "Gänsefußgewächse", NutrientDemand.MITTEL, WaterDemand.MITTEL, 28, 3, 6, 3), ("Spinat", "Spinacia oleracea", "Gänsefußgewächse", NutrientDemand.MITTEL, WaterDemand.MITTEL, 12, 3, 9, 3), ("Rote Bete", "Beta vulgaris var. conditiva", "Gänsefußgewächse", NutrientDemand.MITTEL, WaterDemand.MITTEL, 10, 4, 6, 3), # Lippenblütler ("Basilikum", "Ocimum basilicum", "Lippenblütler", NutrientDemand.SCHWACH, WaterDemand.MITTEL, 20, 4, 5, 2), ("Thymian", "Thymus vulgaris", "Lippenblütler", NutrientDemand.SCHWACH, WaterDemand.WENIG, 25, 3, 4, 2), ("Minze", "Mentha spicata", "Lippenblütler", NutrientDemand.SCHWACH, WaterDemand.VIEL, 30, 3, 4, 2), ("Oregano", "Origanum vulgare", "Lippenblütler", NutrientDemand.SCHWACH, WaterDemand.WENIG, 25, 3, 4, 2), ] # (plant_a_name, plant_b_name, rating, reason) COMPATIBILITIES = [ ("Tomate", "Basilikum", CompatibilityRating.GUT, "Basilikum fördert das Tomatenwachstum und hält Schädlinge fern."), ("Tomate", "Möhre", CompatibilityRating.GUT, "Gute Nachbarn, gegenseitige Förderung."), ("Tomate", "Petersilie", CompatibilityRating.GUT, "Petersilie stärkt die Tomaten."), ("Tomate", "Brokkoli", CompatibilityRating.SCHLECHT, "Kohl hemmt das Tomatenwachstum."), ("Tomate", "Weißkohl", CompatibilityRating.SCHLECHT, "Kohl hemmt das Tomatenwachstum."), ("Möhre", "Zwiebel", CompatibilityRating.GUT, "Zwiebeln halten die Möhrenfliege fern."), ("Möhre", "Lauch", CompatibilityRating.GUT, "Lauch schützt die Möhre vor der Möhrenfliege."), ("Möhre", "Erbse", CompatibilityRating.GUT, "Erbsen lockern den Boden für Möhren."), ("Gurke", "Buschbohne", CompatibilityRating.GUT, "Klassische gute Nachbarschaft."), ("Weißkohl", "Sellerie", CompatibilityRating.GUT, "Sellerie hält die Kohlfliege fern."), ("Brokkoli", "Sellerie", CompatibilityRating.GUT, "Sellerie hält Kohlschädlinge fern."), ("Spinat", "Radieschen", CompatibilityRating.GUT, "Platzsparende Kombination, gegenseitig förderlich."), ("Zwiebel", "Buschbohne", CompatibilityRating.SCHLECHT, "Zwiebeln hemmen das Bohnenwachstum."), ("Zwiebel", "Erbse", CompatibilityRating.SCHLECHT, "Zwiebeln und Hülsenfrüchtler vertragen sich nicht."), ("Zwiebel", "Weißkohl", CompatibilityRating.SCHLECHT, "Konkurrenz um Nährstoffe."), ] async def seed_initial_data(db: AsyncSession) -> None: # 1. Plant families family_map: dict[str, PlantFamily] = {} for f in FAMILIES: result = await db.execute(select(PlantFamily).where(PlantFamily.name == f["name"])) existing = result.scalar_one_or_none() if existing: family_map[f["name"]] = existing else: obj = PlantFamily(id=uuid.uuid4(), **f) db.add(obj) await db.flush() family_map[f["name"]] = obj # 2. Global plants plant_map: dict[str, Plant] = {} for (name, latin, family_name, nutrient, water, spacing, sow_start, sow_end, rest) in PLANTS: result = await db.execute( select(Plant).where(Plant.name == name, Plant.tenant_id == None) # noqa: E711 ) existing = result.scalar_one_or_none() if existing: plant_map[name] = existing else: obj = Plant( id=uuid.uuid4(), tenant_id=None, family_id=family_map[family_name].id, name=name, latin_name=latin, nutrient_demand=nutrient, water_demand=water, spacing_cm=spacing, sowing_start_month=sow_start, sowing_end_month=sow_end, rest_years=rest, ) db.add(obj) await db.flush() plant_map[name] = obj # 3. Compatibilities (both directions) for (name_a, name_b, rating, reason) in COMPATIBILITIES: if name_a not in plant_map or name_b not in plant_map: continue id_a = plant_map[name_a].id id_b = plant_map[name_b].id result = await db.execute( select(PlantCompatibility).where( PlantCompatibility.plant_id_a == id_a, PlantCompatibility.plant_id_b == id_b, ) ) if not result.scalar_one_or_none(): db.add(PlantCompatibility(id=uuid.uuid4(), plant_id_a=id_a, plant_id_b=id_b, rating=rating, reason=reason)) # Reverse direction result = await db.execute( select(PlantCompatibility).where( PlantCompatibility.plant_id_a == id_b, PlantCompatibility.plant_id_b == id_a, ) ) if not result.scalar_one_or_none(): db.add(PlantCompatibility(id=uuid.uuid4(), plant_id_a=id_b, plant_id_b=id_a, rating=rating, reason=reason)) await db.commit() print("Seed-Daten erfolgreich eingespielt.") async def main() -> None: async with AsyncSessionLocal() as db: await seed_initial_data(db) if __name__ == "__main__": asyncio.run(main())