From 114a4574b0b7cce568bb0ccef248a4c68c2432a3 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Thu, 30 Jul 2026 11:41:05 -0400 Subject: [PATCH] feat(db): add query to count media items per visible library Add GetVisibleLibraryMediaCounts, which returns the media item count for each library visible to a given user in a single GROUP BY query over media_items. It mirrors the visibility logic in GetUserVisibleLibraries (libraries default to visible unless an explicit false row exists) so counts can be resolved in one round-trip instead of N per-library lookups. Regenerated sqlc bindings (querier.go, queries.sql.go). --- internal/database/querier.go | 1 + internal/database/queries.sql.go | 34 +++++++++++++++++++++++++++ internal/database/queries/queries.sql | 8 +++++++ 3 files changed, 43 insertions(+) diff --git a/internal/database/querier.go b/internal/database/querier.go index 4a6f720..5d8fbc2 100644 --- a/internal/database/querier.go +++ b/internal/database/querier.go @@ -303,6 +303,7 @@ type Querier interface { // Get user reading history for analytics GetUserReadingHistory(ctx context.Context, arg GetUserReadingHistoryParams) ([]GetUserReadingHistoryRow, error) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUID) ([]GetUserVisibleLibrariesRow, error) + GetVisibleLibraryMediaCounts(ctx context.Context, userID pgtype.UUID) ([]GetVisibleLibraryMediaCountsRow, error) HasRecentConflictResolution(ctx context.Context, arg HasRecentConflictResolutionParams) (bool, error) IncrementSyncQueueAttempts(ctx context.Context, arg IncrementSyncQueueAttemptsParams) (SyncQueue, error) // Check if book is in collection diff --git a/internal/database/queries.sql.go b/internal/database/queries.sql.go index 4d8327c..91961c5 100644 --- a/internal/database/queries.sql.go +++ b/internal/database/queries.sql.go @@ -7493,6 +7493,40 @@ func (q *Queries) GetUserVisibleLibraries(ctx context.Context, userID pgtype.UUI return items, nil } +const GetVisibleLibraryMediaCounts = `-- name: GetVisibleLibraryMediaCounts :many +SELECT l.id, COUNT(mi.id) as media_count +FROM libraries l +LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1 +LEFT JOIN media_items mi ON mi.library_id = l.id +WHERE COALESCE(lv.is_visible, true) = true +GROUP BY l.id +` + +type GetVisibleLibraryMediaCountsRow struct { + ID pgtype.UUID `db:"id" json:"id"` + MediaCount int64 `db:"media_count" json:"media_count"` +} + +func (q *Queries) GetVisibleLibraryMediaCounts(ctx context.Context, userID pgtype.UUID) ([]GetVisibleLibraryMediaCountsRow, error) { + rows, err := q.db.Query(ctx, GetVisibleLibraryMediaCounts, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetVisibleLibraryMediaCountsRow{} + for rows.Next() { + var i GetVisibleLibraryMediaCountsRow + if err := rows.Scan(&i.ID, &i.MediaCount); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const HasRecentConflictResolution = `-- name: HasRecentConflictResolution :one SELECT EXISTS( SELECT 1 FROM sync_conflicts diff --git a/internal/database/queries/queries.sql b/internal/database/queries/queries.sql index b26d576..eb1220a 100644 --- a/internal/database/queries/queries.sql +++ b/internal/database/queries/queries.sql @@ -137,6 +137,14 @@ LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1 WHERE COALESCE(lv.is_visible, true) = true ORDER BY l.created_at ASC; +-- name: GetVisibleLibraryMediaCounts :many +SELECT l.id, COUNT(mi.id) as media_count +FROM libraries l +LEFT JOIN library_visibility lv ON l.id = lv.library_id AND lv.user_id = $1 +LEFT JOIN media_items mi ON mi.library_id = l.id +WHERE COALESCE(lv.is_visible, true) = true +GROUP BY l.id; + -- Media Items queries -- name: CreateMediaItem :one INSERT INTO media_items (library_id, title, author, isbn, description, file_path, file_size, mime_type, cover_image_path, series, series_number, tags, tags_search, asin, date_published, publisher, contributors, contributors_search, language, edition, page_count, genre, copyright_year, goodreads_id, openlibrary_id, google_books_id, added_by_admin_id, created_at, imported_at, manga_type, reading_direction, series_count, volume, imprint, age_rating, web_url, story_arc, is_black_and_white, metadata_notes, community_rating, alternate_info, scan_information, summary, library_type_name)