// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: events.sql package dbq import ( "context" "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 ORDER BY last_event_at DESC LIMIT 1 ` func (q *Queries) GetMostRecentPlaySessionForUser(ctx context.Context, userID pgtype.UUID) (PlaySession, error) { row := q.db.QueryRow(ctx, getMostRecentPlaySessionForUser, userID) var i PlaySession err := row.Scan( &i.ID, &i.UserID, &i.StartedAt, &i.EndedAt, &i.LastEventAt, &i.TrackCount, &i.ClientID, ) return i, err } const getOpenPlayEventForUser = `-- name: GetOpenPlayEventForUser :one SELECT id, user_id, track_id, session_id, started_at, ended_at, duration_played_ms, completion_ratio, was_skipped, client_id, session_vector_at_play, scrobbled_at, source, pick_kind FROM play_events WHERE user_id = $1 AND ended_at IS NULL ORDER BY started_at DESC LIMIT 1 ` // Returns the most recent play_event for a user where ended_at IS NULL. // Used by the auto-close-prior step in playevents.RecordPlayStarted. func (q *Queries) GetOpenPlayEventForUser(ctx context.Context, userID pgtype.UUID) (PlayEvent, error) { row := q.db.QueryRow(ctx, getOpenPlayEventForUser, userID) var i PlayEvent err := row.Scan( &i.ID, &i.UserID, &i.TrackID, &i.SessionID, &i.StartedAt, &i.EndedAt, &i.DurationPlayedMs, &i.CompletionRatio, &i.WasSkipped, &i.ClientID, &i.SessionVectorAtPlay, &i.ScrobbledAt, &i.Source, &i.PickKind, ) return i, err } const getPlayEventByID = `-- name: GetPlayEventByID :one SELECT id, user_id, track_id, session_id, started_at, ended_at, duration_played_ms, completion_ratio, was_skipped, client_id, session_vector_at_play, scrobbled_at, source, pick_kind FROM play_events WHERE id = $1 ` func (q *Queries) GetPlayEventByID(ctx context.Context, id pgtype.UUID) (PlayEvent, error) { row := q.db.QueryRow(ctx, getPlayEventByID, id) var i PlayEvent err := row.Scan( &i.ID, &i.UserID, &i.TrackID, &i.SessionID, &i.StartedAt, &i.EndedAt, &i.DurationPlayedMs, &i.CompletionRatio, &i.WasSkipped, &i.ClientID, &i.SessionVectorAtPlay, &i.ScrobbledAt, &i.Source, &i.PickKind, ) return i, err } const getSystemPickKindForTrack = `-- name: GetSystemPickKindForTrack :one SELECT pt.pick_kind FROM playlist_tracks pt JOIN playlists p ON p.id = pt.playlist_id WHERE p.user_id = $1 AND p.system_variant = $2 AND pt.track_id = $3 LIMIT 1 ` type GetSystemPickKindForTrackParams struct { UserID pgtype.UUID SystemVariant *string TrackID pgtype.UUID } // Looks a track up in the user's CURRENT snapshot of the given system // variant and returns its pick_kind. Used at play-ingestion time to // freeze provenance onto the play_event — snapshots rebuild daily, so // attribution can't be reconstructed at read time (#1249/#1270). No // row = track not in today's snapshot (caller stores NULL); a row with // NULL pick_kind = the variant doesn't stamp (yet). songs_like_artist // is non-singleton (up to 3 mixes/user); a track in two of them takes // whichever LIMIT 1 hits — acceptable, tier stamps there describe the // same eligibility ladder. func (q *Queries) GetSystemPickKindForTrack(ctx context.Context, arg GetSystemPickKindForTrackParams) (*string, error) { row := q.db.QueryRow(ctx, getSystemPickKindForTrack, arg.UserID, arg.SystemVariant, arg.TrackID) var pick_kind *string err := row.Scan(&pick_kind) return pick_kind, err } const insertPlayEvent = `-- name: InsertPlayEvent :one INSERT INTO play_events ( user_id, track_id, session_id, started_at, client_id, source, pick_kind ) VALUES ($1, $2, $3, $4, $5, $6, $7::text) RETURNING id, user_id, track_id, session_id, started_at, ended_at, duration_played_ms, completion_ratio, was_skipped, client_id, session_vector_at_play, scrobbled_at, source, pick_kind ` type InsertPlayEventParams struct { UserID pgtype.UUID TrackID pgtype.UUID SessionID pgtype.UUID StartedAt pgtype.Timestamptz ClientID *string Source *string PickKind *string } // pick_kind is non-NULL only for system-playlist plays whose track was // found (with a stamped kind) in the user's live snapshot for that // variant at ingestion time (#1249, generalized in #1270). func (q *Queries) InsertPlayEvent(ctx context.Context, arg InsertPlayEventParams) (PlayEvent, error) { row := q.db.QueryRow(ctx, insertPlayEvent, arg.UserID, arg.TrackID, arg.SessionID, arg.StartedAt, arg.ClientID, arg.Source, arg.PickKind, ) var i PlayEvent err := row.Scan( &i.ID, &i.UserID, &i.TrackID, &i.SessionID, &i.StartedAt, &i.EndedAt, &i.DurationPlayedMs, &i.CompletionRatio, &i.WasSkipped, &i.ClientID, &i.SessionVectorAtPlay, &i.ScrobbledAt, &i.Source, &i.PickKind, ) return i, err } const insertPlaySession = `-- name: InsertPlaySession :one INSERT INTO play_sessions (user_id, started_at, last_event_at, client_id) VALUES ($1, $2, $2, $3) RETURNING id, user_id, started_at, ended_at, last_event_at, track_count, client_id ` type InsertPlaySessionParams struct { UserID pgtype.UUID StartedAt pgtype.Timestamptz ClientID *string } func (q *Queries) InsertPlaySession(ctx context.Context, arg InsertPlaySessionParams) (PlaySession, error) { row := q.db.QueryRow(ctx, insertPlaySession, arg.UserID, arg.StartedAt, arg.ClientID) var i PlaySession err := row.Scan( &i.ID, &i.UserID, &i.StartedAt, &i.EndedAt, &i.LastEventAt, &i.TrackCount, &i.ClientID, ) return i, err } const insertSkipEvent = `-- name: InsertSkipEvent :one INSERT INTO skip_events (user_id, track_id, session_id, skipped_at, position_ms) VALUES ($1, $2, $3, $4, $5) RETURNING id, user_id, track_id, session_id, skipped_at, position_ms ` type InsertSkipEventParams struct { UserID pgtype.UUID TrackID pgtype.UUID SessionID pgtype.UUID SkippedAt pgtype.Timestamptz PositionMs int32 } func (q *Queries) InsertSkipEvent(ctx context.Context, arg InsertSkipEventParams) (SkipEvent, error) { row := q.db.QueryRow(ctx, insertSkipEvent, arg.UserID, arg.TrackID, arg.SessionID, arg.SkippedAt, arg.PositionMs, ) var i SkipEvent err := row.Scan( &i.ID, &i.UserID, &i.TrackID, &i.SessionID, &i.SkippedAt, &i.PositionMs, ) return i, err } const listRecentSessionTracks = `-- name: ListRecentSessionTracks :many SELECT t.id, t.title, t.album_id, t.artist_id, t.track_number, t.disc_number, t.duration_ms, t.file_path, t.file_size, t.file_format, t.bitrate, t.mbid, t.genre, t.added_at, t.updated_at FROM tracks t JOIN play_events pe ON pe.track_id = t.id WHERE pe.session_id = $1 AND pe.started_at < $2 ORDER BY pe.started_at DESC LIMIT $3 ` type ListRecentSessionTracksParams struct { SessionID pgtype.UUID StartedAt pgtype.Timestamptz Limit int32 } // Returns up to $3 tracks in session $1 whose play_event started before // $2, ordered newest-first. Used by playevents.RecordPlayStarted to // build the session_vector for the just-inserted play_event. func (q *Queries) ListRecentSessionTracks(ctx context.Context, arg ListRecentSessionTracksParams) ([]Track, error) { rows, err := q.db.Query(ctx, listRecentSessionTracks, arg.SessionID, arg.StartedAt, arg.Limit) if err != nil { return nil, err } defer rows.Close() var items []Track for rows.Next() { var i Track if err := rows.Scan( &i.ID, &i.Title, &i.AlbumID, &i.ArtistID, &i.TrackNumber, &i.DiscNumber, &i.DurationMs, &i.FilePath, &i.FileSize, &i.FileFormat, &i.Bitrate, &i.Mbid, &i.Genre, &i.AddedAt, &i.UpdatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const touchPlaySessionLastEvent = `-- name: TouchPlaySessionLastEvent :exec UPDATE play_sessions SET last_event_at = $2, track_count = track_count + 1 WHERE id = $1 ` type TouchPlaySessionLastEventParams struct { ID pgtype.UUID LastEventAt pgtype.Timestamptz } func (q *Queries) TouchPlaySessionLastEvent(ctx context.Context, arg TouchPlaySessionLastEventParams) error { _, err := q.db.Exec(ctx, touchPlaySessionLastEvent, arg.ID, arg.LastEventAt) return err } const updatePlayEventEnded = `-- name: UpdatePlayEventEnded :one UPDATE play_events SET ended_at = $2, duration_played_ms = $3, completion_ratio = $4, was_skipped = $5 WHERE id = $1 RETURNING id, user_id, track_id, session_id, started_at, ended_at, duration_played_ms, completion_ratio, was_skipped, client_id, session_vector_at_play, scrobbled_at, source, pick_kind ` type UpdatePlayEventEndedParams struct { ID pgtype.UUID EndedAt pgtype.Timestamptz DurationPlayedMs *int32 CompletionRatio *float64 WasSkipped bool } // Closes a play_event by id with the given ended_at, duration, and skip flag. // completion_ratio is computed from duration_played_ms and the track duration // (looked up by the caller — sqlc doesn't do joins on UPDATE). func (q *Queries) UpdatePlayEventEnded(ctx context.Context, arg UpdatePlayEventEndedParams) (PlayEvent, error) { row := q.db.QueryRow(ctx, updatePlayEventEnded, arg.ID, arg.EndedAt, arg.DurationPlayedMs, arg.CompletionRatio, arg.WasSkipped, ) var i PlayEvent err := row.Scan( &i.ID, &i.UserID, &i.TrackID, &i.SessionID, &i.StartedAt, &i.EndedAt, &i.DurationPlayedMs, &i.CompletionRatio, &i.WasSkipped, &i.ClientID, &i.SessionVectorAtPlay, &i.ScrobbledAt, &i.Source, &i.PickKind, ) return i, err } const updatePlayEventVector = `-- name: UpdatePlayEventVector :exec UPDATE play_events SET session_vector_at_play = $2 WHERE id = $1 ` type UpdatePlayEventVectorParams struct { ID pgtype.UUID SessionVectorAtPlay []byte } // Used right after InsertPlayEvent to populate session_vector_at_play // once the vector has been computed. func (q *Queries) UpdatePlayEventVector(ctx context.Context, arg UpdatePlayEventVectorParams) error { _, err := q.db.Exec(ctx, updatePlayEventVector, arg.ID, arg.SessionVectorAtPlay) return err }