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 fn create( initial_settings: Doc, instance: &Instance, signing_key: SigningKey, sigkey: String, ) -> 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 KeySource::Provided for all subsequent operations, meaning transactions will use the provided key directly rather than looking it up from backend storage.

§Key Management Models
  • Backend-managed keys (legacy): Use Database::new() - keys stored in backend
  • User-managed keys (recommended): Use this method - keys managed by UserKeyManager
§Arguments
  • initial_settings - A Doc CRDT containing the initial settings for the database. If no auth configuration is provided, it will be bootstrapped with the provided key.
  • 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.
  • sigkey - The SigKey identifier to use in the database’s auth settings. This is typically the public key string but can be any identifier.
§Returns

A Result containing the new Database instance configured with KeySource::Provided.

§Example
let instance = Instance::open(Box::new(InMemory::new()))?;
let (signing_key, public_key) = generate_keypair();
let sigkey = format_public_key(&public_key);

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

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

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

pub fn open_readonly(id: ID, instance: &Instance) -> Result<Self>

Creates a new Database instance from an existing ID without authentication.

This constructor takes an existing ID and an Instance handle and constructs a Database instance with the specified root ID. The resulting database has no key source set, so operations will fail at commit time without authentication.

This is useful for read-only access or testing scenarios. For normal use with the User API, use Database::open() instead.

§Arguments
  • id - The ID of the root entry.
  • instance - Instance handle for storage and coordination
§Returns

A Result containing the new Database instance or an error.

Source

pub fn open( instance: Instance, root_id: &ID, signing_key: SigningKey, sigkey: String, ) -> Result<Self>

Opens an existing Database with a user-provided signing key.

This constructor opens an existing database by its root ID and configures it to use a user-provided signing key 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 KeySource::Provided 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
  • signing_key - Decrypted signing key from UserKeyManager
  • sigkey - SigKey identifier string (use find_sigkeys() to discover available options)
§Returns

A Result containing the Database instance configured with KeySource::Provided

§Example
// Find all SigKeys this public key can use
let pubkey = format_public_key(&verifying_key);
let sigkeys = Database::find_sigkeys(&instance, &root_id, &pubkey)?;

// Use the first available SigKey
if let Some((sigkey, _permission)) = sigkeys.first() {
    let sigkey_str = match sigkey {
        SigKey::Direct(name) => name.clone(),
        _ => panic!("Delegation paths not yet supported"),
    };

    // Open database with the resolved SigKey
    let database = Database::open(instance, &root_id, signing_key, sigkey_str)?;

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

pub fn find_sigkeys( instance: &Instance, root_id: &ID, pubkey: &str, ) -> 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
  • (Future) Delegation paths

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
// Get the public key string
let pubkey = format_public_key(&verifying_key);

// Find all SigKeys this pubkey can use (sorted highest permission first)
let sigkeys = Database::find_sigkeys(&instance, &root_id, &pubkey)?;

// Use the first available SigKey (highest permission)
if let Some((sigkey, _permission)) = sigkeys.first() {
    let sigkey_str = match sigkey {
        SigKey::Direct(name) => name.clone(),
        _ => panic!("Delegation paths not yet supported"),
    };
    let database = Database::open(instance, &root_id, signing_key, sigkey_str)?;
}
Source

pub fn default_auth_key(&self) -> Option<&str>

Get the default authentication key ID for this database.

Source

pub fn on_local_write<F>(&self, callback: F) -> Result<()>
where F: Fn(&Entry, &Database, &Instance) -> Result<()> + Send + Sync + '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()))?;

database.on_local_write(|entry, db, instance| {
    println!("Entry {} written to database {}", entry.id(), db.root_id());
    Ok(())
})?;
Source

pub fn on_remote_write<F>(&self, callback: F) -> Result<()>
where F: Fn(&Entry, &Database, &Instance) -> Result<()> + Send + Sync + '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()))?;

database.on_remote_write(|entry, db, instance| {
    println!("Remote entry {} synced to database {}", entry.id(), db.root_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 fn get_root(&self) -> Result<Entry>

Retrieve the root entry from the backend

Source

pub 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()?;
let name = settings.get_name()?;

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

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

Get the name of the database from its settings store

Source

pub 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 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 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 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 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 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 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 = op.commit()?;
let entry = tree.get_entry(&entry_id)?;           // Using &String
let entry = tree.get_entry("some_entry_id")?;     // Using &str
let entry = tree.get_entry(entry_id.clone())?;    // Using String
println!("Entry signature: {:?}", entry.sig);
Source

pub 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)?;
Source

pub 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 fn get_sigkey_permission(&self, sigkey: &str) -> Result<Permission>

Get the effective permission level for a given SigKey in this database.

This method checks the database’s authentication settings to determine what permission level (if any) the specified SigKey has. This is useful for validating that a user has the required permission before performing sensitive operations.

§Arguments
  • sigkey - The SigKey identifier to check permissions for
§Returns

The effective Permission for the SigKey if found

§Errors

Returns an error if:

  • The database settings cannot be retrieved
  • The authentication settings cannot be parsed
  • The SigKey is not found in the authentication settings
§Example
// Check if a key has Admin permission
let permission = database.get_sigkey_permission("my_key")?;
if permission.can_admin() {
    println!("Key has Admin permission!");
}
Source

pub 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
Source§

impl<T> CompatExt for T

Source§

fn compat(self) -> Compat<T>

Applies the Compat adapter by value. Read more
Source§

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

Applies the Compat adapter by shared reference. Read more
Source§

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.

Source§

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

Source§

fn from_ref(input: &T) -> T

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

impl<T> Instrument for T

Source§

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

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

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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

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

Initializes a with the given initializer. Read more
Source§

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

Dereferences the given pointer. Read more
Source§

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

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

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

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

Source§

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
Source§

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.
Source§

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

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

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
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

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