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

Database

Struct Database 

Source
pub struct Database { /* private fields */ }
Expand description

Represents a collection of related entries, like a traditional database or a branch in a version control system.

Each Database is identified by the ID of its root Entry and manages the history of data associated with that root. It interacts with the underlying storage through the Instance handle.

Implementations§

Source§

impl Database

Source

pub async fn create( instance: &Instance, signing_key: PrivateKey, initial_settings: Doc, ) -> Result<Self>

Creates a new Database instance with a user-provided signing key.

This constructor creates a new database using a signing key that’s already in memory (e.g., from UserKeyManager), without requiring the key to be stored in the backend. This is the preferred method for creating databases in a User context where keys are managed separately from the backend.

The created database will use a DatabaseKey for all subsequent operations, meaning transactions will use the provided key directly rather than looking it up from backend storage.

§Auth Bootstrapping

Auth is always bootstrapped with the signing key as Admin(0). Passing auth configuration in initial_settings is an error — additional keys must be added via follow-up transactions after creation.

§Arguments
  • instance - Instance handle for storage and coordination
  • signing_key - The signing key to use for the initial commit and subsequent operations. This key should already be decrypted and ready to use. The public key is derived automatically and used as the key identifier in auth settings.
  • initial_settings - Doc CRDT containing the initial settings for the database. Use Doc::new() for an empty settings document.
§Returns

A Result containing the new Database instance configured with a DatabaseKey.

§Example
let instance = Instance::open(Box::new(InMemory::new())).await?;
let (signing_key, _public_key) = generate_keypair();

let mut settings = Doc::new();
settings.set("name", "my_database");

// Create database with user-managed key (no backend storage needed)
let database = Database::create(&instance, signing_key, settings).await?;

// All transactions automatically use the provided key
let tx = database.new_transaction().await?;
Source

pub async fn open( instance: Instance, root_id: &ID, key: DatabaseKey, ) -> Result<Self>

Opens an existing Database with a DatabaseKey.

This constructor opens an existing database by its root ID and configures it to use a DatabaseKey for all subsequent operations. This is used in the User context where keys are managed by UserKeyManager and already decrypted in memory.

§Key Management

This constructor uses user-managed keys:

  • The key is provided directly (e.g., from UserKeyManager)
  • Uses DatabaseKey for all subsequent operations
  • No backend key storage needed

Note: To create a new database with user-managed keys, use create(). This method is for opening existing databases.

To discover which SigKey to use for a given public key, use Database::find_sigkeys().

§Arguments
  • instance - Instance handle for storage and coordination
  • root_id - The root entry ID of the existing database to open
  • key - A DatabaseKey combining signing key and auth identity
§Returns

A Result containing the Database instance configured with the DatabaseKey

§Example
// Open database with pubkey identity (most common)
let key = DatabaseKey::new(signing_key);
let database = Database::open(instance, &root_id, key).await?;

// All transactions automatically use the provided key
let tx = database.new_transaction().await?;
Source

pub async fn find_sigkeys( instance: &Instance, root_id: &ID, pubkey: &PublicKey, ) -> Result<Vec<(SigKey, Permission)>>

Find all SigKeys that a public key can use to access a database.

This static helper method loads a database’s authentication settings and returns all possible SigKeys that can be used with the given public key. This is useful for discovering authentication options before opening a database.

Returns all matching SigKeys including:

  • Specific key names where the pubkey matches
  • Global permission if available
  • Single-hop delegation paths (pubkey found in a directly delegated tree)

The results are sorted by permission level, highest first, making it easy to select the most privileged access available.

§Arguments
  • instance - Instance handle for storage and coordination
  • root_id - Root entry ID of the database to check
  • pubkey - Public key string (e.g., “Ed25519:abc123…”) to look up
§Returns

A vector of (SigKey, Permission) tuples, sorted by permission (highest first). Returns empty vector if no valid access methods are found.

§Errors

Returns an error if:

  • Database cannot be loaded
  • Auth settings cannot be parsed
§Example
// Find all SigKeys this pubkey can use (sorted highest permission first)
let sigkeys = Database::find_sigkeys(&instance, &root_id, &pubkey).await?;

// Use the first available SigKey (highest permission)
if let Some((sigkey, _permission)) = sigkeys.first() {
    let key = DatabaseKey::with_identity(signing_key, sigkey.clone());
    let database = Database::open(instance, &root_id, key).await?;
}
Source

pub fn auth_identity(&self) -> Option<&SigKey>

Get the auth identity for this database’s configured key.

Source

pub fn on_local_write<F, Fut>(&self, callback: F) -> Result<()>
where F: for<'a> Fn(&'a Entry, &'a Database, &'a Instance) -> Fut + Send + Sync + 'static, Fut: Future<Output = Result<()>> + Send + 'static,

Register an Instance-wide callback to be invoked when entries are written locally to this database.

Local writes are those originating from transaction commits in the current Instance. The callback receives the entry, database, and instance as parameters, providing full context for any coordination or side effects needed.

Important: This callback is registered at the Instance level and will fire for all local writes to the database tree (identified by root ID), regardless of which Database handle performed the write. Multiple Database handles pointing to the same root ID share the same set of callbacks.

§Arguments
  • callback - Function to invoke on local writes to this database tree
§Returns

A Result indicating success or failure

§Example
let instance = Instance::open(Box::new(InMemory::new())).await?;

database.on_local_write(|entry, db, _instance| {
    let entry_id = entry.id().clone();
    let db_id = db.root_id().clone();
    Box::pin(async move {
        println!("Entry {} written to database {}", entry_id, db_id);
        Ok(())
    })
})?;
Source

pub fn on_remote_write<F, Fut>(&self, callback: F) -> Result<()>
where F: for<'a> Fn(&'a Entry, &'a Database, &'a Instance) -> Fut + Send + Sync + 'static, Fut: Future<Output = Result<()>> + Send + 'static,

Register an Instance-wide callback to be invoked when entries are written remotely to this database.

Remote writes are those originating from sync or replication from other nodes. The callback receives the entry, database, and instance as parameters.

Important: This callback is registered at the Instance level and will fire for all remote writes to the database tree (identified by root ID), regardless of which Database handle registered the callback. Multiple Database handles pointing to the same root ID share the same set of callbacks.

§Arguments
  • callback - Function to invoke on remote writes to this database tree
§Returns

A Result indicating success or failure

§Example
let instance = Instance::open(Box::new(InMemory::new())).await?;

database.on_remote_write(|entry, db, _instance| {
    let entry_id = entry.id().clone();
    let db_id = db.root_id().clone();
    Box::pin(async move {
        println!("Remote entry {} synced to database {}", entry_id, db_id);
        Ok(())
    })
})?;
Source

pub fn root_id(&self) -> &ID

Get the ID of the root entry

Source

pub fn backend(&self) -> Result<Backend>

Get a reference to the backend

Source

pub async fn get_root(&self) -> Result<Entry>

Retrieve the root entry from the backend

Source

pub async fn get_settings(&self) -> Result<SettingsStore>

Get a read-only settings store for the database.

Returns a SettingsStore that provides access to the database’s settings. Since this creates an internal transaction that is never committed, any modifications made through the returned store will not persist.

For making persistent changes to settings, create a transaction and use Transaction::get_settings() instead.

§Returns

A Result containing the SettingsStore for settings or an error.

§Example
// Read-only access
let settings = database.get_settings().await?;
let name = settings.get_name().await?;

// For modifications, use a transaction:
let txn = database.new_transaction().await?;
let settings = txn.get_settings()?;
settings.set_name("new_name").await?;
txn.commit().await?;
Source

pub async fn get_name(&self) -> Result<String>

Get the name of the database from its settings store

Source

pub async fn new_transaction(&self) -> Result<Transaction>

Create a new atomic transaction on this database

This creates a new atomic transaction containing a new Entry. The atomic transaction will be initialized with the current state of the database. If a default authentication key is set, the transaction will use it for signing.

§Returns

A Result<Transaction> containing the new atomic transaction

Source

pub async fn new_transaction_with_tips( &self, tips: impl AsRef<[ID]>, ) -> Result<Transaction>

Create a new atomic transaction on this database with specific parent tips

This creates a new atomic transaction that will have the specified entries as parents instead of using the current database tips. This allows creating complex DAG structures like diamond patterns for testing and advanced use cases.

§Arguments
  • tips - The specific parent tips to use for this transaction
§Returns

A Result<Transaction> containing the new atomic transaction

Source

pub async fn insert_raw(&self, entry: Entry) -> Result<ID>

Insert an entry into the database without modifying it. This is primarily for testing purposes or when you need full control over the entry. Note: This method assumes the entry is already properly signed and verified.

Source

pub async fn get_store_viewer<T>(&self, name: impl Into<String>) -> Result<T>
where T: Store,

Get a Store type that will handle accesses to the Store This will return a Store initialized to point at the current state of the database.

The returned store should NOT be used to modify the database, as it intentionally does not expose the Transaction. Since the Transaction is never committed, it does not have any effect on the database.

Source

pub async fn get_tips(&self) -> Result<Vec<ID>>

Get the current tips (leaf entries) of the main database branch.

Tips represent the latest entries in the database’s main history, forming the heads of the DAG.

§Returns

A Result containing a vector of IDs for the tip entries or an error.

Source

pub async fn get_tip_entries(&self) -> Result<Vec<Entry>>

Get the full Entry objects for the current tips of the main database branch.

§Returns

A Result containing a vector of the tip Entry objects or an error.

Source

pub async fn get_entry<I: Into<ID>>(&self, entry_id: I) -> Result<Entry>

Get a single entry by ID from this database.

This is the primary method for retrieving entries after commit operations. It provides safe, high-level access to entry data without exposing backend details.

The method verifies that the entry belongs to this database by checking its root ID. If the entry exists but belongs to a different database, an error is returned.

§Arguments
  • entry_id - The ID of the entry to retrieve (accepts anything that converts to ID/String)
§Returns

A Result containing the Entry or an error if not found or not part of this database

§Example
let entry_id = txn.commit().await?;
let entry = tree.get_entry(&entry_id).await?;           // Using &String
let entry = tree.get_entry("some_entry_id").await?;     // Using &str
let entry = tree.get_entry(entry_id.clone()).await?;    // Using String
println!("Entry signature: {:?}", entry.sig);
Source

pub async fn get_entries<I, T>(&self, entry_ids: I) -> Result<Vec<Entry>>
where I: IntoIterator<Item = T>, T: Into<ID>,

Get multiple entries by ID efficiently.

This method retrieves multiple entries more efficiently than multiple get_entry() calls by minimizing conversion overhead and pre-allocating the result vector.

The method verifies that all entries belong to this database by checking their root IDs. If any entry exists but belongs to a different database, an error is returned.

§Parameters
  • entry_ids - An iterable of entry IDs to retrieve. Accepts any string or ID types that can be converted to ID (&str, String, &ID, etc.)
§Returns

A Result containing a vector of Entry objects or an error if any entry is not found or not part of this database

§Example
let entry_ids = vec!["id1", "id2", "id3"];
let entries = tree.get_entries(entry_ids).await?;
Source

pub async fn verify_entry_signature<I: Into<ID>>( &self, entry_id: I, ) -> Result<bool>

Verify an entry’s signature and authentication against the database’s configuration that was valid at the time of entry creation.

This method validates that:

  1. The entry belongs to this database
  2. The entry is properly signed with a key that was authorized in the database’s authentication settings at the time the entry was created
  3. The signature is cryptographically valid

The method uses the entry’s metadata to determine which authentication settings were active when the entry was signed, ensuring that entries remain valid even if keys are later revoked or settings change.

§Arguments
  • entry_id - The ID of the entry to verify (accepts anything that converts to ID/String)
§Returns

A Result containing true if the entry is valid and properly authenticated, false if authentication fails

§Errors

Returns an error if:

  • The entry is not found
  • The entry does not belong to this database
  • The entry’s metadata cannot be parsed
  • The historical authentication settings cannot be retrieved
Source

pub async fn current_permission(&self) -> Result<Permission>

Get the permission level for this database’s configured signing key.

Returns the effective permission for the key that was configured when opening or creating this database. This uses the already-resolved identity stored in the database’s DatabaseKey, ensuring consistency with Database::open.

§Returns

The effective Permission for the configured signing key.

§Errors

Returns an error if:

  • No signing key is configured (database opened without authentication)
  • The database settings cannot be retrieved
  • The key is no longer valid in the current auth settings
§Example
// Check if the current key has Admin permission
let permission = database.current_permission().await?;
if permission.can_admin() {
    println!("Current key has Admin permission!");
}
Source

pub async fn get_all_entries(&self) -> Result<Vec<Entry>>

Get all entries in this database.

⚠️ Warning: This method loads all entries into memory. Use with caution on large databases. Consider using get_tips() or get_tip_entries() for more efficient access patterns.

§Returns

A Result containing a vector of all Entry objects in the database

Trait Implementations§

Source§

impl Clone for Database

Source§

fn clone(&self) -> Database

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Database

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> CompatExt for T

§

fn compat(self) -> Compat<T>

Applies the [Compat] adapter by value. Read more
§

fn compat_ref(&self) -> Compat<&T>

Applies the [Compat] adapter by shared reference. Read more
§

fn compat_mut(&mut self) -> Compat<&mut T>

Applies the [Compat] adapter by mutable reference. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FromRef<T> for T
where T: Clone,

§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more