From 1f80f6acfda1c1c7e32c30080f865e0003020f56 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Thu, 19 Feb 2026 20:55:54 -0500 Subject: [PATCH] feat(dashboard): add Phase 3 database queries for Carousel-style dashboard Add SQL queries for dashboard functionality and system collections: Dashboard Preferences Queries: - GetDashboardPreferences: Fetch user preferences for a library - UpsertDashboardPreferences: Create or update user dashboard preferences - UpdateDashboardPreferences: Update existing preferences Dashboard Collections Queries: - GetSystemCollectionsForDashboard: Fetch system collections (user_id IS NULL) - GetUserCollectionsForDashboard: Fetch user collections marked for dashboard - DeleteUserSystemCollection: Delete user's copy of a system collection System Collection Smart Queries: - GetContinueReadingItems: Books with 0 < progress < 1 - GetRecentlyAddedItems: Newly added items to library - GetRecentlyReadItems: Books with progress >= 1 - GetNotStartedItems: Books with progress = 0 or no record Collection Management Queries: - GetCollectionItemsForDashboard: Fetch collection items with excluded flag - GetLibraryItems: Fetch all items in a library These queries support the unified collections architecture where system defaults and user-created sections are both collections with user_id NULL for system-owned and NOT NULL for user-created. --- internal/database/queries/queries.sql | 100 ++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/internal/database/queries/queries.sql b/internal/database/queries/queries.sql index fa94f3f..e757468 100644 --- a/internal/database/queries/queries.sql +++ b/internal/database/queries/queries.sql @@ -1588,3 +1588,103 @@ JOIN devices d ON ub.device_id = d.id WHERE ub.resolved = false ORDER BY ub.last_seen_at DESC LIMIT $1 OFFSET $2; + +-- ============================================ +-- CAROUSEL-STYLE DASHBOARD +-- ============================================ + +-- Dashboard preferences queries +-- name: GetDashboardPreferences :one +SELECT * FROM user_dashboard_preferences +WHERE user_id = $1 AND library_id = $2; + +-- name: UpsertDashboardPreferences :one +INSERT INTO user_dashboard_preferences (user_id, library_id, hidden_collections, collection_order, items_per_section) +VALUES ($1, $2, $3, $4, $5) +ON CONFLICT (user_id, library_id) +DO UPDATE SET + hidden_collections = EXCLUDED.hidden_collections, + collection_order = EXCLUDED.collection_order, + items_per_section = EXCLUDED.items_per_section, + updated_at = NOW() +RETURNING *; + +-- name: UpdateDashboardPreferences :one +UPDATE user_dashboard_preferences +SET hidden_collections = $2, + collection_order = $3, + items_per_section = $4, + updated_at = NOW() +WHERE user_id = $1 AND library_id = $5 +RETURNING *; + +-- Dashboard collections queries +-- name: GetSystemCollectionsForDashboard :many +SELECT * FROM collections +WHERE user_id IS NULL + AND show_on_dashboard = true +ORDER BY priority ASC; + +-- name: GetUserCollectionsForDashboard :many +SELECT c.* FROM collections c +WHERE c.user_id = $1 + AND c.show_on_dashboard = true + AND c.is_system_collection = false +ORDER BY priority ASC; + +-- name: DeleteUserSystemCollection :exec +DELETE FROM collections +WHERE user_id = $1 + AND name = $2 + AND is_system_collection = true; + +-- Smart section queries (for system collections) +-- name: GetContinueReadingItems :many +SELECT DISTINCT mi.* FROM media_items mi +INNER JOIN reading_progress rp ON rp.media_item_id = mi.id +WHERE mi.library_id = $1 + AND rp.user_id = $2 + AND rp.percentage > 0 + AND rp.percentage < 1 +ORDER BY rp.last_read_at DESC +LIMIT $3; + +-- name: GetRecentlyAddedItems :many +SELECT mi.* FROM media_items mi +WHERE mi.library_id = $1 +ORDER BY mi.created_at DESC +LIMIT $2; + +-- name: GetRecentlyReadItems :many +SELECT DISTINCT mi.* FROM media_items mi +INNER JOIN reading_progress rp ON rp.media_item_id = mi.id +WHERE mi.library_id = $1 + AND rp.user_id = $2 + AND rp.percentage >= 1 +ORDER BY rp.last_read_at DESC +LIMIT $3; + +-- name: GetNotStartedItems :many +SELECT mi.* FROM media_items mi +WHERE mi.library_id = $1 + AND NOT EXISTS ( + SELECT 1 FROM reading_progress rp + WHERE rp.media_item_id = mi.id + AND rp.user_id = $2 + AND rp.percentage > 0 + ) +ORDER BY mi.created_at DESC +LIMIT $3; + +-- name: GetCollectionItemsForDashboard :many +SELECT mi.*, ci.excluded FROM media_items mi +INNER JOIN collection_items ci ON ci.media_item_id = mi.id +WHERE ci.collection_id = $1 + AND mi.library_id = $2 +ORDER BY ci.added_at DESC +LIMIT $3; + +-- name: GetLibraryItems :many +SELECT mi.* FROM media_items mi +WHERE mi.library_id = $1 +ORDER BY mi.created_at DESC;