- Implement maintenance tool for adding, logging, and retrieving tasks - Create meals tool for managing recipes, meal plans, and shopping lists - Introduce reparse metadata tool for updating thought metadata - Add household knowledge, home maintenance, family calendar, meal planning, and professional CRM database migrations - Grant necessary permissions for new database tables
143 lines
4.4 KiB
Go
143 lines
4.4 KiB
Go
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()
|
|
}
|