pub struct Database<T, S = FileSource> where
T: IntoJson + FromJson + 'static,
S: Source, { /* private fields */ }Expand description
Represents a JasonDB database.
The type of values in the database is specified by the T generic parameter.
This must implement Humphrey JSON’s IntoJson and FromJson traits, which can be done
with its json_map macro.
These traits are automatically implemented for basic types like strings and numbers.
Example
use jasondb::Database;
use jasondb::error::JasonError;
use humphrey_json::prelude::*;
struct Person {
name: String,
age: u8,
}
json_map! {
Person,
name => "name",
age => "age"
}
fn main() -> Result<(), JasonError> {
let mut db: Database<Person> = Database::new("database.jdb")?;
db.set("alice", Person {
name: "Alice".to_string(),
age: 20,
})?;
db.set("bob", Person {
name: "Bob".to_string(),
age: 24,
})?;
let alice = db.get("alice")?;
assert_eq!(alice.age, 20);
Ok(())
}Implementations
sourceimpl<T> Database<T, FileSource> where
T: IntoJson + FromJson,
impl<T> Database<T, FileSource> where
T: IntoJson + FromJson,
sourcepub fn new(path: impl AsRef<Path>) -> Result<Self, JasonError>
pub fn new(path: impl AsRef<Path>) -> Result<Self, JasonError>
Opens the database from the given path, or creates an empty one if it doesn’t exist.
To create an empty database and throw an error if it already exists, use create.
To open an existing database and throw an error if it doesn’t exist, use open.
sourcepub fn create(path: impl AsRef<Path>) -> Result<Self, JasonError>
pub fn create(path: impl AsRef<Path>) -> Result<Self, JasonError>
Creates a new empty database at the given path.
If the file already exists, an error will be thrown.
sourcepub fn open(path: impl AsRef<Path>) -> Result<Self, JasonError>
pub fn open(path: impl AsRef<Path>) -> Result<Self, JasonError>
Opens an existing database at the given path.
If the file doesn’t exist, an error will be thrown.
sourcepub fn into_memory(self) -> Result<Database<T, InMemory>, JasonError>
pub fn into_memory(self) -> Result<Database<T, InMemory>, JasonError>
Converts the file-based database into an in-memory database by copying the contents of the file into memory.
Warning: changes made to the new in-memory database will not be reflected in the original file-based database.
sourceimpl<T> Database<T, InMemory> where
T: IntoJson + FromJson,
impl<T> Database<T, InMemory> where
T: IntoJson + FromJson,
sourcepub fn new_in_memory() -> Self
pub fn new_in_memory() -> Self
Creates a new empty in-memory database.
sourceimpl<T, S> Database<T, S> where
T: IntoJson + FromJson,
S: Source,
impl<T, S> Database<T, S> where
T: IntoJson + FromJson,
S: Source,
sourcepub fn from_source(source: S) -> Result<Self, JasonError>
pub fn from_source(source: S) -> Result<Self, JasonError>
Creates a new database backed by the given source.
sourcepub fn with_compaction(self) -> Result<Self, JasonError>
pub fn with_compaction(self) -> Result<Self, JasonError>
Compacts the database on load.
For smaller databases and for frequently-updated databases, it is good practice to do this on load. For more read-oriented databases, it can offer a minor performance boost but it does take longer to load.
sourcepub fn with_index(self, field: impl AsRef<str>) -> Result<Self, JasonError>
pub fn with_index(self, field: impl AsRef<str>) -> Result<Self, JasonError>
Configures the database to use the given secondary index. This is intended for use in a builder pattern as the example below shows.
The field can be given as a dot-separated string or using the field macro, and it specifies how to find the field to index in the JSON representation of the type.
Example
let mut db = Database::new(source)?
.with_index(field!(my_field.my_subfield))?
.with_index("my_field.my_other_subfield")?;sourcepub fn with_replica<R>(self, replica: R) -> Self where
R: Replica<T>,
pub fn with_replica<R>(self, replica: R) -> Self where
R: Replica<T>,
Adds a synchronous replica to the database.
This is useful to add persistence to an in-memory database. By having an in-memory database with a synchronous file-based replica, you get the speed of the in-memory database for reads and the persistence of the file-based replica for writes. This is a good idea for databases that get many reads and less writes.
All writes to the database will be replicated to the all configured replicas synchronously, so having many replicas or having slow ones can slow down writes.
Any implementor of the Replica trait can be used. Currently, this is just Database, but the API has been
designed in such a way that in the future, other types of replica could be used, for example distributed
replicas or even other database systems completely.
Example
// Creating a new in-memory database with synchronous replication to disk.
let mut db = Database::new_in_memory()
.with_replica(Database::create("sync_file_replica.jdb")?);
// Opening a disk-based database, copying it into memory, and synchronously replicating it back to disk.
let mut db = Database::open("database.jdb")?
.into_memory()?
.with_replica(Database::open("database.jdb")?);sourcepub fn with_async_replica<R>(self, replica: R) -> Self where
R: Replica<T>,
pub fn with_async_replica<R>(self, replica: R) -> Self where
R: Replica<T>,
Adds an asynchronous replica to the database, and starts a background thread to replicate writes to it.
All writes to the database will be replicated to the all configured replicas asynchronously, so data loss
is possible in the event of a panic. The database will attempt to continue replicating writes to the
replica if an error causes the database to be dropped, but if drop is not called, all
pending writes will be lost.
Any implementor of the Replica trait can be used. Currently, this is just Database, but the API has been
designed in such a way that in the future, other types of replica could be used, for example distributed
replicas or even other database systems completely.
Example
let mut db = Database::new_in_memory()
.with_async_replica(Database::create("async_file_replica.jdb")?);sourcepub fn get(&mut self, key: impl AsRef<str>) -> Result<T, JasonError>
pub fn get(&mut self, key: impl AsRef<str>) -> Result<T, JasonError>
Gets the value with the given key.
Returns Err(JasonError::InvalidKey) if the index is not found, or another error if the source fails.
sourcepub fn set(
&mut self,
key: impl AsRef<str>,
value: impl Borrow<T>
) -> Result<(), JasonError>
pub fn set(
&mut self,
key: impl AsRef<str>,
value: impl Borrow<T>
) -> Result<(), JasonError>
Sets the value with the given key to the given value.
Updates all indexes with the new value.
sourcepub fn delete(&mut self, key: impl AsRef<str>) -> Result<(), JasonError>
pub fn delete(&mut self, key: impl AsRef<str>) -> Result<(), JasonError>
Deletes the value with the given key.
This appends a null value to the end of the database, and updates all indexes.
sourcepub fn query(&mut self, query: Query) -> Result<Iter<'_, T, S>, JasonError>
pub fn query(&mut self, query: Query) -> Result<Iter<'_, T, S>, JasonError>
Executes the given query on the database.
Queries are typically constructed with the query! macro.
sourcepub fn iter(&mut self) -> Iter<'_, T, S>
pub fn iter(&mut self) -> Iter<'_, T, S>
Creates an iterator over the database.
This only reads from the database when it is used, so is very cheap to create. It does, however,
sort the keys so it can iterate over the database in the order in which it is stored on disk.
To avoid this behaviour, use the iter_unordered method instead.
sourcepub fn iter_unordered(&mut self) -> Iter<'_, T, S>
pub fn iter_unordered(&mut self) -> Iter<'_, T, S>
Creates an iterator over the database, but does not sort the keys.
This is quicker to create, but will be slower to iterate over since the disk will not be read sequentially.
sourcepub fn compact(&mut self) -> Result<(), JasonError>
pub fn compact(&mut self) -> Result<(), JasonError>
Performs compaction on the database.
Trait Implementations
Auto Trait Implementations
impl<T, S = FileSource> !RefUnwindSafe for Database<T, S>
impl<T, S> Send for Database<T, S> where
S: Send,
T: Send,
impl<T, S = FileSource> !Sync for Database<T, S>
impl<T, S> Unpin for Database<T, S> where
S: Unpin,
T: Unpin,
impl<T, S = FileSource> !UnwindSafe for Database<T, S>
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more