neveko/neveko-core/src/db.rs

159 lines
5.2 KiB
Rust
Raw Normal View History

2023-04-30 15:55:41 +00:00
// db created and exported from here
extern crate lmdb_rs as lmdb;
2023-05-09 21:28:07 +00:00
use lmdb::{
DbFlags,
DbHandle,
EnvBuilder,
Environment,
};
use log::{
debug,
error,
};
2023-04-30 15:55:41 +00:00
use crate::utils;
2023-05-17 14:18:22 +00:00
/// LMDB Interface allows access to the env
///
/// and handle for the write, read and delete
///
/// functionality.
2023-04-30 15:55:41 +00:00
pub struct Interface {
pub env: Environment,
pub handle: DbHandle,
}
impl Interface {
2023-05-17 14:18:22 +00:00
/// Instantiation of ```Environment``` and ```DbHandle```
2023-04-30 15:55:41 +00:00
pub fn open() -> Self {
let release_env = utils::get_release_env();
2023-05-09 21:28:07 +00:00
let file_path = format!(
2023-06-03 15:22:40 +00:00
"/home/{}/.{}/",
std::env::var("USER").unwrap_or(String::from("user")),
crate::APP_NAME,
2023-05-09 21:28:07 +00:00
);
2023-04-30 15:55:41 +00:00
let mut env_str: &str = "test-lmdb";
2023-05-09 21:28:07 +00:00
if release_env != utils::ReleaseEnvironment::Development {
env_str = "lmdb";
};
let env = EnvBuilder::new()
.open(format!("{}/{}", file_path, env_str), 0o777)
2023-05-17 14:18:22 +00:00
.expect(&format!("could not open LMDB at {}", file_path));
2023-04-30 15:55:41 +00:00
let handle = env.get_default_db(DbFlags::empty()).unwrap();
Interface { env, handle }
}
2023-05-20 08:05:48 +00:00
pub async fn async_open() -> Self {
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
self::Interface::open()
}
2023-06-03 14:17:58 +00:00
/// Write a key-value to LMDB. NEVEKO does not currently support
2023-05-17 14:18:22 +00:00
///
/// writing multiple key value pairs.
2023-04-30 15:55:41 +00:00
pub fn write(e: &Environment, h: &DbHandle, k: &str, v: &str) {
let txn = e.new_transaction().unwrap();
{
// get a database bound to this transaction
2023-05-09 21:28:07 +00:00
let db = txn.bind(&h);
let pair = vec![(k, v)];
for &(key, value) in pair.iter() {
db.set(&key, &value).unwrap();
}
2023-04-30 15:55:41 +00:00
}
match txn.commit() {
Err(_) => error!("failed to commit!"),
2023-05-09 21:28:07 +00:00
Ok(_) => (),
2023-04-30 15:55:41 +00:00
}
}
2023-05-20 15:39:50 +00:00
pub async fn async_write(e: &Environment, h: &DbHandle, k: &str, v: &str) {
2023-05-20 08:05:48 +00:00
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
self::Interface::write(e, h, k, v)
}
2023-05-17 14:18:22 +00:00
/// Read a value from LMDB by passing the key as a static
///
/// string. If the value does not exist an empty string is
///
2023-06-03 14:17:58 +00:00
/// returned. NEVEKO does not currently support duplicate keys.
2023-04-30 15:55:41 +00:00
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
}
2023-05-20 15:39:50 +00:00
pub async fn async_read(e: &Environment, h: &DbHandle, k: &str) -> String {
2023-05-20 08:05:48 +00:00
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
self::Interface::read(e, h, k)
}
2023-05-17 14:18:22 +00:00
/// 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.
2023-04-30 15:55:41 +00:00
pub fn delete(e: &Environment, h: &DbHandle, k: &str) {
let txn = e.new_transaction().unwrap();
{
// get a database bound to this transaction
2023-05-09 21:28:07 +00:00
let db = txn.bind(&h);
db.del(&k).unwrap_or_else(|_| error!("failed to delete"));
2023-04-30 15:55:41 +00:00
}
match txn.commit() {
Err(_) => error!("failed to commit!"),
2023-05-09 21:28:07 +00:00
Ok(_) => (),
2023-04-30 15:55:41 +00:00
}
}
2023-05-20 08:05:48 +00:00
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)
}
2023-04-30 15:55:41 +00:00
}
2023-05-17 14:18:22 +00:00
// Tests
//-------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[test]
2023-05-20 08:05:48 +00:00
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;
});
2023-05-17 14:18:22 +00:00
}
#[test]
2023-05-20 08:05:48 +00:00
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);
});
2023-05-17 14:18:22 +00:00
}
}