package postgres import ( "database/sql" "gardomatic.kleiax.de/internal/storage" ) // TaskTemplateOptOutModel stores per-plant task-generation suppression while // enforcing the garden boundary. type TaskTemplateOptOutModel struct{ DB *sql.DB } // IsOptedOut reports whether task generation is suppressed for a plant-template pair. func (m TaskTemplateOptOutModel) IsOptedOut(gardenID, plantID, templateID int) (bool, error) { ctx, cancel := contextWithTimeout() defer cancel() var value bool err := m.DB.QueryRowContext(ctx, `SELECT EXISTS(SELECT 1 FROM task_template_opt_outs o JOIN plants p ON p.id=o.plant_id JOIN species_task_templates st ON st.id=o.template_id WHERE p.garden_id=$1 AND p.id=$2 AND st.id=$3 AND st.species_id=p.species_id)`, gardenID, plantID, templateID).Scan(&value) return value, err } // GetAllForPlant lists suppressed template IDs for a plant. func (m TaskTemplateOptOutModel) GetAllForPlant(gardenID, plantID int) ([]int, error) { ctx, cancel := contextWithTimeout() defer cancel() rows, err := m.DB.QueryContext(ctx, `SELECT o.template_id FROM task_template_opt_outs o JOIN plants p ON p.id=o.plant_id WHERE p.garden_id=$1 AND p.id=$2 ORDER BY o.template_id`, gardenID, plantID) if err != nil { return nil, err } defer rows.Close() result := []int{} for rows.Next() { var id int if err = rows.Scan(&id); err != nil { return nil, err } result = append(result, id) } return result, rows.Err() } // Set creates or removes suppression for a plant-template pair. func (m TaskTemplateOptOutModel) Set(gardenID, plantID, templateID int, optedOut bool) error { ctx, cancel := contextWithTimeout() defer cancel() var valid bool err := m.DB.QueryRowContext(ctx, `SELECT EXISTS(SELECT 1 FROM plants p JOIN species_task_templates st ON st.species_id=p.species_id WHERE p.garden_id=$1 AND p.id=$2 AND st.id=$3)`, gardenID, plantID, templateID).Scan(&valid) if err != nil { return err } if !valid { return storage.ErrRecordNotFound } if optedOut { _, err = m.DB.ExecContext(ctx, `INSERT INTO task_template_opt_outs(plant_id,template_id) VALUES($1,$2) ON CONFLICT DO NOTHING`, plantID, templateID) } else { _, err = m.DB.ExecContext(ctx, `DELETE FROM task_template_opt_outs WHERE plant_id=$1 AND template_id=$2`, plantID, templateID) } return err }