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
impl Database
Sourcepub fn create(
initial_settings: Doc,
instance: &Instance,
signing_key: SigningKey,
sigkey: String,
) -> Result<Self>
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- ADocCRDT 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 coordinationsigning_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()?;Sourcepub fn open_readonly(id: ID, instance: &Instance) -> Result<Self>
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- TheIDof the root entry.instance- Instance handle for storage and coordination
§Returns
A Result containing the new Database instance or an error.
Sourcepub fn open(
instance: Instance,
root_id: &ID,
signing_key: SigningKey,
sigkey: String,
) -> Result<Self>
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::Providedfor 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 coordinationroot_id- The root entry ID of the existing database to opensigning_key- Decrypted signing key from UserKeyManagersigkey- SigKey identifier string (usefind_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()?;
}Sourcepub fn find_sigkeys(
instance: &Instance,
root_id: &ID,
pubkey: &str,
) -> Result<Vec<(SigKey, Permission)>>
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 coordinationroot_id- Root entry ID of the database to checkpubkey- 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)?;
}Sourcepub fn default_auth_key(&self) -> Option<&str>
pub fn default_auth_key(&self) -> Option<&str>
Get the default authentication key ID for this database.
Sourcepub fn on_local_write<F>(&self, callback: F) -> Result<()>
pub fn on_local_write<F>(&self, callback: F) -> Result<()>
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(())
})?;Sourcepub fn on_remote_write<F>(&self, callback: F) -> Result<()>
pub fn on_remote_write<F>(&self, callback: F) -> Result<()>
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(())
})?;Sourcepub fn get_settings(&self) -> Result<SettingsStore>
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()?;Sourcepub fn new_transaction(&self) -> Result<Transaction>
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
Sourcepub fn new_transaction_with_tips(
&self,
tips: impl AsRef<[ID]>,
) -> Result<Transaction>
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
Sourcepub fn insert_raw(&self, entry: Entry) -> Result<ID>
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.
Sourcepub fn get_store_viewer<T>(&self, name: impl Into<String>) -> Result<T>where
T: Store,
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.
Sourcepub fn get_tips(&self) -> Result<Vec<ID>>
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.
Sourcepub fn get_tip_entries(&self) -> Result<Vec<Entry>>
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.
Sourcepub fn get_entry<I: Into<ID>>(&self, entry_id: I) -> Result<Entry>
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);Sourcepub fn get_entries<I, T>(&self, entry_ids: I) -> Result<Vec<Entry>>
pub fn get_entries<I, T>(&self, entry_ids: I) -> Result<Vec<Entry>>
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 toID(&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)?;Sourcepub fn verify_entry_signature<I: Into<ID>>(&self, entry_id: I) -> Result<bool>
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:
- The entry belongs to this database
- The entry is properly signed with a key that was authorized in the database’s authentication settings at the time the entry was created
- 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
Sourcepub fn get_sigkey_permission(&self, sigkey: &str) -> Result<Permission>
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!");
}Sourcepub fn get_all_entries(&self) -> Result<Vec<Entry>>
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