package store import ( "context" "fmt" "strings" "time" ext "git.warky.dev/wdevs/amcs/internal/types" ) func (db *DB) AddMaintenanceTask(ctx context.Context, t ext.MaintenanceTask) (ext.MaintenanceTask, error) { row := db.pool.QueryRow(ctx, ` insert into maintenance_tasks (name, category, frequency_days, next_due, priority, notes) values ($1, $2, $3, $4, $5, $6) returning id, created_at, updated_at `, t.Name, nullStr(t.Category), t.FrequencyDays, t.NextDue, t.Priority, nullStr(t.Notes)) created := t if err := row.Scan(&created.ID, &created.CreatedAt, &created.UpdatedAt); err != nil { return ext.MaintenanceTask{}, fmt.Errorf("insert maintenance task: %w", err) } return created, nil } func (db *DB) LogMaintenance(ctx context.Context, log ext.MaintenanceLog) (ext.MaintenanceLog, error) { completedAt := log.CompletedAt if completedAt.IsZero() { completedAt = time.Now() } row := db.pool.QueryRow(ctx, ` insert into maintenance_logs (task_id, completed_at, performed_by, cost, notes, next_action) values ($1, $2, $3, $4, $5, $6) returning id `, log.TaskID, completedAt, nullStr(log.PerformedBy), log.Cost, nullStr(log.Notes), nullStr(log.NextAction)) created := log created.CompletedAt = completedAt if err := row.Scan(&created.ID); err != nil { return ext.MaintenanceLog{}, fmt.Errorf("insert maintenance log: %w", err) } return created, nil } func (db *DB) GetUpcomingMaintenance(ctx context.Context, daysAhead int) ([]ext.MaintenanceTask, error) { if daysAhead <= 0 { daysAhead = 30 } cutoff := time.Now().Add(time.Duration(daysAhead) * 24 * time.Hour) rows, err := db.pool.Query(ctx, ` select id, name, category, frequency_days, last_completed, next_due, priority, notes, created_at, updated_at from maintenance_tasks where next_due <= $1 or next_due is null order by next_due asc nulls last, priority desc `, cutoff) if err != nil { return nil, fmt.Errorf("get upcoming maintenance: %w", err) } defer rows.Close() return scanMaintenanceTasks(rows) } func (db *DB) SearchMaintenanceHistory(ctx context.Context, query, category string, start, end *time.Time) ([]ext.MaintenanceLogWithTask, error) { args := []any{} conditions := []string{} if q := strings.TrimSpace(query); q != "" { args = append(args, "%"+q+"%") conditions = append(conditions, fmt.Sprintf("(mt.name ILIKE $%d OR ml.notes ILIKE $%d)", len(args), len(args))) } if c := strings.TrimSpace(category); c != "" { args = append(args, c) conditions = append(conditions, fmt.Sprintf("mt.category = $%d", len(args))) } if start != nil { args = append(args, *start) conditions = append(conditions, fmt.Sprintf("ml.completed_at >= $%d", len(args))) } if end != nil { args = append(args, *end) conditions = append(conditions, fmt.Sprintf("ml.completed_at <= $%d", len(args))) } q := ` select ml.id, ml.task_id, ml.completed_at, ml.performed_by, ml.cost, ml.notes, ml.next_action, mt.name, mt.category from maintenance_logs ml join maintenance_tasks mt on mt.id = ml.task_id ` if len(conditions) > 0 { q += " where " + strings.Join(conditions, " and ") } q += " order by ml.completed_at desc" rows, err := db.pool.Query(ctx, q, args...) if err != nil { return nil, fmt.Errorf("search maintenance history: %w", err) } defer rows.Close() var logs []ext.MaintenanceLogWithTask for rows.Next() { var l ext.MaintenanceLogWithTask var performedBy, notes, nextAction, taskCategory *string if err := rows.Scan( &l.ID, &l.TaskID, &l.CompletedAt, &performedBy, &l.Cost, ¬es, &nextAction, &l.TaskName, &taskCategory, ); err != nil { return nil, fmt.Errorf("scan maintenance log: %w", err) } l.PerformedBy = strVal(performedBy) l.Notes = strVal(notes) l.NextAction = strVal(nextAction) l.TaskCategory = strVal(taskCategory) logs = append(logs, l) } return logs, rows.Err() } func scanMaintenanceTasks(rows interface { Next() bool Scan(...any) error Err() error Close() }) ([]ext.MaintenanceTask, error) { defer rows.Close() var tasks []ext.MaintenanceTask for rows.Next() { var t ext.MaintenanceTask var category, notes *string if err := rows.Scan(&t.ID, &t.Name, &category, &t.FrequencyDays, &t.LastCompleted, &t.NextDue, &t.Priority, ¬es, &t.CreatedAt, &t.UpdatedAt); err != nil { return nil, fmt.Errorf("scan maintenance task: %w", err) } t.Category = strVal(category) t.Notes = strVal(notes) tasks = append(tasks, t) } return tasks, rows.Err() }