From cb46b3830f3ec5271ec52e2d7e0906cf212fda1f Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 27 Apr 2026 20:36:42 -0400 Subject: [PATCH] feat(db): add similarity lookup queries (ListActiveContextualLikesForUser, GetCurrentSessionVectorForUser) --- internal/db/dbq/albums.sql.go | 2 +- internal/db/dbq/artists.sql.go | 2 +- internal/db/dbq/contextual_likes.sql.go | 39 +++++++++++++++++++++++- internal/db/dbq/db.go | 2 +- internal/db/dbq/events.sql.go | 22 ++++++++++++- internal/db/dbq/likes.sql.go | 2 +- internal/db/dbq/models.go | 2 +- internal/db/dbq/recommendation.sql.go | 2 +- internal/db/dbq/sessions.sql.go | 2 +- internal/db/dbq/tracks.sql.go | 2 +- internal/db/dbq/users.sql.go | 2 +- internal/db/queries/contextual_likes.sql | 11 +++++++ internal/db/queries/events.sql | 12 ++++++++ 13 files changed, 91 insertions(+), 11 deletions(-) diff --git a/internal/db/dbq/albums.sql.go b/internal/db/dbq/albums.sql.go index acbdeb5b..f94956b6 100644 --- a/internal/db/dbq/albums.sql.go +++ b/internal/db/dbq/albums.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: albums.sql package dbq diff --git a/internal/db/dbq/artists.sql.go b/internal/db/dbq/artists.sql.go index cafeb6b5..259efbc4 100644 --- a/internal/db/dbq/artists.sql.go +++ b/internal/db/dbq/artists.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: artists.sql package dbq diff --git a/internal/db/dbq/contextual_likes.sql.go b/internal/db/dbq/contextual_likes.sql.go index 7543cc6e..6b932e5e 100644 --- a/internal/db/dbq/contextual_likes.sql.go +++ b/internal/db/dbq/contextual_likes.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: contextual_likes.sql package dbq @@ -33,6 +33,43 @@ func (q *Queries) InsertContextualLike(ctx context.Context, arg InsertContextual return err } +const listActiveContextualLikesForUser = `-- name: ListActiveContextualLikesForUser :many +SELECT track_id, session_vector +FROM contextual_likes +WHERE user_id = $1 + AND deleted_at IS NULL + AND session_vector IS NOT NULL +` + +type ListActiveContextualLikesForUserRow struct { + TrackID pgtype.UUID + SessionVector []byte +} + +// Returns all the user's active (non-soft-deleted) contextual_likes with +// non-null vectors. Cardinality is bounded by the user's actual like-while- +// playing history — typically tens to low hundreds. Used by the engine to +// compute contextual_match_score for the candidate pool. +func (q *Queries) ListActiveContextualLikesForUser(ctx context.Context, userID pgtype.UUID) ([]ListActiveContextualLikesForUserRow, error) { + rows, err := q.db.Query(ctx, listActiveContextualLikesForUser, userID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListActiveContextualLikesForUserRow + for rows.Next() { + var i ListActiveContextualLikesForUserRow + if err := rows.Scan(&i.TrackID, &i.SessionVector); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const softDeleteContextualLikesForUserTrack = `-- name: SoftDeleteContextualLikesForUserTrack :exec UPDATE contextual_likes SET deleted_at = now() diff --git a/internal/db/dbq/db.go b/internal/db/dbq/db.go index 1890abd0..8650b40f 100644 --- a/internal/db/dbq/db.go +++ b/internal/db/dbq/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 package dbq diff --git a/internal/db/dbq/events.sql.go b/internal/db/dbq/events.sql.go index 44183e7d..7d3624b9 100644 --- a/internal/db/dbq/events.sql.go +++ b/internal/db/dbq/events.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: events.sql package dbq @@ -11,6 +11,26 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) +const getCurrentSessionVectorForUser = `-- name: GetCurrentSessionVectorForUser :one +SELECT pe.session_vector_at_play +FROM play_events pe +JOIN play_sessions s ON s.id = pe.session_id +WHERE pe.user_id = $1 + AND s.ended_at IS NULL +ORDER BY pe.started_at DESC +LIMIT 1 +` + +// Returns the session_vector_at_play of the user's most recent play_event +// in a still-active (un-timed-out) session. NoRows means no current vector. +// Joined with play_sessions so closed sessions don't leak stale vectors. +func (q *Queries) GetCurrentSessionVectorForUser(ctx context.Context, userID pgtype.UUID) ([]byte, error) { + row := q.db.QueryRow(ctx, getCurrentSessionVectorForUser, userID) + var session_vector_at_play []byte + err := row.Scan(&session_vector_at_play) + return session_vector_at_play, err +} + const getMostRecentPlaySessionForUser = `-- name: GetMostRecentPlaySessionForUser :one SELECT id, user_id, started_at, ended_at, last_event_at, track_count, client_id FROM play_sessions WHERE user_id = $1 diff --git a/internal/db/dbq/likes.sql.go b/internal/db/dbq/likes.sql.go index 5510829b..53533cc2 100644 --- a/internal/db/dbq/likes.sql.go +++ b/internal/db/dbq/likes.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: likes.sql package dbq diff --git a/internal/db/dbq/models.go b/internal/db/dbq/models.go index 4de19781..04475635 100644 --- a/internal/db/dbq/models.go +++ b/internal/db/dbq/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 package dbq diff --git a/internal/db/dbq/recommendation.sql.go b/internal/db/dbq/recommendation.sql.go index 535b4bea..8bfbcf62 100644 --- a/internal/db/dbq/recommendation.sql.go +++ b/internal/db/dbq/recommendation.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: recommendation.sql package dbq diff --git a/internal/db/dbq/sessions.sql.go b/internal/db/dbq/sessions.sql.go index bc34671b..3ac9741c 100644 --- a/internal/db/dbq/sessions.sql.go +++ b/internal/db/dbq/sessions.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: sessions.sql package dbq diff --git a/internal/db/dbq/tracks.sql.go b/internal/db/dbq/tracks.sql.go index d17447c9..5254bb50 100644 --- a/internal/db/dbq/tracks.sql.go +++ b/internal/db/dbq/tracks.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: tracks.sql package dbq diff --git a/internal/db/dbq/users.sql.go b/internal/db/dbq/users.sql.go index c3b5f3d9..2e7dccbf 100644 --- a/internal/db/dbq/users.sql.go +++ b/internal/db/dbq/users.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.1 +// sqlc v1.27.0 // source: users.sql package dbq diff --git a/internal/db/queries/contextual_likes.sql b/internal/db/queries/contextual_likes.sql index 2a99793a..c84fdb5f 100644 --- a/internal/db/queries/contextual_likes.sql +++ b/internal/db/queries/contextual_likes.sql @@ -8,3 +8,14 @@ VALUES ($1, $2, $3, $4); UPDATE contextual_likes SET deleted_at = now() WHERE user_id = $1 AND track_id = $2 AND deleted_at IS NULL; + +-- name: ListActiveContextualLikesForUser :many +-- Returns all the user's active (non-soft-deleted) contextual_likes with +-- non-null vectors. Cardinality is bounded by the user's actual like-while- +-- playing history — typically tens to low hundreds. Used by the engine to +-- compute contextual_match_score for the candidate pool. +SELECT track_id, session_vector +FROM contextual_likes +WHERE user_id = $1 + AND deleted_at IS NULL + AND session_vector IS NOT NULL; diff --git a/internal/db/queries/events.sql b/internal/db/queries/events.sql index 3a7ec1b7..60e42f4d 100644 --- a/internal/db/queries/events.sql +++ b/internal/db/queries/events.sql @@ -66,3 +66,15 @@ LIMIT $3; UPDATE play_events SET session_vector_at_play = $2 WHERE id = $1; + +-- name: GetCurrentSessionVectorForUser :one +-- Returns the session_vector_at_play of the user's most recent play_event +-- in a still-active (un-timed-out) session. NoRows means no current vector. +-- Joined with play_sessions so closed sessions don't leak stale vectors. +SELECT pe.session_vector_at_play +FROM play_events pe +JOIN play_sessions s ON s.id = pe.session_id +WHERE pe.user_id = $1 + AND s.ended_at IS NULL +ORDER BY pe.started_at DESC +LIMIT 1;