heating-monitor/cmd/import/main.go
2024-11-28 13:52:58 +01:00

170 lines
4.6 KiB
Go

package main
import (
"encoding/csv"
"fmt"
"log"
"os"
"strings"
"time"
"heating-monitor/internal/bot"
"heating-monitor/internal/config"
"github.com/spf13/cobra"
"gorm.io/gorm"
)
func main() {
var filePath string
var dryRun bool
// Define el comando principal
var cmd = &cobra.Command{
Use: "import",
Short: "Importa datos desde un CSV a la base de datos",
Run: func(cmd *cobra.Command, args []string) {
if filePath == "" {
log.Fatal("Debe especificar un archivo CSV con el flag -f o --file")
}
// Abre el archivo CSV
file, err := os.Open(filePath)
if err != nil {
log.Fatalf("No se pudo abrir el archivo: %v", err)
}
defer file.Close()
reader := csv.NewReader(file)
reader.Comma = ';' // Usamos punto y coma como separador
// Lee el archivo CSV
records, err := reader.ReadAll()
if err != nil {
log.Fatalf("Error al leer el archivo CSV: %v", err)
}
// Ignorar la primera línea de encabezado
records = records[1:]
insertedCount := 0
// Procesa cada línea del CSV
for _, record := range records {
// Ignorar encabezado
if strings.HasPrefix(record[0], ";") {
continue
}
// Parsear la fecha
fecha, err := time.Parse("2006-01-02", record[1])
if err != nil {
log.Printf("Error al parsear la fecha: %v", err)
continue
}
// Procesar las columnas ON/OFF
for i := 2; i <= 6; i += 3 {
if record[i] != "" && record[i+1] != "" {
// Parsear las horas ON/OFF
onTime, err := time.Parse("15:04", record[i])
if err != nil {
log.Printf("Error al parsear hora ON: %v", err)
continue
}
offTime, err := time.Parse("15:04", record[i+1])
if err != nil {
log.Printf("Error al parsear hora OFF: %v", err)
continue
}
// Ajustar los tiempos a la fecha correcta
onTimestamp := time.Date(fecha.Year(), fecha.Month(), fecha.Day(), onTime.Hour(), onTime.Minute(), 0, 0, time.UTC)
offTimestamp := time.Date(fecha.Year(), fecha.Month(), fecha.Day(), offTime.Hour(), offTime.Minute(), 0, 0, time.UTC)
// Mostrar en dry-run
if dryRun {
fmt.Printf("ON: %v, OFF: %v\n", onTimestamp, offTimestamp)
} else {
// Inicializar la base de datos
config.InitDB()
// Insertar en la base de datos
existsOn, err := eventExists(config.DB, "ON", onTimestamp)
if err != nil {
log.Printf("Error al verificar existencia de evento ON: %v", err)
continue
}
if !existsOn {
err := insertHeatingEvent(config.DB, "ON", onTimestamp)
if err != nil {
log.Printf("Error al insertar evento ON: %v", err)
continue
}
insertedCount++
} else {
log.Printf("Evento ON ya existe: %v", onTimestamp)
}
existsOff, err := eventExists(config.DB, "OFF", offTimestamp)
if err != nil {
log.Printf("Error al verificar existencia de evento OFF: %v", err)
continue
}
if !existsOff {
err := insertHeatingEvent(config.DB, "OFF", offTimestamp)
if err != nil {
log.Printf("Error al insertar evento OFF: %v", err)
continue
}
insertedCount++
} else {
log.Printf("Evento OFF ya existe: %v", offTimestamp)
}
}
}
}
}
log.Printf("Se insertaron %d registros en la base de datos", insertedCount)
},
}
// Añadir flags al comando
cmd.Flags().StringVarP(&filePath, "file", "f", "", "Ruta del archivo CSV")
cmd.Flags().BoolVarP(&dryRun, "dry-run", "", false, "Simula la importación y muestra los datos")
// Ejecutar el comando
if err := cmd.Execute(); err != nil {
log.Fatal(err)
}
}
// insertHeatingEvent inserta un evento de calefacción en la base de datos
func insertHeatingEvent(db *gorm.DB, eventType string, timestamp time.Time) error {
event := bot.HeatingEvent{
EventType: eventType,
Timestamp: timestamp,
}
// Insertar el evento en la base de datos
if err := db.Create(&event).Error; err != nil {
return fmt.Errorf("no se pudo insertar el evento: %v", err)
}
return nil
}
// eventExists verifica si un evento con el mismo tipo y timestamp ya existe
func eventExists(db *gorm.DB, eventType string, timestamp time.Time) (bool, error) {
var existingEvent bot.HeatingEvent
err := db.Where("event_type = ? AND timestamp = ?", eventType, timestamp).First(&existingEvent).Error
if err == nil {
// Si err es nil, significa que se encontró un evento existente
return true, nil
} else if err == gorm.ErrRecordNotFound {
// Si el error es ErrRecordNotFound, no existe el evento
return false, nil
}
// Si hay otro tipo de error
return false, err
}