- 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
151 lines
4.9 KiB
Go
151 lines
4.9 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
ext "git.warky.dev/wdevs/amcs/internal/types"
|
|
)
|
|
|
|
func (db *DB) AddHouseholdItem(ctx context.Context, item ext.HouseholdItem) (ext.HouseholdItem, error) {
|
|
details, err := json.Marshal(item.Details)
|
|
if err != nil {
|
|
return ext.HouseholdItem{}, fmt.Errorf("marshal details: %w", err)
|
|
}
|
|
|
|
row := db.pool.QueryRow(ctx, `
|
|
insert into household_items (name, category, location, details, notes)
|
|
values ($1, $2, $3, $4::jsonb, $5)
|
|
returning id, created_at, updated_at
|
|
`, item.Name, nullStr(item.Category), nullStr(item.Location), details, nullStr(item.Notes))
|
|
|
|
created := item
|
|
if err := row.Scan(&created.ID, &created.CreatedAt, &created.UpdatedAt); err != nil {
|
|
return ext.HouseholdItem{}, fmt.Errorf("insert household item: %w", err)
|
|
}
|
|
return created, nil
|
|
}
|
|
|
|
func (db *DB) SearchHouseholdItems(ctx context.Context, query, category, location string) ([]ext.HouseholdItem, error) {
|
|
args := []any{}
|
|
conditions := []string{}
|
|
|
|
if q := strings.TrimSpace(query); q != "" {
|
|
args = append(args, "%"+q+"%")
|
|
conditions = append(conditions, fmt.Sprintf("(name ILIKE $%d OR notes ILIKE $%d)", len(args), len(args)))
|
|
}
|
|
if c := strings.TrimSpace(category); c != "" {
|
|
args = append(args, c)
|
|
conditions = append(conditions, fmt.Sprintf("category = $%d", len(args)))
|
|
}
|
|
if l := strings.TrimSpace(location); l != "" {
|
|
args = append(args, "%"+l+"%")
|
|
conditions = append(conditions, fmt.Sprintf("location ILIKE $%d", len(args)))
|
|
}
|
|
|
|
q := `select id, name, category, location, details, notes, created_at, updated_at from household_items`
|
|
if len(conditions) > 0 {
|
|
q += " where " + strings.Join(conditions, " and ")
|
|
}
|
|
q += " order by name"
|
|
|
|
rows, err := db.pool.Query(ctx, q, args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("search household items: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var items []ext.HouseholdItem
|
|
for rows.Next() {
|
|
var item ext.HouseholdItem
|
|
var detailsBytes []byte
|
|
var category, location, notes *string
|
|
if err := rows.Scan(&item.ID, &item.Name, &category, &location, &detailsBytes, ¬es, &item.CreatedAt, &item.UpdatedAt); err != nil {
|
|
return nil, fmt.Errorf("scan household item: %w", err)
|
|
}
|
|
item.Category = strVal(category)
|
|
item.Location = strVal(location)
|
|
item.Notes = strVal(notes)
|
|
if err := json.Unmarshal(detailsBytes, &item.Details); err != nil {
|
|
item.Details = map[string]any{}
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
return items, rows.Err()
|
|
}
|
|
|
|
func (db *DB) GetHouseholdItem(ctx context.Context, id uuid.UUID) (ext.HouseholdItem, error) {
|
|
row := db.pool.QueryRow(ctx, `
|
|
select id, name, category, location, details, notes, created_at, updated_at
|
|
from household_items where id = $1
|
|
`, id)
|
|
|
|
var item ext.HouseholdItem
|
|
var detailsBytes []byte
|
|
var category, location, notes *string
|
|
if err := row.Scan(&item.ID, &item.Name, &category, &location, &detailsBytes, ¬es, &item.CreatedAt, &item.UpdatedAt); err != nil {
|
|
return ext.HouseholdItem{}, fmt.Errorf("get household item: %w", err)
|
|
}
|
|
item.Category = strVal(category)
|
|
item.Location = strVal(location)
|
|
item.Notes = strVal(notes)
|
|
if err := json.Unmarshal(detailsBytes, &item.Details); err != nil {
|
|
item.Details = map[string]any{}
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
func (db *DB) AddVendor(ctx context.Context, v ext.HouseholdVendor) (ext.HouseholdVendor, error) {
|
|
row := db.pool.QueryRow(ctx, `
|
|
insert into household_vendors (name, service_type, phone, email, website, notes, rating, last_used)
|
|
values ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
returning id, created_at
|
|
`, v.Name, nullStr(v.ServiceType), nullStr(v.Phone), nullStr(v.Email),
|
|
nullStr(v.Website), nullStr(v.Notes), v.Rating, v.LastUsed)
|
|
|
|
created := v
|
|
if err := row.Scan(&created.ID, &created.CreatedAt); err != nil {
|
|
return ext.HouseholdVendor{}, fmt.Errorf("insert vendor: %w", err)
|
|
}
|
|
return created, nil
|
|
}
|
|
|
|
func (db *DB) ListVendors(ctx context.Context, serviceType string) ([]ext.HouseholdVendor, error) {
|
|
args := []any{}
|
|
q := `select id, name, service_type, phone, email, website, notes, rating, last_used, created_at from household_vendors`
|
|
if st := strings.TrimSpace(serviceType); st != "" {
|
|
args = append(args, st)
|
|
q += " where service_type = $1"
|
|
}
|
|
q += " order by name"
|
|
|
|
rows, err := db.pool.Query(ctx, q, args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list vendors: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var vendors []ext.HouseholdVendor
|
|
for rows.Next() {
|
|
var v ext.HouseholdVendor
|
|
var serviceType, phone, email, website, notes *string
|
|
var lastUsed *time.Time
|
|
if err := rows.Scan(&v.ID, &v.Name, &serviceType, &phone, &email, &website, ¬es, &v.Rating, &lastUsed, &v.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("scan vendor: %w", err)
|
|
}
|
|
v.ServiceType = strVal(serviceType)
|
|
v.Phone = strVal(phone)
|
|
v.Email = strVal(email)
|
|
v.Website = strVal(website)
|
|
v.Notes = strVal(notes)
|
|
v.LastUsed = lastUsed
|
|
vendors = append(vendors, v)
|
|
}
|
|
return vendors, rows.Err()
|
|
}
|