Document database's file.rs
This commit is contained in:
parent
64b5553863
commit
2701729dcf
@ -9,14 +9,28 @@ const JSON_POINTER_SEPARATOR: &str = "/";
|
||||
|
||||
custom_error! { pub IncorrectPointer{pointer: String} = "Incorrect pointer is specified: {pointer}" }
|
||||
|
||||
/// This is a enum that used internally to refer to values inside of
|
||||
/// JSON (their serde implementation) objects and arrays.
|
||||
/// This enum helps to simplify module's code.
|
||||
///
|
||||
/// For values inside of JSON object it stores object's
|
||||
/// `Map<String, serde_json::Value>` and name of referred value.
|
||||
///
|
||||
/// For values inside JSON arrays it stores array's
|
||||
/// `Vec<serde_json::Value>` and referred index.
|
||||
///
|
||||
/// `Invalid` can be used to return a failed state.
|
||||
enum ValueReference<'a> {
|
||||
Object(&'a mut serde_json::Map<String, serde_json::Value>, String),
|
||||
Array(&'a mut Vec<serde_json::Value>, usize),
|
||||
Invalid,
|
||||
}
|
||||
|
||||
/// Implements database's file by wrapping JSON value (`serde_json::Value`)
|
||||
/// and providing several convenient accessor methods.
|
||||
#[derive(Debug)]
|
||||
pub struct File {
|
||||
/// File's full contents, normally a JSON object.
|
||||
contents: serde_json::Value,
|
||||
}
|
||||
|
||||
@ -27,30 +41,49 @@ impl ToString for File {
|
||||
}
|
||||
|
||||
impl File {
|
||||
/// Creates an empty file that will contain an empty JSON object.
|
||||
pub fn empty() -> File {
|
||||
File {
|
||||
contents: json!({}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(file_contents: String) -> Result<File, Box<dyn Error>> {
|
||||
/// Loads JSON value from the specified file.
|
||||
pub fn load(file_contents: String) -> Result<File, Box<dyn Error>> {
|
||||
Ok(File {
|
||||
contents: serde_json::from_str(&file_contents)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns file's "root", - JSON value contained inside it.
|
||||
pub fn root(&self) -> &serde_json::Value {
|
||||
&self.contents
|
||||
}
|
||||
|
||||
/// Attempts to return JSON value, corresponding to the given JSON pointer.
|
||||
/// `None` if the value is missing.
|
||||
pub fn get(&self, pointer: &str) -> Option<&serde_json::Value> {
|
||||
self.contents.pointer(pointer)
|
||||
}
|
||||
|
||||
/// Checks if values at a given JSON pointer exists.
|
||||
/// Returns `true` if it does.
|
||||
pub fn contains(&self, pointer: &str) -> bool {
|
||||
self.get(pointer) != None
|
||||
}
|
||||
|
||||
/// Inserts new JSON value inside this file
|
||||
/// (possibly in some sub-object/array).
|
||||
///
|
||||
/// Given pointer must point at new value:
|
||||
/// 1. If it already exists, - it will be overwritten.
|
||||
/// 2. If it does not exist, but it's parent object/array does -
|
||||
/// it will be added.
|
||||
/// 3. Otherwise an error will be raise.
|
||||
///
|
||||
/// If array needs to be expanded, - missing values will be filled
|
||||
/// with `json!(null)`, i.e. inserting `7` at index `5` in array `[1, 2, 3]`
|
||||
/// will produce `[1, 2, 3, null, null, 7]`.
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
pointer: &str,
|
||||
@ -70,6 +103,8 @@ impl File {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes (and returns) value specified by theJSON pointer.
|
||||
/// If it did not exist - returns `None`.
|
||||
pub fn remove(&mut self, pointer: &str) -> Option<serde_json::Value> {
|
||||
match self.pointer_to_reference(pointer) {
|
||||
ValueReference::Object(map, variable_name) => map.remove(&variable_name),
|
||||
@ -83,6 +118,10 @@ impl File {
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper method to create a value if missing (as `json!(null)`).
|
||||
/// Can only be done if parent container already exists.
|
||||
///
|
||||
/// For specifics refer to `insert()` method.
|
||||
fn touch(&mut self, pointer: &str) -> (Result<(), IncorrectPointer>) {
|
||||
// If value is present - we're done
|
||||
if pointer.is_empty() || self.contents.pointer_mut(pointer).is_some() {
|
||||
@ -108,6 +147,7 @@ impl File {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper method, - converts JSON pointer into auxiliary `ValueReference` enum.
|
||||
fn pointer_to_reference<'a>(&'a mut self, pointer: &str) -> ValueReference<'a> {
|
||||
if pointer.is_empty() {
|
||||
return ValueReference::Invalid;
|
||||
@ -145,6 +185,7 @@ impl File {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to disassemble JSON path.
|
||||
fn pop_json_pointer(pointer: &str) -> Option<(String, String)> {
|
||||
let mut pointer = pointer.to_string();
|
||||
let last_separator_index = match pointer.rfind(JSON_POINTER_SEPARATOR) {
|
||||
|
@ -121,7 +121,7 @@ fn read_group(group_path: &path::Path) -> Result<Option<Group>, Box<dyn Error>>
|
||||
}
|
||||
let file_name = get_file_name(path.as_path());
|
||||
let file_contents = fs::read_to_string(&path)?;
|
||||
files.insert(file_name, File::new(file_contents)?);
|
||||
files.insert(file_name, File::load(file_contents)?);
|
||||
}
|
||||
if files.len() > 0 {
|
||||
return Ok(Some(Group {
|
||||
|
@ -17,7 +17,8 @@ pub mod io;
|
||||
custom_error! { pub DBError
|
||||
InvalidEntityName{entity_name: String} = r#"Cannot use {entity_name} for file or group"#,
|
||||
NoGroup{group_name: String} = r#"Group "{group_name}" does not exist"#,
|
||||
NoFile{group_name: String, file_name: String} = r#"There is no "{file_name}" file in group "{group_name}""#,
|
||||
NoFile{group_name: String, file_name: String} = r#"There is no "{file_name}" file in group\
|
||||
"{group_name}""#,
|
||||
GroupAlreadyExists{group_name: String} = r#"Group "{group_name}" already exists"#,
|
||||
FileAlreadyExists{group_name: String, file_name: String} = r#"File "{file_name}" already exists\
|
||||
in the group "{group_name}""#,
|
||||
|
Loading…
Reference in New Issue
Block a user