korrosync/service/db/mod.rs
1//! Database service layer for KoReader synchronization.
2//!
3//! This module defines the [`KorrosyncService`] trait which provides an abstract interface
4//! for managing persistent storage of user authentication and reading progress synchronization.
5//!
6//! # Implementations
7//!
8//! Currently available implementations:
9//!
10//! - [`KorrosyncServiceRedb`] - Embedded redb database implementation (default)
11//!
12
13use crate::{
14 model::{Progress, User},
15 service::error::ServiceError,
16};
17
18pub mod redb;
19pub use self::redb::KorrosyncServiceRedb;
20
21/// Trait defining the core database operations for KoReader synchronization.
22///
23/// This trait provides a database-agnostic interface for managing users and reading progress.
24/// Implementations can use any storage backend (embedded databases, SQL databases, etc.)
25/// as long as they provide these operations.
26///
27/// # Design
28///
29/// The trait uses owned `String` parameters for flexibility and to avoid lifetime issues
30/// when used with trait objects (`Arc<dyn KorrosyncService>`).
31///
32/// # Thread Safety
33///
34/// Implementations must be thread-safe when wrapped in `Arc`. All methods take `&self`
35/// to allow concurrent access from multiple threads.
36pub trait KorrosyncService {
37 /// Retrieves a user by username.
38 ///
39 /// # Arguments
40 ///
41 /// * `name` - The username to look up
42 ///
43 /// # Returns
44 ///
45 /// - `Ok(Some(user))` - User found with the given username
46 /// - `Ok(None)` - No user exists with the given username
47 /// - `Err(...)` - Unexpected database error occurred
48 fn get_user(&self, name: String) -> Result<Option<User>, ServiceError>;
49
50 /// Creates a new user or updates an existing one.
51 ///
52 /// If a user with the same username already exists, they will be overwritten.
53 ///
54 /// # Arguments
55 ///
56 /// * `user` - The user to add or update
57 ///
58 /// # Returns
59 ///
60 /// - `Ok(User)` - User was successfully created or updated
61 /// - `Err(...)` - unexpected database error occurred
62 fn create_or_update_user(&self, user: User) -> Result<User, ServiceError>;
63
64 /// Updates or creates reading progress for a user's document.
65 ///
66 /// If progress already exists for this user/document combination, it will be overwritten.
67 ///
68 /// # Arguments
69 ///
70 /// * `user` - The username of the user
71 /// * `document` - The document identifier
72 /// * `progress` - The progress information to store
73 ///
74 /// # Returns
75 ///
76 /// Returns a tuple containing:
77 /// - The document identifier (echoed back)
78 /// - The timestamp from the progress record
79 ///
80 /// # Errors
81 ///
82 /// Returns an error if an unexpected database error occurs.
83 fn update_progress(
84 &self,
85 user: String,
86 document: String,
87 progress: Progress,
88 ) -> Result<(String, u64), ServiceError>;
89
90 /// Retrieves reading progress for a specific user and document.
91 ///
92 /// # Arguments
93 ///
94 /// * `user` - The username of the user
95 /// * `document` - The document identifier to look up
96 ///
97 /// # Returns
98 ///
99 /// - `Ok(Some(progress))` - Progress found for the user/document combination
100 /// - `Ok(None)` - No progress exists for this combination
101 /// - `Err(...)` - Unexpected error occurred
102 fn get_progress(
103 &self,
104 user: String,
105 document: String,
106 ) -> Result<Option<Progress>, ServiceError>;
107
108 /// Lists all users in the database.
109 ///
110 /// # Returns
111 ///
112 /// - `Ok(Vec<User>)` - All users currently stored
113 /// - `Err(...)` - Unexpected database error occurred
114 fn list_users(&self) -> Result<Vec<User>, ServiceError>;
115
116 /// Deletes a user by username.
117 ///
118 /// # Arguments
119 ///
120 /// * `name` - The username to delete
121 ///
122 /// # Returns
123 ///
124 /// - `Ok(true)` - User existed and was deleted
125 /// - `Ok(false)` - No user with that username existed
126 /// - `Err(...)` - Unexpected database error occurred
127 fn delete_user(&self, name: String) -> Result<bool, ServiceError>;
128}