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

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;
29pub mod store;
30pub mod sync;
31pub mod transaction;
32pub mod user;
33
34pub use auth::crypto::{PrivateKey, PublicKey};
35pub use clock::{Clock, SystemClock};
36#[cfg(any(test, feature = "testing"))]
37pub use clock::{ClockHold, FixedClock};
38pub use database::{Database, DatabaseKey};
39pub use entry::Entry;
40pub use height::HeightStrategy;
41pub use instance::{Instance, WeakInstance};
42pub use store::{Registered, Store};
43/// Re-export fundamental types for easier access.
44pub use transaction::Transaction;
45
46/// Y-CRDT types re-exported for convenience when the "y-crdt" feature is enabled.
47///
48/// This module re-exports commonly used types from the `yrs` crate so that client code
49/// doesn't need to add `yrs` as a separate dependency when using `YDoc`.
50#[cfg(feature = "y-crdt")]
51pub mod y_crdt {
52    pub use yrs::*;
53}
54
55/// Result type used throughout the Eidetica library.
56pub type Result<T, E = Error> = std::result::Result<T, E>;
57
58/// Common error type for the Eidetica library.
59#[derive(Debug, thiserror::Error)]
60pub enum Error {
61    #[error("I/O error: {0}")]
62    Io(#[from] std::io::Error),
63
64    #[error("Serialization error: {0}")]
65    Serialize(#[from] serde_json::Error),
66
67    /// Structured authentication errors from the auth module
68    #[error(transparent)]
69    Auth(auth::AuthError),
70
71    /// Structured database errors from the backend module
72    #[error(transparent)]
73    Backend(backend::BackendError),
74
75    /// Structured base database errors from the instance module
76    #[error(transparent)]
77    Instance(instance::InstanceError),
78
79    /// Structured CRDT errors from the crdt module
80    #[error(transparent)]
81    CRDT(crdt::CRDTError),
82
83    /// Structured subtree errors from the store module
84    #[error(transparent)]
85    Store(store::StoreError),
86
87    /// Structured transaction errors from the transaction module
88    #[error(transparent)]
89    Transaction(transaction::TransactionError),
90
91    /// Structured synchronization errors from the sync module
92    #[error(transparent)]
93    Sync(sync::SyncError),
94
95    /// Structured entry errors from the entry module
96    #[error(transparent)]
97    Entry(entry::EntryError),
98
99    /// Structured ID errors from the entry::id module
100    #[error(transparent)]
101    Id(entry::id::IdError),
102
103    /// Structured user errors from the user module
104    #[error(transparent)]
105    User(user::UserError),
106}
107
108impl From<sync::SyncError> for Error {
109    fn from(err: sync::SyncError) -> Self {
110        Error::Sync(err)
111    }
112}
113
114impl From<entry::EntryError> for Error {
115    fn from(err: entry::EntryError) -> Self {
116        Error::Entry(err)
117    }
118}
119
120impl From<entry::id::IdError> for Error {
121    fn from(err: entry::id::IdError) -> Self {
122        Error::Id(err)
123    }
124}
125
126impl From<user::UserError> for Error {
127    fn from(err: user::UserError) -> Self {
128        Error::User(err)
129    }
130}
131
132impl Error {
133    /// Get the originating module for this error.
134    pub fn module(&self) -> &'static str {
135        match self {
136            Error::Auth(_) => "auth",
137            Error::Backend(_) => "backend",
138            Error::Instance(_) => "instance",
139            Error::CRDT(_) => "crdt",
140            Error::Store(_) => "store",
141            Error::Transaction(_) => "transaction",
142            Error::Sync(_) => "sync",
143            Error::Entry(_) => "entry",
144            Error::Id(_) => "id",
145            Error::User(_) => "user",
146            Error::Io(_) => "io",
147            Error::Serialize(_) => "serialize",
148        }
149    }
150
151    /// Check if this error indicates a resource was not found.
152    pub fn is_not_found(&self) -> bool {
153        match self {
154            Error::Auth(auth_err) => auth_err.is_not_found(),
155            Error::Backend(backend_err) => backend_err.is_not_found(),
156            Error::Instance(base_err) => base_err.is_not_found(),
157            Error::CRDT(crdt_err) => crdt_err.is_not_found(),
158            Error::Store(store_err) => store_err.is_not_found(),
159            Error::Sync(sync_err) => sync_err.is_not_found(),
160            Error::User(user_err) => user_err.is_not_found(),
161            _ => false,
162        }
163    }
164
165    /// Check if this error indicates permission was denied.
166    pub fn is_permission_denied(&self) -> bool {
167        match self {
168            Error::Auth(auth_err) => auth_err.is_permission_denied(),
169            Error::Transaction(transaction_err) => transaction_err.is_authentication_error(),
170            _ => false,
171        }
172    }
173
174    /// Check if this error indicates a conflict (already exists).
175    pub fn is_conflict(&self) -> bool {
176        match self {
177            Error::Instance(base_err) => base_err.is_already_exists(),
178            _ => false,
179        }
180    }
181
182    /// Check if this error is authentication-related.
183    pub fn is_authentication_error(&self) -> bool {
184        match self {
185            Error::Auth(_) => true,
186            Error::Instance(base_err) => base_err.is_authentication_error(),
187            Error::Transaction(transaction_err) => transaction_err.is_authentication_error(),
188            _ => false,
189        }
190    }
191
192    /// Check if this error is database/backend-related.
193    pub fn is_database_error(&self) -> bool {
194        matches!(self, Error::Backend(_))
195    }
196
197    /// Check if this error indicates a data integrity issue.
198    pub fn is_integrity_error(&self) -> bool {
199        match self {
200            Error::Backend(backend_err) => backend_err.is_integrity_error(),
201            _ => false,
202        }
203    }
204
205    /// Check if this error is I/O related.
206    pub fn is_io_error(&self) -> bool {
207        match self {
208            Error::Io(_) => true,
209            Error::Backend(backend_err) => backend_err.is_io_error(),
210            _ => false,
211        }
212    }
213
214    /// Check if this error is base database-related.
215    pub fn is_base_database_error(&self) -> bool {
216        matches!(self, Error::Instance(_))
217    }
218
219    /// Check if this error is validation-related.
220    pub fn is_validation_error(&self) -> bool {
221        match self {
222            Error::Id(_) => true, // ID errors are validation errors
223            Error::Instance(base_err) => base_err.is_validation_error(),
224            Error::Backend(backend_err) => backend_err.is_logical_error(),
225            Error::Transaction(transaction_err) => transaction_err.is_validation_error(),
226            Error::Entry(entry_err) => entry_err.is_validation_error(),
227            _ => false,
228        }
229    }
230
231    /// Check if this error is operation-related.
232    pub fn is_operation_error(&self) -> bool {
233        match self {
234            Error::Instance(base_err) => base_err.is_operation_error(),
235            Error::Store(store_err) => store_err.is_operation_error(),
236            Error::Transaction(transaction_err) => transaction_err.is_validation_error(),
237            _ => false,
238        }
239    }
240
241    /// Check if this error is type-related.
242    pub fn is_type_error(&self) -> bool {
243        match self {
244            Error::Store(store_err) => store_err.is_type_error(),
245            _ => false,
246        }
247    }
248
249    /// Check if this error is CRDT-related.
250    pub fn is_crdt_error(&self) -> bool {
251        matches!(self, Error::CRDT(_))
252    }
253
254    /// Check if this error is a CRDT merge failure.
255    pub fn is_crdt_merge_error(&self) -> bool {
256        match self {
257            Error::CRDT(crdt_err) => crdt_err.is_merge_error(),
258            _ => false,
259        }
260    }
261
262    /// Check if this error is a CRDT serialization failure.
263    pub fn is_crdt_serialization_error(&self) -> bool {
264        match self {
265            Error::CRDT(crdt_err) => crdt_err.is_serialization_error(),
266            _ => false,
267        }
268    }
269
270    /// Check if this error is a CRDT type mismatch.
271    pub fn is_crdt_type_error(&self) -> bool {
272        match self {
273            Error::CRDT(crdt_err) => crdt_err.is_type_error(),
274            _ => false,
275        }
276    }
277
278    /// Check if this error is store-related.
279    pub fn is_store_error(&self) -> bool {
280        matches!(self, Error::Store(_))
281    }
282
283    /// Check if this error is a store serialization failure.
284    pub fn is_store_serialization_error(&self) -> bool {
285        match self {
286            Error::Store(store_err) => store_err.is_serialization_error(),
287            _ => false,
288        }
289    }
290
291    /// Check if this error is a store type mismatch.
292    pub fn is_store_type_error(&self) -> bool {
293        match self {
294            Error::Store(store_err) => store_err.is_type_error(),
295            _ => false,
296        }
297    }
298
299    /// Check if this error indicates an operation was already committed.
300    pub fn is_already_committed(&self) -> bool {
301        match self {
302            Error::Transaction(transaction_err) => transaction_err.is_already_committed(),
303            _ => false,
304        }
305    }
306
307    /// Check if this error is related to entry operations.
308    pub fn is_entry_error(&self) -> bool {
309        match self {
310            Error::Transaction(transaction_err) => transaction_err.is_entry_error(),
311            Error::Entry(_) => true,
312            _ => false,
313        }
314    }
315
316    /// Check if this error is specifically about ID validation.
317    pub fn is_id_error(&self) -> bool {
318        matches!(self, Error::Id(_))
319    }
320
321    /// Check if this error is specifically about entry structure validation.
322    pub fn is_entry_validation_error(&self) -> bool {
323        match self {
324            Error::Entry(entry_err) => entry_err.is_validation_error(),
325            _ => false,
326        }
327    }
328
329    /// Check if this error is specifically about entry serialization.
330    pub fn is_entry_serialization_error(&self) -> bool {
331        match self {
332            Error::Entry(entry_err) => entry_err.is_serialization_error(),
333            _ => false,
334        }
335    }
336}