feat(server): GET /api/library/sync endpoint

Returns batched upserts + deletes since the supplied cursor. Empty cursor
returns full snapshot; subsequent calls pull deltas. Per-user entities
(likes, playlists) are scoped to the authed user. Composite-key entities
(likes, playlist_tracks) use stable string ids encoded by sync.EncodeLikeID
/ sync.EncodePlaylistTrackID.

Behavior:
  204 No Content - no changes since cursor
  200 OK         - JSON syncResponse {cursor, upserts, deletes}
  410 Gone       - cursor older than oldest log row; client must reset
  401 / 500      - standard envelope errors

Adds sqlc queries GetAlbumsByIDs, GetTracksByIDs, GetPlaylistsByIDs to
mirror the existing GetArtistsByIDs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 22:36:26 -04:00
parent 3959c85111
commit 9bf4b504b3
8 changed files with 641 additions and 0 deletions
+38
View File
@@ -168,6 +168,44 @@ func (q *Queries) GetAlbumCoverageRollup(ctx context.Context) (GetAlbumCoverageR
return i, err
}
const getAlbumsByIDs = `-- name: GetAlbumsByIDs :many
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version FROM albums WHERE id = ANY($1::uuid[])
`
// Batched lookup used by /api/library/sync to hydrate upsert payloads
// (#357). Mirror of GetArtistsByIDs.
func (q *Queries) GetAlbumsByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]Album, error) {
rows, err := q.db.Query(ctx, getAlbumsByIDs, dollar_1)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Album
for rows.Next() {
var i Album
if err := rows.Scan(
&i.ID,
&i.Title,
&i.SortTitle,
&i.ArtistID,
&i.ReleaseDate,
&i.Mbid,
&i.CoverArtPath,
&i.CreatedAt,
&i.UpdatedAt,
&i.CoverArtSource,
&i.CoverArtSourcesVersion,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listAlbumsAlphaByArtist = `-- name: ListAlbumsAlphaByArtist :many
SELECT albums.id, albums.title, albums.sort_title, albums.artist_id, albums.release_date, albums.mbid, albums.cover_art_path, albums.created_at, albums.updated_at, albums.cover_art_source, albums.cover_art_sources_version, artists.sort_name AS artist_sort_name
FROM albums