added Entry update function.

This commit is contained in:
Jeff Baskin 2023-02-15 12:13:19 -05:00
parent ef48fde890
commit c0e4a5fad7
1 changed files with 110 additions and 20 deletions

View File

@ -1,10 +1,12 @@
use super::{DBError, FileData, SessionData, Store}; use super::{DBError, FileData, SessionData, Store};
use async_std::{fs::{read, write}, path::Path}; use async_std::{
fs::{read, remove_file, write},
path::Path,
};
use rand::{distributions::Alphanumeric, thread_rng, Rng}; use rand::{distributions::Alphanumeric, thread_rng, Rng};
use std::{ use std::{
cell::Cell, cell::Cell,
slice, slice, str,
str,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -50,7 +52,7 @@ impl FileData<Self> for DataType {
output.append(&mut "DBMap".as_bytes().to_vec()); output.append(&mut "DBMap".as_bytes().to_vec());
output.push(0); output.push(0);
output.append(&mut store.to_bytes()); output.append(&mut store.to_bytes());
}, }
} }
output output
} }
@ -73,11 +75,9 @@ impl FileData<Self> for DataType {
Err(_) => return Err(DBError::new("file corruption")), Err(_) => return Err(DBError::new("file corruption")),
}; };
match header { match header {
"DBMap" => { "DBMap" => match Store::from_bytes(data) {
match Store::from_bytes(data) { Ok(store) => Ok(DataType::DBMap(store)),
Ok(store) => Ok(DataType::DBMap(store)), Err(err) => Err(err),
Err(err) => Err(err),
}
}, },
_ => Err(DBError::new("file corruption")), _ => Err(DBError::new("file corruption")),
} }
@ -120,6 +120,21 @@ impl Entry {
self.last_used.set(Instant::now()); self.last_used.set(Instant::now());
Ok(self.data.clone()) Ok(self.data.clone())
} }
async fn update(&mut self, data: DataType) -> Result<(), DBError> {
self.last_used.set(Instant::now());
let filepath = Path::new(&self.filename);
match write(filepath, data.to_bytes()).await {
Ok(_) => (),
Err(err) => {
let mut error = DBError::new("write error");
error.add_source(err);
return Err(error);
}
};
self.data = data;
Ok(())
}
} }
struct Cache; struct Cache;
@ -194,7 +209,10 @@ mod datatype_file {
let data = dt_store.to_bytes(); let data = dt_store.to_bytes();
let mut feed = data.iter(); let mut feed = data.iter();
let output = DataType::from_bytes(&mut feed).unwrap(); let output = DataType::from_bytes(&mut feed).unwrap();
assert_eq!(dt_store.list(["database"].to_vec()).unwrap(), output.list(["database"].to_vec()).unwrap()); assert_eq!(
dt_store.list(["database"].to_vec()).unwrap(),
output.list(["database"].to_vec()).unwrap()
);
} }
#[test] #[test]
@ -204,7 +222,10 @@ mod datatype_file {
let data = dt_store.to_bytes(); let data = dt_store.to_bytes();
let mut feed = data.iter(); let mut feed = data.iter();
let output = DataType::from_bytes(&mut feed).unwrap(); let output = DataType::from_bytes(&mut feed).unwrap();
assert_eq!(dt_store.list(["database"].to_vec()).unwrap(), output.list(["database"].to_vec()).unwrap()); assert_eq!(
dt_store.list(["database"].to_vec()).unwrap(),
output.list(["database"].to_vec()).unwrap()
);
} }
#[test] #[test]
@ -216,7 +237,7 @@ mod datatype_file {
Err(err) => { Err(err) => {
assert_eq!(err.to_string(), "file corruption"); assert_eq!(err.to_string(), "file corruption");
Ok(()) Ok(())
}, }
} }
} }
@ -231,7 +252,7 @@ mod datatype_file {
Err(err) => { Err(err) => {
assert_eq!(err.to_string(), "file corruption"); assert_eq!(err.to_string(), "file corruption");
Ok(()) Ok(())
}, }
} }
} }
} }
@ -249,9 +270,16 @@ mod entry {
let filepath = dir.path().join("count"); let filepath = dir.path().join("count");
let filename = filepath.to_str().unwrap(); let filename = filepath.to_str().unwrap();
let item = Entry::new(filename.to_string(), data).await.unwrap(); let item = Entry::new(filename.to_string(), data).await.unwrap();
assert!(Duration::from_secs(1) > item.elapsed(), "last_used should have been now."); assert!(
item.last_used.set(Instant::now() - Duration::from_secs(500)); Duration::from_secs(1) > item.elapsed(),
assert!(Duration::from_secs(499) < item.elapsed(), "The duration should have increased."); "last_used should have been now."
);
item.last_used
.set(Instant::now() - Duration::from_secs(500));
assert!(
Duration::from_secs(499) < item.elapsed(),
"The duration should have increased."
);
} }
#[async_std::test] #[async_std::test]
@ -264,7 +292,10 @@ mod entry {
let item = Entry::new(filename.to_string(), data.clone()) let item = Entry::new(filename.to_string(), data.clone())
.await .await
.unwrap(); .unwrap();
assert!(Duration::from_secs(1) > item.elapsed(), "last_used should have been now."); assert!(
Duration::from_secs(1) > item.elapsed(),
"last_used should have been now."
);
let output = item.get().await.unwrap(); let output = item.get().await.unwrap();
assert_eq!( assert_eq!(
data.list(["database"].to_vec()).unwrap(), data.list(["database"].to_vec()).unwrap(),
@ -286,7 +317,11 @@ mod entry {
Err(err) => { Err(err) => {
assert_eq!(err.to_string(), "failed to write"); assert_eq!(err.to_string(), "failed to write");
assert!(err.source().is_some(), "Must include the source error."); assert!(err.source().is_some(), "Must include the source error.");
assert!(err.source().unwrap().to_string().contains("could not write to file")); assert!(err
.source()
.unwrap()
.to_string()
.contains("could not write to file"));
Ok(()) Ok(())
} }
} }
@ -320,9 +355,64 @@ mod entry {
let filepath = dir.path().join("holder"); let filepath = dir.path().join("holder");
let filename = filepath.to_str().unwrap(); let filename = filepath.to_str().unwrap();
let item = Entry::new(filename.to_string(), data).await.unwrap(); let item = Entry::new(filename.to_string(), data).await.unwrap();
item.last_used.set(Instant::now() - Duration::from_secs(300)); item.last_used
.set(Instant::now() - Duration::from_secs(300));
item.get().await.unwrap(); item.get().await.unwrap();
assert!(Duration::from_secs(1) > item.elapsed(), "last_used should have been reset."); assert!(
Duration::from_secs(1) > item.elapsed(),
"last_used should have been reset."
);
}
#[async_std::test]
async fn update_entry() {
let dir = tempdir().unwrap();
let mut data = DataType::new("store").unwrap();
let filepath = dir.path().join("changing");
let filename = filepath.to_str().unwrap();
let mut item = Entry::new(filename.to_string(), data.clone())
.await
.unwrap();
item.last_used
.set(Instant::now() - Duration::from_secs(500));
data.add("database", "new", "stuff").unwrap();
item.update(data.clone()).await.unwrap();
assert!(
Duration::from_secs(1) > item.elapsed(),
"last_used should have been reset."
);
let output = item.get().await.unwrap();
assert_eq!(
data.list(["database"].to_vec()).unwrap(),
output.list(["database"].to_vec()).unwrap()
);
let content = read(&filepath).await.unwrap();
assert_eq!(content, data.to_bytes());
}
#[async_std::test]
async fn update_write_errors() -> Result<(), DBError> {
let dir = tempdir().unwrap();
let data = DataType::new("store").unwrap();
let filepath = dir.path().join("changing");
let filename = filepath.to_str().unwrap();
let mut item = Entry::new(filename.to_string(), data.clone())
.await
.unwrap();
drop(dir);
match item.update(data).await {
Ok(_) => Err(DBError::new("file writes should return an error")),
Err(err) => {
assert_eq!(err.to_string(), "write error");
assert!(err.source().is_some(), "Must include the source error.");
assert!(err
.source()
.unwrap()
.to_string()
.contains("could not write to file"));
Ok(())
}
}
} }
} }