package database import ( "context" "fmt" "time" "github.com/jackc/pgx/v5/pgxpool" ) type AlbumEvent struct { ID string Seq int64 WorkflowRunID string AlbumID string EventType string Step string Message string DataJSON []byte CreatedAt time.Time } type AlbumEventRepository struct { pool *pgxpool.Pool } func NewAlbumEventRepository(pool *pgxpool.Pool) *AlbumEventRepository { return &AlbumEventRepository{pool: pool} } func (r *AlbumEventRepository) Create(ctx context.Context, event *AlbumEvent) error { err := r.pool.QueryRow(ctx, `INSERT INTO album_events (workflow_run_id, album_id, event_type, step, message, data_json) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id, seq, created_at`, event.WorkflowRunID, event.AlbumID, event.EventType, event.Step, event.Message, event.DataJSON, ).Scan(&event.ID, &event.Seq, &event.CreatedAt) if err != nil { return fmt.Errorf("creating album event: %w", err) } return nil } func (r *AlbumEventRepository) GetByWorkflowRun(ctx context.Context, workflowRunID string) ([]*AlbumEvent, error) { rows, err := r.pool.Query(ctx, `SELECT id, seq, workflow_run_id, album_id, event_type, step, message, data_json, created_at FROM album_events WHERE workflow_run_id = $1 ORDER BY seq`, workflowRunID, ) if err != nil { return nil, fmt.Errorf("listing album events by workflow run: %w", err) } defer rows.Close() var events []*AlbumEvent for rows.Next() { event := &AlbumEvent{} if err := rows.Scan(&event.ID, &event.Seq, &event.WorkflowRunID, &event.AlbumID, &event.EventType, &event.Step, &event.Message, &event.DataJSON, &event.CreatedAt); err != nil { return nil, fmt.Errorf("scanning album event: %w", err) } events = append(events, event) } return events, nil } func (r *AlbumEventRepository) GetByAlbum(ctx context.Context, albumID string, afterSeq int64, limit int) ([]*AlbumEvent, error) { rows, err := r.pool.Query(ctx, `SELECT id, seq, workflow_run_id, album_id, event_type, step, message, data_json, created_at FROM album_events WHERE album_id = $1 AND seq > $2 ORDER BY seq LIMIT $3`, albumID, afterSeq, limit, ) if err != nil { return nil, fmt.Errorf("listing album events by album: %w", err) } defer rows.Close() var events []*AlbumEvent for rows.Next() { event := &AlbumEvent{} if err := rows.Scan(&event.ID, &event.Seq, &event.WorkflowRunID, &event.AlbumID, &event.EventType, &event.Step, &event.Message, &event.DataJSON, &event.CreatedAt); err != nil { return nil, fmt.Errorf("scanning album event: %w", err) } events = append(events, event) } return events, nil } func (r *AlbumEventRepository) GetLatestSeq(ctx context.Context) (int64, error) { var seq int64 err := r.pool.QueryRow(ctx, `SELECT COALESCE(MAX(seq), 0) FROM album_events`, ).Scan(&seq) if err != nil { return 0, fmt.Errorf("getting latest album event seq: %w", err) } return seq, nil } func (r *AlbumEventRepository) GetAfterSeq(ctx context.Context, afterSeq int64) ([]*AlbumEvent, error) { rows, err := r.pool.Query(ctx, `SELECT id, seq, workflow_run_id, album_id, event_type, step, message, data_json, created_at FROM album_events WHERE seq > $1 ORDER BY seq LIMIT 1000`, afterSeq, ) if err != nil { return nil, fmt.Errorf("listing album events after seq: %w", err) } defer rows.Close() var events []*AlbumEvent for rows.Next() { event := &AlbumEvent{} if err := rows.Scan(&event.ID, &event.Seq, &event.WorkflowRunID, &event.AlbumID, &event.EventType, &event.Step, &event.Message, &event.DataJSON, &event.CreatedAt); err != nil { return nil, fmt.Errorf("scanning album event: %w", err) } events = append(events, event) } return events, nil }