lookbook/internal/data/item/queries.go
soup fc625fb9cf
Initial lookbook implementation
Pinterest-style visual bookmarking app with:
- URL metadata extraction (OG/Twitter meta, oEmbed fallback)
- Image caching in Postgres with 480px thumbnails
- Multi-tag filtering with Ctrl/Cmd for OR mode
- Fuzzy tag suggestions and inline tag editing
- Browser console auth() with first-use password setup
- Brutalist UI with Commit Mono font and Pico CSS
- Light/dark mode via browser preference
2026-01-16 21:14:23 -05:00

100 lines
2.6 KiB
Go

package item
import (
"context"
"database/sql"
"time"
"github.com/google/uuid"
)
type Row struct {
ID int64
PubID uuid.UUID
SourceURL string
Title string
Description string
SiteName string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt sql.Null[time.Time]
}
func QList(ctx context.Context, db *sql.DB) ([]Row, error) {
rows, err := db.QueryContext(ctx, `
SELECT id, pub_id, source_url, title, description, site_name, created_at, updated_at, deleted_at
FROM item
WHERE deleted_at IS NULL
ORDER BY created_at DESC
`)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Row
for rows.Next() {
var row Row
if err := rows.Scan(&row.ID, &row.PubID, &row.SourceURL, &row.Title, &row.Description, &row.SiteName, &row.CreatedAt, &row.UpdatedAt, &row.DeletedAt); err != nil {
return nil, err
}
items = append(items, row)
}
return items, rows.Err()
}
func QFindByID(ctx context.Context, db *sql.DB, id int64) (*Row, error) {
var row Row
err := db.QueryRowContext(ctx, `
SELECT id, pub_id, source_url, title, description, site_name, created_at, updated_at, deleted_at
FROM item
WHERE id = $1
LIMIT 1
`, id).Scan(&row.ID, &row.PubID, &row.SourceURL, &row.Title, &row.Description, &row.SiteName, &row.CreatedAt, &row.UpdatedAt, &row.DeletedAt)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
return &row, nil
}
func QCreate(ctx context.Context, db *sql.DB, sourceURL, title, description, siteName string) (Row, error) {
var row Row
err := db.QueryRowContext(ctx, `
INSERT INTO item (source_url, title, description, site_name)
VALUES ($1, $2, $3, $4)
RETURNING id, pub_id, source_url, title, description, site_name, created_at, updated_at, deleted_at
`, sourceURL, title, description, siteName).Scan(
&row.ID,
&row.PubID,
&row.SourceURL,
&row.Title,
&row.Description,
&row.SiteName,
&row.CreatedAt,
&row.UpdatedAt,
&row.DeletedAt,
)
return row, err
}
func QUpdateMeta(ctx context.Context, db *sql.DB, id int64, title, description, siteName string) error {
_, err := db.ExecContext(ctx, `
UPDATE item
SET title = $2, description = $3, site_name = $4, updated_at = NOW()
WHERE id = $1
`, id, title, description, siteName)
return err
}
func QSoftDelete(ctx context.Context, db *sql.DB, id int64) error {
_, err := db.ExecContext(ctx, `UPDATE item SET deleted_at = NOW() WHERE id = $1`, id)
return err
}
func QRestore(ctx context.Context, db *sql.DB, id int64) error {
_, err := db.ExecContext(ctx, `UPDATE item SET deleted_at = NULL WHERE id = $1`, id)
return err
}