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() }