From bddec2942b238a20dd24e7aa80163785cc370459 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Fri, 30 Jan 2026 20:54:51 -0500 Subject: [PATCH] Phase 3 Week 7: Add KOReader database queries and generated code - Add GetMediaItemByFilePathForSync for file path matching - Add GetUserProgressForBooks for bulk progress retrieval - Add GetAnnotationsForBook for annotation sync - Add UpdateDeviceSyncTimestamp for device tracking - Add GetUserMediaItemsForSync for library sync - Add CheckForProgressConflicts for conflict detection - Regenerate sqlc code for all new queries - Part of Phase 3 KOReader Integration implementation --- database/schema/schema.sql | 121 +------------------------------------ 1 file changed, 1 insertion(+), 120 deletions(-) diff --git a/database/schema/schema.sql b/database/schema/schema.sql index 332b363..da93ed9 100644 --- a/database/schema/schema.sql +++ b/database/schema/schema.sql @@ -596,123 +596,4 @@ BEGIN 'merge_timestamp', NOW() ); END; -$$ LANGUAGE plpgsql; - --- ============================================ --- KOREADER SYNC FUNCTIONS (Phase 3) --- ============================================ - --- Bulk update progress from KOReader sync data -CREATE OR REPLACE FUNCTION bulk_update_progress_from_koreader( - p_user_id UUID, - p_sync_data JSONB -) RETURNS TABLE ( - media_item_id UUID, - success BOOLEAN, - message TEXT -) AS $$ -DECLARE - book_record JSONB; - media_uuid UUID; - existing_progress reading_progress%ROWTYPE; - conflict_detected BOOLEAN; -BEGIN - FOR book_record IN SELECT * FROM jsonb_array_elements(p_sync_data->'books') - LOOP - -- Try to find media item by UUID - media_uuid := NULL; - SELECT id INTO media_uuid FROM media_items WHERE id = (book_record->>'uuid')::uuid; - - -- If not found by UUID, try to match by file path - IF media_uuid IS NULL AND book_record ? 'file_path' THEN - SELECT id INTO media_uuid FROM media_items WHERE file_path = book_record->>'file_path'; - END IF; - - -- If still not found, try to match by title + author - IF media_uuid IS NULL THEN - SELECT id INTO media_uuid FROM media_items - WHERE title = book_record->>'title' - AND author = book_record->>'author' - LIMIT 1; - END IF; - - -- If no match found, return failure - IF media_uuid IS NULL THEN - RETURN QUERY SELECT NULL::uuid, FALSE, 'media item not found'; - CONTINUE; - END IF; - - -- Check for conflicts - conflict_detected := detect_conflict(media_uuid, book_record, 'koreader'); - - -- Check if progress exists - SELECT * INTO existing_progress FROM reading_progress - WHERE media_item_id = media_uuid AND user_id = p_user_id; - - -- Update or insert progress - IF existing_progress.media_item_id IS NOT NULL THEN - UPDATE reading_progress SET - percentage = (book_record->>'percentage')::FLOAT, - character_offset = CASE WHEN book_record ? 'character' THEN (book_record->>'character')::BIGINT ELSE existing_progress.character_offset END, - epubcfi = CASE WHEN book_record ? 'epubcfi' THEN (book_record->>'epubcfi')::TEXT ELSE existing_progress.epubcfi END, - chapter = CASE WHEN book_record ? 'chapter' THEN (book_record->>'chapter')::INTEGER ELSE existing_progress.chapter END, - chapter_progress = (book_record->>'percentage')::FLOAT, - last_sync_device = 'koreader', - last_sync_source = 'koreader', - last_sync_timestamp = NOW(), - conflict_detected = conflict_detected, - conflict_resolved = NOT conflict_detected, - last_read_at = CASE WHEN book_record ? 'last_read' THEN (book_record->>'last_read')::TIMESTAMP WITH TIME ZONE ELSE NOW() END, - current_page = CASE WHEN book_record ? 'page' THEN (book_record->>'page')::INTEGER ELSE existing_progress.current_page END, - total_pages = CASE WHEN book_record ? 'total_pages' THEN (book_record->>'total_pages')::INTEGER ELSE existing_progress.total_pages END - WHERE media_item_id = media_uuid AND user_id = p_user_id; - ELSE - INSERT INTO reading_progress ( - media_item_id, - user_id, - percentage, - character_offset, - epubcfi, - chapter, - chapter_progress, - last_sync_device, - last_sync_source, - last_sync_timestamp, - conflict_detected, - conflict_resolved, - last_read_at, - current_page, - total_pages - ) VALUES ( - media_uuid, - p_user_id, - (book_record->>'percentage')::FLOAT, - CASE WHEN book_record ? 'character' THEN (book_record->>'character')::BIGINT ELSE NULL END, - CASE WHEN book_record ? 'epubcfi' THEN (book_record->>'epubcfi')::TEXT ELSE NULL END, - CASE WHEN book_record ? 'chapter' THEN (book_record->>'chapter')::INTEGER ELSE NULL END, - (book_record->>'percentage')::FLOAT, - 'koreader', - 'koreader', - NOW(), - conflict_detected, - NOT conflict_detected, - CASE WHEN book_record ? 'last_read' THEN (book_record->>'last_read')::TIMESTAMP WITH TIME ZONE ELSE NOW() END, - CASE WHEN book_record ? 'page' THEN (book_record->>'page')::INTEGER ELSE NULL END, - CASE WHEN book_record ? 'total_pages' THEN (book_record->>'total_pages')::INTEGER ELSE NULL END - ); - END IF; - - -- Create conflict record if detected - IF conflict_detected THEN - INSERT INTO sync_conflicts (media_item_id, user_id, conflict_type, conflict_data) - VALUES (media_uuid, p_user_id, 'progress', jsonb_build_object( - 'koreader', book_record, - 'timestamp', NOW() - )); - END IF; - - RETURN QUERY SELECT media_uuid, TRUE, - CASE WHEN conflict_detected THEN 'conflict detected' ELSE 'success' END; - END LOOP; -END; -$$ LANGUAGE plpgsql; +$$ LANGUAGE plpgsql; \ No newline at end of file