Development Documentation (main branch) - For stable release docs, see docs.rs/eidetica
Skip to main content

eidetica/
lib.rs

1//!
2//! Eidetica: A decentralized database designed to "Remember Everything".
3//! This library provides the core components for building and interacting with Eidetica instances.
4//!
5//! ## Core Concepts
6//!
7//! Eidetica is built around several key concepts:
8//!
9//! * **Entries (`Entry`)**: The fundamental, content-addressable unit of data. Entries contain data for a main database and optional named stores.
10//! * **Databases (`Database`)**: Like a traditional database or branch, representing a versioned collection of related entries identified by a root entry ID.
11//! * **Backends (`backend::Backend`)**: A pluggable storage layer for persisting entries.
12//! * **Instance (`Instance`)**: The main database struct that manages multiple databases and interacts with a backend.
13//! * **CRDTs (`crdt::CRDT`)**: Conflict-free Replicated Data Types used for merging data from different entries, particularly for settings and store data.
14//! * **Stores (`Store`)**: Named data structures within a database that provide specialized data access patterns, analogous to tables:
15//!     * **DocStore (`store::DocStore`)**: A document-oriented store for structured data with path-based operations.
16//!     * **Table (`store::Table`)**: A record-oriented store with automatic primary key generation, similar to a database table.
17//!     * **YDoc (`store::YDoc`)**: A Y-CRDT based store for collaborative data structures (requires the "y-crdt" feature).
18//! * **Merkle-CRDT**: The underlying principle combining Merkle DAGs (formed by entries and parent links) with CRDTs for efficient, decentralized data synchronization.
19
20pub mod auth;
21pub mod backend;
22pub mod clock;
23pub mod constants;
24pub mod crdt;
25pub mod database;
26pub mod entry;
27pub mod height;
28pub mod instance;
29#[cfg(all(unix, feature = "service"))]
30pub mod service;
31pub mod snapshot;
32pub mod store;
33pub mod sync;
34pub mod transaction;
35pub mod user;
36
37pub use auth::crypto::{PrivateKey, PublicKey};
38pub use clock::{Clock, SystemClock};
39#[cfg(any(test, feature = "testing"))]
40pub use clock::{ClockHold, FixedClock};
41pub use database::{Database, DatabaseKey};
42pub use entry::{Entry, ID};
43pub use height::HeightStrategy;
44pub use instance::{Instance, NewUser, WeakInstance, WriteCallback, WriteEvent, WriteSource};
45pub use snapshot::Snapshot;
46pub use store::{Registered, Store};
47/// Re-export fundamental types for easier access.
48pub use transaction::Transaction;
49
50/// Y-CRDT types re-exported for convenience when the "y-crdt" feature is enabled.
51///
52/// This module re-exports commonly used types from the `yrs` crate so that client code
53/// doesn't need to add `yrs` as a separate dependency when using `YDoc`.
54#[cfg(feature = "y-crdt")]
55pub mod y_crdt {
56    pub use yrs::*;
57}
58
59/// Result type used throughout the Eidetica library.
60pub type Result<T, E = Error> = std::result::Result<T, E>;
61
62/// Common error type for the Eidetica library.
63///
64/// All domain-specific error variants are boxed to keep `Result<T, Error>` small
65/// on the stack. The box allocation only occurs on the error (cold) path.
66///
67/// `#[error(transparent)]` works with `Box<impl Error>` because `thiserror`
68/// delegates `Display` and `source()` through the wrapper.
69#[derive(Debug, thiserror::Error)]
70pub enum Error {
71    #[error("I/O error: {0}")]
72    Io(#[from] std::io::Error),
73
74    #[error("Serialization error: {0}")]
75    Serialize(#[from] serde_json::Error),
76
77    /// Structured authentication errors from the auth module
78    #[error(transparent)]
79    Auth(Box<auth::AuthError>),
80
81    /// Structured database errors from the backend module
82    #[error(transparent)]
83    Backend(Box<backend::BackendError>),
84
85    /// Structured base database errors from the instance module
86    #[error(transparent)]
87    Instance(Box<instance::InstanceError>),
88
89    /// Structured CRDT errors from the crdt module
90    #[error(transparent)]
91    CRDT(Box<crdt::CRDTError>),
92
93    /// Structured subtree errors from the store module
94    #[error(transparent)]
95    Store(Box<store::StoreError>),
96
97    /// Structured transaction errors from the transaction module
98    #[error(transparent)]
99    Transaction(Box<transaction::TransactionError>),
100
101    /// Structured synchronization errors from the sync module
102    #[error(transparent)]
103    Sync(Box<sync::SyncError>),
104
105    /// Structured entry errors from the entry module
106    #[error(transparent)]
107    Entry(Box<entry::EntryError>),
108
109    /// Structured ID errors from the entry::id module
110    #[error(transparent)]
111    Id(Box<entry::id::IdError>),
112
113    /// Structured user errors from the user module
114    #[error(transparent)]
115    User(Box<user::UserError>),
116}
117
118impl From<sync::SyncError> for Error {
119    fn from(err: sync::SyncError) -> Self {
120        Error::Sync(Box::new(err))
121    }
122}
123
124impl From<entry::EntryError> for Error {
125    fn from(err: entry::EntryError) -> Self {
126        Error::Entry(Box::new(err))
127    }
128}
129
130impl From<entry::id::IdError> for Error {
131    fn from(err: entry::id::IdError) -> Self {
132        Error::Id(Box::new(err))
133    }
134}
135
136impl From<user::UserError> for Error {
137    fn from(err: user::UserError) -> Self {
138        Error::User(Box::new(err))
139    }
140}
141
142impl Error {
143    /// Get the originating module for this error.
144    pub fn module(&self) -> &'static str {
145        match self {
146            Error::Auth(_) => "auth",
147            Error::Backend(_) => "backend",
148            Error::Instance(_) => "instance",
149            Error::CRDT(_) => "crdt",
150            Error::Store(_) => "store",
151            Error::Transaction(_) => "transaction",
152            Error::Sync(_) => "sync",
153            Error::Entry(_) => "entry",
154            Error::Id(_) => "id",
155            Error::User(_) => "user",
156            Error::Io(_) => "io",
157            Error::Serialize(_) => "serialize",
158        }
159    }
160
161    /// Check if this error indicates a resource was not found.
162    pub fn is_not_found(&self) -> bool {
163        match self {
164            Error::Auth(auth_err) => auth_err.is_not_found(),
165            Error::Backend(backend_err) => backend_err.is_not_found(),
166            Error::Instance(base_err) => base_err.is_not_found(),
167            Error::CRDT(crdt_err) => crdt_err.is_not_found(),
168            Error::Store(store_err) => store_err.is_not_found(),
169            Error::Sync(sync_err) => sync_err.is_not_found(),
170            Error::User(user_err) => user_err.is_not_found(),
171            _ => false,
172        }
173    }
174
175    /// Check if this error indicates permission was denied.
176    pub fn is_permission_denied(&self) -> bool {
177        match self {
178            Error::Auth(auth_err) => auth_err.is_permission_denied(),
179            Error::Transaction(transaction_err) => transaction_err.is_authentication_error(),
180            _ => false,
181        }
182    }
183
184    /// Check if this error indicates a conflict (already exists).
185    pub fn is_conflict(&self) -> bool {
186        match self {
187            Error::Instance(base_err) => base_err.is_already_exists(),
188            _ => false,
189        }
190    }
191
192    /// Check if this error is authentication-related.
193    pub fn is_authentication_error(&self) -> bool {
194        match self {
195            Error::Auth(_) => true,
196            Error::Instance(base_err) => base_err.is_authentication_error(),
197            Error::Transaction(transaction_err) => transaction_err.is_authentication_error(),
198            _ => false,
199        }
200    }
201
202    /// Check if this error is database/backend-related.
203    pub fn is_database_error(&self) -> bool {
204        matches!(self, Error::Backend(_))
205    }
206
207    /// Check if this error indicates a data integrity issue.
208    pub fn is_integrity_error(&self) -> bool {
209        match self {
210            Error::Backend(backend_err) => backend_err.is_integrity_error(),
211            _ => false,
212        }
213    }
214
215    /// Check if this error is I/O related.
216    pub fn is_io_error(&self) -> bool {
217        match self {
218            Error::Io(_) => true,
219            Error::Backend(backend_err) => backend_err.is_io_error(),
220            _ => false,
221        }
222    }
223
224    /// Check if this error is base database-related.
225    pub fn is_base_database_error(&self) -> bool {
226        matches!(self, Error::Instance(_))
227    }
228
229    /// Check if this error is validation-related.
230    pub fn is_validation_error(&self) -> bool {
231        match self {
232            Error::Id(_) => true, // ID errors are validation errors
233            Error::Instance(base_err) => base_err.is_validation_error(),
234            Error::Backend(backend_err) => backend_err.is_logical_error(),
235            Error::Transaction(transaction_err) => transaction_err.is_validation_error(),
236            Error::Entry(entry_err) => entry_err.is_validation_error(),
237            _ => false,
238        }
239    }
240
241    /// Check if this error is operation-related.
242    pub fn is_operation_error(&self) -> bool {
243        match self {
244            Error::Instance(base_err) => base_err.is_operation_error(),
245            Error::Store(store_err) => store_err.is_operation_error(),
246            Error::Transaction(transaction_err) => transaction_err.is_validation_error(),
247            _ => false,
248        }
249    }
250
251    /// Check if this error is type-related.
252    pub fn is_type_error(&self) -> bool {
253        match self {
254            Error::Store(store_err) => store_err.is_type_error(),
255            _ => false,
256        }
257    }
258
259    /// Check if this error is CRDT-related.
260    pub fn is_crdt_error(&self) -> bool {
261        matches!(self, Error::CRDT(_))
262    }
263
264    /// Check if this error is a CRDT merge failure.
265    pub fn is_crdt_merge_error(&self) -> bool {
266        match self {
267            Error::CRDT(crdt_err) => crdt_err.is_merge_error(),
268            _ => false,
269        }
270    }
271
272    /// Check if this error is a CRDT serialization failure.
273    pub fn is_crdt_serialization_error(&self) -> bool {
274        match self {
275            Error::CRDT(crdt_err) => crdt_err.is_serialization_error(),
276            _ => false,
277        }
278    }
279
280    /// Check if this error is a CRDT type mismatch.
281    pub fn is_crdt_type_error(&self) -> bool {
282        match self {
283            Error::CRDT(crdt_err) => crdt_err.is_type_error(),
284            _ => false,
285        }
286    }
287
288    /// Check if this error is store-related.
289    pub fn is_store_error(&self) -> bool {
290        matches!(self, Error::Store(_))
291    }
292
293    /// Check if this error is a store serialization failure.
294    pub fn is_store_serialization_error(&self) -> bool {
295        match self {
296            Error::Store(store_err) => store_err.is_serialization_error(),
297            _ => false,
298        }
299    }
300
301    /// Check if this error is a store type mismatch.
302    pub fn is_store_type_error(&self) -> bool {
303        match self {
304            Error::Store(store_err) => store_err.is_type_error(),
305            _ => false,
306        }
307    }
308
309    /// Check if this error indicates an operation was already committed.
310    pub fn is_already_committed(&self) -> bool {
311        match self {
312            Error::Transaction(transaction_err) => transaction_err.is_already_committed(),
313            _ => false,
314        }
315    }
316
317    /// Check if this error is related to entry operations.
318    pub fn is_entry_error(&self) -> bool {
319        match self {
320            Error::Transaction(transaction_err) => transaction_err.is_entry_error(),
321            Error::Entry(_) => true,
322            _ => false,
323        }
324    }
325
326    /// Check if this error is specifically about ID validation.
327    pub fn is_id_error(&self) -> bool {
328        matches!(self, Error::Id(_))
329    }
330
331    /// Check if this error is specifically about entry structure validation.
332    pub fn is_entry_validation_error(&self) -> bool {
333        match self {
334            Error::Entry(entry_err) => entry_err.is_validation_error(),
335            _ => false,
336        }
337    }
338
339    /// Check if this error is specifically about entry serialization.
340    pub fn is_entry_serialization_error(&self) -> bool {
341        match self {
342            Error::Entry(entry_err) => entry_err.is_serialization_error(),
343            _ => false,
344        }
345    }
346}