|
|
@ -1,62 +1,25 @@ |
|
|
|
use std::collections::{HashMap}; |
|
|
|
|
|
|
|
use thiserror::Error; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use crate::cool::{map_drain_filter, KVVecToKeysOrValues}; |
|
|
|
|
|
|
|
use model::{ObjectModel}; |
|
|
|
|
|
|
|
use insert::InsertObj; |
|
|
|
|
|
|
|
use itertools::Itertools; |
|
|
|
|
|
|
|
use std::borrow::Cow; |
|
|
|
use std::borrow::Cow; |
|
|
|
|
|
|
|
use std::collections::HashMap; |
|
|
|
|
|
|
|
|
|
|
|
use insert::InsertValue; |
|
|
|
use itertools::Itertools; |
|
|
|
|
|
|
|
use serde::{Deserialize, Serialize}; |
|
|
|
|
|
|
|
use thiserror::Error; |
|
|
|
mod cool; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(feature="uuid-ids")] |
|
|
|
|
|
|
|
pub mod id { |
|
|
|
|
|
|
|
/// Common identifier type
|
|
|
|
|
|
|
|
#[allow(non_camel_case_types)] |
|
|
|
|
|
|
|
pub type ID = uuid::Uuid; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn next_id() -> ID { |
|
|
|
|
|
|
|
uuid::Uuid::new_v4() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn zero_id() -> ID { |
|
|
|
|
|
|
|
uuid::Uuid::nil() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(not(feature="uuid-ids"))] |
|
|
|
|
|
|
|
pub mod id { |
|
|
|
|
|
|
|
/// Common identifier type
|
|
|
|
|
|
|
|
#[allow(non_camel_case_types)] |
|
|
|
|
|
|
|
pub type ID = u64; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lazy_static::lazy_static! { |
|
|
|
|
|
|
|
static ref COUNTER: parking_lot::Mutex<u64> = parking_lot::Mutex::new(0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn next_id() -> ID { |
|
|
|
|
|
|
|
let mut m = COUNTER.lock(); |
|
|
|
|
|
|
|
let v = *m; |
|
|
|
|
|
|
|
*m += 1; |
|
|
|
|
|
|
|
v |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn zero_id() -> ID { |
|
|
|
|
|
|
|
0 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use cool::{KVVecToKeysOrValues, map_drain_filter}; |
|
|
|
pub use id::ID; |
|
|
|
pub use id::ID; |
|
|
|
use id::next_id; |
|
|
|
use id::next_id; |
|
|
|
|
|
|
|
use insert::InsertObj; |
|
|
|
|
|
|
|
use insert::InsertValue; |
|
|
|
|
|
|
|
use model::ObjectModel; |
|
|
|
|
|
|
|
|
|
|
|
pub mod model; |
|
|
|
pub mod model; |
|
|
|
pub mod data; |
|
|
|
pub mod data; |
|
|
|
pub mod insert; |
|
|
|
pub mod insert; |
|
|
|
|
|
|
|
pub mod id; |
|
|
|
|
|
|
|
mod cool; |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Default)] |
|
|
|
/// Stupid storage with no persistence
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)] |
|
|
|
pub struct InMemoryStorage { |
|
|
|
pub struct InMemoryStorage { |
|
|
|
obj_models: HashMap<ID, model::ObjectModel>, |
|
|
|
obj_models: HashMap<ID, model::ObjectModel>, |
|
|
|
rel_models: HashMap<ID, model::RelationModel>, |
|
|
|
rel_models: HashMap<ID, model::RelationModel>, |
|
|
@ -76,10 +39,12 @@ pub enum StorageError { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl InMemoryStorage { |
|
|
|
impl InMemoryStorage { |
|
|
|
|
|
|
|
/// Create empty store
|
|
|
|
pub fn new() -> Self { |
|
|
|
pub fn new() -> Self { |
|
|
|
Self::default() |
|
|
|
Self::default() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Define a data object
|
|
|
|
pub fn define_object(&mut self, mut tpl: model::ObjectModel) -> Result<ID, StorageError> { |
|
|
|
pub fn define_object(&mut self, mut tpl: model::ObjectModel) -> Result<ID, StorageError> { |
|
|
|
if let Some(pid) = tpl.parent_tpl_id { |
|
|
|
if let Some(pid) = tpl.parent_tpl_id { |
|
|
|
if !self.obj_models.contains_key(&pid) { |
|
|
|
if !self.obj_models.contains_key(&pid) { |
|
|
@ -97,6 +62,7 @@ impl InMemoryStorage { |
|
|
|
Ok(id) |
|
|
|
Ok(id) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Define a relation between two data objects
|
|
|
|
pub fn define_relation(&mut self, mut rel: model::RelationModel) -> Result<ID, StorageError> { |
|
|
|
pub fn define_relation(&mut self, mut rel: model::RelationModel) -> Result<ID, StorageError> { |
|
|
|
if !self.obj_models.contains_key(&rel.object_tpl_id) { |
|
|
|
if !self.obj_models.contains_key(&rel.object_tpl_id) { |
|
|
|
return Err(StorageError::NotExist(format!("source object model {}", rel.object_tpl_id).into())); |
|
|
|
return Err(StorageError::NotExist(format!("source object model {}", rel.object_tpl_id).into())); |
|
|
@ -116,6 +82,7 @@ impl InMemoryStorage { |
|
|
|
Ok(id) |
|
|
|
Ok(id) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Define a property attached to an object or a relation
|
|
|
|
pub fn define_property(&mut self, mut prop: model::PropertyModel) -> Result<ID, StorageError> { |
|
|
|
pub fn define_property(&mut self, mut prop: model::PropertyModel) -> Result<ID, StorageError> { |
|
|
|
if !self.obj_models.contains_key(&prop.parent_tpl_id) { |
|
|
|
if !self.obj_models.contains_key(&prop.parent_tpl_id) { |
|
|
|
// Maybe it's attached to a relation?
|
|
|
|
// Maybe it's attached to a relation?
|
|
|
@ -143,6 +110,7 @@ impl InMemoryStorage { |
|
|
|
Ok(id) |
|
|
|
Ok(id) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Delete an object definition and associated data
|
|
|
|
pub fn undefine_object(&mut self, id: ID) -> Result<ObjectModel, StorageError> { |
|
|
|
pub fn undefine_object(&mut self, id: ID) -> Result<ObjectModel, StorageError> { |
|
|
|
return if let Some(t) = self.obj_models.remove(&id) { |
|
|
|
return if let Some(t) = self.obj_models.remove(&id) { |
|
|
|
// Remove relation templates
|
|
|
|
// Remove relation templates
|
|
|
@ -167,9 +135,10 @@ impl InMemoryStorage { |
|
|
|
Ok(t) |
|
|
|
Ok(t) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Err(StorageError::NotExist(format!("object model {}", id).into())) |
|
|
|
Err(StorageError::NotExist(format!("object model {}", id).into())) |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Delete a relation definition and associated data
|
|
|
|
pub fn undefine_relation(&mut self, id: ID) -> Result<model::RelationModel, StorageError> { |
|
|
|
pub fn undefine_relation(&mut self, id: ID) -> Result<model::RelationModel, StorageError> { |
|
|
|
return if let Some(t) = self.rel_models.remove(&id) { |
|
|
|
return if let Some(t) = self.rel_models.remove(&id) { |
|
|
|
// Remove relations
|
|
|
|
// Remove relations
|
|
|
@ -185,9 +154,10 @@ impl InMemoryStorage { |
|
|
|
Ok(t) |
|
|
|
Ok(t) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Err(StorageError::NotExist(format!("relation model {}", id).into())) |
|
|
|
Err(StorageError::NotExist(format!("relation model {}", id).into())) |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Delete a property definition and associated data
|
|
|
|
pub fn undefine_property(&mut self, id: ID) -> Result<model::PropertyModel, StorageError> { |
|
|
|
pub fn undefine_property(&mut self, id: ID) -> Result<model::PropertyModel, StorageError> { |
|
|
|
return if let Some(t) = self.prop_models.remove(&id) { |
|
|
|
return if let Some(t) = self.prop_models.remove(&id) { |
|
|
|
// Remove relations
|
|
|
|
// Remove relations
|
|
|
@ -195,12 +165,12 @@ impl InMemoryStorage { |
|
|
|
Ok(t) |
|
|
|
Ok(t) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Err(StorageError::NotExist(format!("property model {}", id).into())) |
|
|
|
Err(StorageError::NotExist(format!("property model {}", id).into())) |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// DATA
|
|
|
|
// DATA
|
|
|
|
|
|
|
|
|
|
|
|
/// Insert object with relations, validating the data model
|
|
|
|
/// Insert object with relations, validating the data model constraints
|
|
|
|
pub fn insert_object(&mut self, insobj: InsertObj) -> Result<ID, StorageError> { |
|
|
|
pub fn insert_object(&mut self, insobj: InsertObj) -> Result<ID, StorageError> { |
|
|
|
let obj_model_id = insobj.model_id; |
|
|
|
let obj_model_id = insobj.model_id; |
|
|
|
|
|
|
|
|
|
|
@ -212,7 +182,7 @@ impl InMemoryStorage { |
|
|
|
let object_id = next_id(); |
|
|
|
let object_id = next_id(); |
|
|
|
let object = data::Object { |
|
|
|
let object = data::Object { |
|
|
|
id: object_id, |
|
|
|
id: object_id, |
|
|
|
model_id: obj_model_id |
|
|
|
model_id: obj_model_id, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let find_values_to_insert = |values: Vec<InsertValue>, parent_id: ID| -> Result<Vec<data::Value>, StorageError> { |
|
|
|
let find_values_to_insert = |values: Vec<InsertValue>, parent_id: ID| -> Result<Vec<data::Value>, StorageError> { |
|
|
@ -230,7 +200,7 @@ impl InMemoryStorage { |
|
|
|
object_id, |
|
|
|
object_id, |
|
|
|
model_id: prop.id, |
|
|
|
model_id: prop.id, |
|
|
|
value: val_instance.value.cast_to(prop.data_type) |
|
|
|
value: val_instance.value.cast_to(prop.data_type) |
|
|
|
.map_err(|v| StorageError::ConstraintViolation(format!("{} cannot accept value {:?}", prop, v).into()))? |
|
|
|
.map_err(|v| StorageError::ConstraintViolation(format!("{} cannot accept value {:?}", prop, v).into()))?, |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -240,7 +210,7 @@ impl InMemoryStorage { |
|
|
|
id: next_id(), |
|
|
|
id: next_id(), |
|
|
|
object_id, |
|
|
|
object_id, |
|
|
|
model_id: prop.id, |
|
|
|
model_id: prop.id, |
|
|
|
value: def.clone() |
|
|
|
value: def.clone(), |
|
|
|
}); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return Err(StorageError::ConstraintViolation(format!("{} is required for {} (and no default value is defined)", prop, obj_model).into())); |
|
|
|
return Err(StorageError::ConstraintViolation(format!("{} is required for {} (and no default value is defined)", prop, obj_model).into())); |
|
|
@ -278,7 +248,7 @@ impl InMemoryStorage { |
|
|
|
id: next_id(), |
|
|
|
id: next_id(), |
|
|
|
object_id, |
|
|
|
object_id, |
|
|
|
model_id: rel_instance.model_id, |
|
|
|
model_id: rel_instance.model_id, |
|
|
|
related_id: rel_instance.related_id |
|
|
|
related_id: rel_instance.related_id, |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|