Skip to content

refactor(client): generic Page[T] paging envelope - #41

Merged
rianjs merged 3 commits into
mainfrom
refactor/31-generic-page
Jul 25, 2026
Merged

rianjs merged 3 commits into
mainfrom
refactor/31-generic-page

Conversation

@rianjs

@rianjs rianjs commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • replace seven exported page structs and nine endpoint wire validations with generic Page[T] and pageResponse[T]
  • preserve endpoint-specific item validation, playlist total/next consistency, and mixed-media playlist-item decoding
  • centralize search query construction

LOC delta: +97/-228 (net -131)

Validation observations

  • SearchTracks intentionally performs no per-item validation; album and artist search require nonblank item IDs
  • current-user playlists require valid playlist IDs and nonnegative item-count metadata
  • playlist items retain their separate wrapper decoding and track/episode/local/unavailable validation rules
  • Page.Total is retained because playlist mutation flows consume it to detect provider drift during traversal

Verification

  • go build ./...
  • go vet ./...
  • make test
  • golangci-lint run

Closes #31

@rianjs

rianjs commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

TDD assessment

Insufficient.

The shared invalid-page logic is otherwise well pinned:

  • TestCatalogSearchRejectsMalformedPages sends {} for album and artist search and expects ErrInvalidResponse, so the new value-typed missing-outer-envelope/zero-value path is covered. TestSearchTracksRejectsInconsistentPaging separately covers missing and null items; adding {} there would be harmless redundancy, not a requirement for a generic helper.
  • Search, traversal, and playlist tests exercise missing items, offset mismatch, limit mismatch, negative total, and over-limit items through page(). Saved tests exercise the same shared path for missing items, offset/limit mismatch, and negative total but omit over-limit items; that duplication is not necessary because another caller pins the generic branch and saved tests prove those endpoints route through it.

The blocking gap is the successful playlist-item page mapping: ListPlaylistItems reconstructs PlaylistItemPage without Total, so the existing response with "total":27 returns page.Total == 0. That is observable and breaks callers that use totals for traversal/provider-drift checks, yet all unit tests pass.

Cheapest fix: in TestListPlaylistItemsUsesCurrentFixedPathAndDecodesMixedItems, add the exact assertion page.Total == 27 (equivalently fail when page.Total != 27) alongside the existing offset/HasNext assertions. That one assertion catches the current regression; no broad per-endpoint duplication of every shared validation branch is needed.

@rianjs
rianjs merged commit ac57ba7 into main Jul 25, 2026
9 checks passed
@rianjs
rianjs deleted the refactor/31-generic-page branch July 25, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(client): generic Page[T] paging envelope

1 participant