You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
perf: Authors page at scale — has_cover, O(n) counts, virtualized list (#122)
* feat(libcalibre): one-pass author book counts
Add Library::author_book_counts: a single GROUP BY over
books_authors_link returning a HashMap<AuthorId, i64> (authors with no
linked books are absent). Mirrors the list_series/SeriesSummary
precedent and measures 0.25ms median for 617 authors / 5,000 links in
the bench example, which gains an author_book_counts scenario.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* perf(tauri): trust has_cover; put book_count on LibraryAuthor
book_cover_image statted cover.jpg per book (PathBuf::exists), which
dominated clb_query_list_all_books at 5k books (~90% of 340ms vs 33ms
of hydration). Trust the books.has_cover flag instead — Calibre keeps
it accurate and our own cover writes (Library::set_book_cover,
Library::add_book) set it alongside writing the file. A stale flag now
yields a dangling asset URL that the frontend cover onerror fallback
absorbs. Applies to clb_query_list_all_books, clb_query_search_books,
and clb_query_books alike (shared to_library_book path).
LibraryAuthor gains book_count (u32), populated from
Library::author_book_counts everywhere the DTO is built — the authors
listing, and each book's author_list (one extra ~0.3ms map fetch per
query call) — so the Authors page no longer needs the whole book list
to render counts. bindings.ts hand-edited in specta style (field order
matches the Rust struct; LibraryBook/LibraryAuthor shapes otherwise
unchanged).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* perf(authors): backend counts + virtualized rows, drop useAllBooks
The Authors page computed each row's book count by scanning all books
per author (O(authors x books): ~480ms warm render at 617 authors /
5,000 books) and pulled the entire library via useAllBooks just for
counts and the authors-without-books filter — triggering the 340ms
list-all on page load. Both now ride on LibraryAuthor.book_count from
the authors payload; the page no longer touches the book list at all.
invalidateBooks reloads authors in the background so counts stay fresh
after book mutations (the page previously got this for free from the
stale-books reload).
The 617 author rows are also windowed with @tanstack/react-virtual
(same pattern as BookGrid), against the app's shared scroll region so
the sticky filter bar, column header, and footer behave exactly as
before.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
0 commit comments