morethantext-web/src/morethantext/cache.rs

169 lines
4.2 KiB
Rust

use super::{DBError, SessionData, Store};
use async_std::{fs::write, path::Path};
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use std::{
cell::Cell,
time::{Duration, Instant},
};
#[derive(Clone)]
enum DataType {
DBMap(Store),
}
impl DataType {
fn new(data_type: &str) -> Result<Self, DBError> {
match data_type {
"store" => Ok(DataType::DBMap(Store::new())),
_ => Err(DBError::new("invalid data type")),
}
}
}
impl SessionData for DataType {
fn add(&mut self, key: &str, value: &str, data: &str) -> Result<Vec<String>, DBError> {
match self {
DataType::DBMap(dbs) => dbs.add(key, value, data),
}
}
fn eq(&self, key: &str, value: &str) -> Result<Vec<String>, DBError> {
match self {
DataType::DBMap(dbs) => dbs.eq(key, value),
}
}
fn list(&self, keys: Vec<&str>) -> Result<Vec<String>, DBError> {
match self {
DataType::DBMap(dbs) => dbs.list(keys),
}
}
}
struct Entry {
data: DataType,
filename: String,
last_used: Cell<Instant>,
}
impl Entry {
async fn new(filename: String, data: DataType) -> Result<Self, DBError> {
if Path::new(&filename).exists().await {
return Err(DBError::new("entry already exists"));
}
Ok(Self {
data: data,
filename: filename,
last_used: Cell::new(Instant::now()),
})
}
async fn get(&self) -> Result<DataType, DBError> {
Ok(self.data.clone())
}
}
struct Cache;
impl Cache {
async fn new(dir: &str) -> Self {
Self
}
}
#[cfg(test)]
mod datatype_sesssion {
use super::*;
#[test]
fn invalid_cache_type() -> Result<(), DBError> {
match DataType::new("dkhgdl") {
Ok(_) => Err(DBError::new("invalid data type should raise an error")),
Err(err) => {
assert_eq!(err.to_string(), "invalid data type");
Ok(())
}
}
}
#[test]
fn create_storage() {
let dbs = DataType::new("store").unwrap();
let expected: Vec<String> = Vec::new();
assert_eq!(dbs.list(["database"].to_vec()).unwrap(), expected);
}
#[test]
fn update_storage() {
let mut dbs = DataType::new("store").unwrap();
let name = "new_database";
let id = "someid";
dbs.add("database", name, id).unwrap();
assert_eq!(dbs.eq("database", name).unwrap(), [id].to_vec());
assert_eq!(dbs.list(["database"].to_vec()).unwrap(), [name].to_vec());
}
}
#[cfg(test)]
mod datatype_file {
use super::*;
// Test file data traits here.
}
#[cfg(test)]
mod entry {
use super::*;
use tempfile::tempdir;
#[async_std::test]
async fn create() {
let dir = tempdir().unwrap();
let mut data = DataType::new("store").unwrap();
data.add("database", "roger", "moore").unwrap();
let filepath = dir.path().join("wiliam");
let filename = filepath.to_str().unwrap();
let item = Entry::new(filename.to_string(), data.clone())
.await
.unwrap();
let output = item.get().await.unwrap();
assert_eq!(
data.list(["database"].to_vec()).unwrap(),
output.list(["database"].to_vec()).unwrap()
);
}
#[async_std::test]
async fn no_over_writes() -> Result<(), DBError> {
let dir = tempdir().unwrap();
let id = "wicked";
let file = dir.path().join(id);
let filename = file.to_str().unwrap();
write(&file, b"previous").await.unwrap();
let data = DataType::new("store").unwrap();
match Entry::new(filename.to_string(), data).await {
Ok(_) => {
return Err(DBError::new(
"Should produce an error for an existing Entry",
))
}
Err(err) => {
assert_eq!(err.to_string(), "entry already exists");
Ok(())
}
}
}
}
#[cfg(test)]
mod cache {
use super::*;
use tempfile::tempdir;
#[async_std::test]
async fn create() {
let dir = tempdir().unwrap();
Cache::new(dir.path().to_str().unwrap()).await;
}
}