mirror of
https://github.com/creating2morrow/neveko.git
synced 2025-01-24 11:36:13 +00:00
158 lines
5.2 KiB
Rust
158 lines
5.2 KiB
Rust
// db created and exported from here
|
|
extern crate lmdb_rs as lmdb;
|
|
|
|
use lmdb::{
|
|
DbFlags,
|
|
DbHandle,
|
|
EnvBuilder,
|
|
Environment,
|
|
};
|
|
use log::{
|
|
debug,
|
|
error,
|
|
};
|
|
|
|
use crate::utils;
|
|
|
|
/// LMDB Interface allows access to the env
|
|
///
|
|
/// and handle for the write, read and delete
|
|
///
|
|
/// functionality.
|
|
pub struct Interface {
|
|
pub env: Environment,
|
|
pub handle: DbHandle,
|
|
}
|
|
|
|
impl Interface {
|
|
/// Instantiation of ```Environment``` and ```DbHandle```
|
|
pub fn open() -> Self {
|
|
let release_env = utils::get_release_env();
|
|
let file_path = format!(
|
|
"/home/{}/.{}/",
|
|
std::env::var("USER").unwrap_or(String::from("user")),
|
|
crate::APP_NAME,
|
|
);
|
|
let mut env_str: &str = "test-lmdb";
|
|
if release_env != utils::ReleaseEnvironment::Development {
|
|
env_str = "lmdb";
|
|
};
|
|
let env = EnvBuilder::new()
|
|
.open(format!("{}/{}", file_path, env_str), 0o777)
|
|
.expect(&format!("could not open LMDB at {}", file_path));
|
|
let handle = env.get_default_db(DbFlags::empty()).unwrap();
|
|
Interface { env, handle }
|
|
}
|
|
pub async fn async_open() -> Self {
|
|
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
|
|
self::Interface::open()
|
|
}
|
|
/// Write a key-value to LMDB. NEVEKO does not currently support
|
|
///
|
|
/// writing multiple key value pairs.
|
|
pub fn write(e: &Environment, h: &DbHandle, k: &str, v: &str) {
|
|
let txn = e.new_transaction().unwrap();
|
|
{
|
|
// get a database bound to this transaction
|
|
let db = txn.bind(&h);
|
|
let pair = vec![(k, v)];
|
|
for &(key, value) in pair.iter() {
|
|
db.set(&key, &value).unwrap();
|
|
}
|
|
}
|
|
match txn.commit() {
|
|
Err(_) => error!("failed to commit!"),
|
|
Ok(_) => (),
|
|
}
|
|
}
|
|
pub async fn async_write(e: &Environment, h: &DbHandle, k: &str, v: &str) {
|
|
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
|
|
self::Interface::write(e, h, k, v)
|
|
}
|
|
/// Read a value from LMDB by passing the key as a static
|
|
///
|
|
/// string. If the value does not exist an empty string is
|
|
///
|
|
/// returned. NEVEKO does not currently support duplicate keys.
|
|
pub fn read(e: &Environment, h: &DbHandle, k: &str) -> String {
|
|
let reader = e.get_reader().unwrap();
|
|
let db = reader.bind(&h);
|
|
let value = db.get::<&str>(&k).unwrap_or_else(|_| "");
|
|
let r = String::from(value);
|
|
{
|
|
if r == utils::empty_string() {
|
|
debug!("Failed to read from db.")
|
|
}
|
|
}
|
|
r
|
|
}
|
|
pub async fn async_read(e: &Environment, h: &DbHandle, k: &str) -> String {
|
|
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
|
|
self::Interface::read(e, h, k)
|
|
}
|
|
/// Delete a value from LMDB by passing the key as a
|
|
///
|
|
/// static string. If the value does not exist then an
|
|
///
|
|
/// error will be logged.
|
|
pub fn delete(e: &Environment, h: &DbHandle, k: &str) {
|
|
let txn = e.new_transaction().unwrap();
|
|
{
|
|
// get a database bound to this transaction
|
|
let db = txn.bind(&h);
|
|
db.del(&k).unwrap_or_else(|_| error!("failed to delete"));
|
|
}
|
|
match txn.commit() {
|
|
Err(_) => error!("failed to commit!"),
|
|
Ok(_) => (),
|
|
}
|
|
}
|
|
pub async fn async_delete(e: &Environment, h: &DbHandle, k: &str) {
|
|
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
|
|
self::Interface::delete(e, h, k)
|
|
}
|
|
}
|
|
|
|
// Tests
|
|
//-------------------------------------------------------------------------------
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn async_write_and_read_test() {
|
|
// run and async cleanup so the test doesn't fail when deleting test data
|
|
use tokio::runtime::Runtime;
|
|
let rt = Runtime::new().expect("Unable to create Runtime for test");
|
|
let _enter = rt.enter();
|
|
tokio::spawn(async move {
|
|
let s = Interface::async_open().await;
|
|
let k = "async-test-key";
|
|
let v = "async-test-value";
|
|
Interface::async_write(&s.env, &s.handle, k, v).await;
|
|
let expected = String::from(v);
|
|
let actual = Interface::async_read(&s.env, &s.handle, k).await;
|
|
assert_eq!(expected, actual);
|
|
Interface::async_delete(&s.env, &s.handle, &k).await;
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn async_write_and_delete_test() {
|
|
// run and async cleanup so the test doesn't fail when deleting test data
|
|
use tokio::runtime::Runtime;
|
|
let rt = Runtime::new().expect("Unable to create Runtime for test");
|
|
let _enter = rt.enter();
|
|
tokio::spawn(async move {
|
|
let s = Interface::open();
|
|
let k = "write_and_delete_test_test-key";
|
|
let v = "write_and_delete_test_test-value";
|
|
Interface::async_write(&s.env, &s.handle, k, v).await;
|
|
let expected = utils::empty_string();
|
|
Interface::async_delete(&s.env, &s.handle, &k).await;
|
|
let actual = Interface::async_read(&s.env, &s.handle, k).await;
|
|
assert_eq!(expected, actual);
|
|
});
|
|
}
|
|
}
|