diff --git a/internal/audiobooks/abs/collections.go b/internal/audiobooks/abs/collections.go index 2eb3ab4c..c22d3d0c 100644 --- a/internal/audiobooks/abs/collections.go +++ b/internal/audiobooks/abs/collections.go @@ -5,10 +5,11 @@ import ( "time" ) -// CollectionStore is the narrow slice of the abs_user_collections + -// abs_collection_items tables the collections handlers need. -// Implemented by ABSCollectionStore in -// internal/audiobooks/abs_collection_store.go. +// CollectionStore is the narrow slice of user_personal_collections +// (collection_type='manual') and user_personal_collection_items +// (sub_item_id='') the collections handlers need. Implemented by +// ABSCollectionStore in internal/audiobooks/abs_collection_store.go; +// post-migration-156 it reads the unified canonical tables. type CollectionStore interface { // ListUserCollections returns collections owned by (userID, profileID), // ordered by created_at DESC. Empty slice (never nil) when none. @@ -22,7 +23,8 @@ type CollectionStore interface { // updated_at = now(). Owner check is the caller's responsibility. UpdateCollection(ctx context.Context, c Collection) error // DeleteCollection removes the collection and (via FK CASCADE) all - // its abs_collection_items. Returns nil even if no row matched. + // its user_personal_collection_items. Returns nil even if no row + // matched. DeleteCollection(ctx context.Context, id string) error // ListCollectionItems returns items ordered by added_at ASC. // Empty slice (never nil) when none. @@ -36,8 +38,8 @@ type CollectionStore interface { RemoveCollectionItem(ctx context.Context, collectionID, libraryItemID string) error } -// Collection is the in-memory representation of an -// abs_user_collections row. +// Collection is the in-memory representation of a +// user_personal_collections row with collection_type='manual'. type Collection struct { ID string UserID string @@ -49,8 +51,9 @@ type Collection struct { UpdatedAt time.Time } -// CollectionItem is the in-memory representation of an -// abs_collection_items row. +// CollectionItem is the in-memory representation of a +// user_personal_collection_items row scoped to a manual collection +// (sub_item_id=''). type CollectionItem struct { CollectionID string LibraryItemID string diff --git a/internal/audiobooks/abs/collections_handler.go b/internal/audiobooks/abs/collections_handler.go index 77b6f5f4..ec841d63 100644 --- a/internal/audiobooks/abs/collections_handler.go +++ b/internal/audiobooks/abs/collections_handler.go @@ -386,7 +386,7 @@ func (h *Handler) handleRemoveCollectionBook(w http.ResponseWriter, r *http.Requ } // handleDeleteCollection — DELETE /collections/{id}. -// Owner-only. Cascade drops abs_collection_items via FK CASCADE. +// Owner-only. Cascade drops user_personal_collection_items via FK CASCADE. // 204 on success; 404 for unknown or non-owned. func (h *Handler) handleDeleteCollection(w http.ResponseWriter, r *http.Request) { a, ok := absAuthFrom(r) diff --git a/internal/audiobooks/abs/handler.go b/internal/audiobooks/abs/handler.go index 1e364068..7ee12478 100644 --- a/internal/audiobooks/abs/handler.go +++ b/internal/audiobooks/abs/handler.go @@ -227,8 +227,10 @@ type Dependencies struct { // PlaylistStore persists ABS playlist rows (migrations 151 + 152). // May be nil; handlers respond 503 when unset. PlaylistStore PlaylistStore - // SmartCollectionStore persists abs_smart_collections rows - // (migration 153). May be nil; handlers respond 503 when unset. + // SmartCollectionStore persists user_personal_collections rows with + // collection_type='smart' (migration 156 unified the old + // abs_smart_collections table into the canonical store). + // May be nil; handlers respond 503 when unset. SmartCollectionStore SmartCollectionStore // RSSFeedStore persists abs_rss_feeds rows (migration 155). // May be nil; handlers respond 503 when unset. diff --git a/internal/audiobooks/abs/playlists.go b/internal/audiobooks/abs/playlists.go index 84b50d2f..aa0794df 100644 --- a/internal/audiobooks/abs/playlists.go +++ b/internal/audiobooks/abs/playlists.go @@ -5,9 +5,11 @@ import ( "time" ) -// PlaylistStore is the narrow slice of abs_playlists + abs_playlist_items -// the playlists handlers need. Implemented by ABSPlaylistStore in -// internal/audiobooks/abs_playlist_store.go. +// PlaylistStore is the narrow slice of user_personal_collections +// (collection_type='playlist') and user_personal_collection_items the +// playlists handlers need. Implemented by ABSPlaylistStore in +// internal/audiobooks/abs_playlist_store.go; post-migration-156 it reads +// the unified canonical tables. type PlaylistStore interface { ListUserPlaylists(ctx context.Context, userID, profileID string) ([]Playlist, error) GetPlaylist(ctx context.Context, id string) (Playlist, error) @@ -19,7 +21,8 @@ type PlaylistStore interface { RemovePlaylistItem(ctx context.Context, playlistID, libraryItemID, episodeID string) error } -// Playlist is the in-memory representation of an abs_playlists row. +// Playlist is the in-memory representation of a user_personal_collections +// row with collection_type='playlist'. type Playlist struct { ID string UserID string @@ -32,7 +35,9 @@ type Playlist struct { UpdatedAt time.Time } -// PlaylistItem is the in-memory representation of an abs_playlist_items row. +// PlaylistItem is the in-memory representation of a +// user_personal_collection_items row scoped to a playlist (sub_item_id +// may be non-empty for podcast-episode entries). type PlaylistItem struct { PlaylistID string LibraryItemID string diff --git a/internal/audiobooks/abs/playlists_handler.go b/internal/audiobooks/abs/playlists_handler.go index 9d313684..354afe8f 100644 --- a/internal/audiobooks/abs/playlists_handler.go +++ b/internal/audiobooks/abs/playlists_handler.go @@ -374,7 +374,7 @@ func (h *Handler) handleAddPlaylistItem(w http.ResponseWriter, r *http.Request) } // handleDeletePlaylist — DELETE /playlists/{id}. -// Owner-only. Cascade drops abs_playlist_items via FK. +// Owner-only. Cascade drops user_personal_collection_items via FK. // Fires playlist_removed. func (h *Handler) handleDeletePlaylist(w http.ResponseWriter, r *http.Request) { a, ok := absAuthFrom(r) diff --git a/internal/audiobooks/abs/smart_collections.go b/internal/audiobooks/abs/smart_collections.go index efc70dbc..9ab8dc7a 100644 --- a/internal/audiobooks/abs/smart_collections.go +++ b/internal/audiobooks/abs/smart_collections.go @@ -6,8 +6,10 @@ import ( "time" ) -// SmartCollectionStore is the narrow slice of abs_smart_collections -// the handlers need. +// SmartCollectionStore is the narrow slice of user_personal_collections +// (collection_type='smart') the handlers need. Post-migration-156 smart +// collections share the unified canonical table; membership is computed +// at request time via the smartcoll package (no items table). type SmartCollectionStore interface { ListUserSmartCollections(ctx context.Context, userID, profileID string) ([]SmartCollection, error) GetSmartCollection(ctx context.Context, id string) (SmartCollection, error) @@ -16,9 +18,10 @@ type SmartCollectionStore interface { DeleteSmartCollection(ctx context.Context, id string) error } -// SmartCollection mirrors an abs_smart_collections row. QueryDef holds -// the raw JSONB bytes (decoded only on the /items route where rules -// are evaluated). +// SmartCollection mirrors a user_personal_collections row with +// collection_type='smart'. QueryDef holds the raw JSONB bytes from +// query_definition (decoded only on the /items route where rules are +// evaluated). type SmartCollection struct { ID string UserID string