|  |  |  | @ -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::collections::HashMap; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | use insert::InsertValue; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 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 itertools::Itertools; | 
			
		
	
		
			
				
					|  |  |  |  | use serde::{Deserialize, Serialize}; | 
			
		
	
		
			
				
					|  |  |  |  | use thiserror::Error; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | use cool::{KVVecToKeysOrValues, map_drain_filter}; | 
			
		
	
		
			
				
					|  |  |  |  | pub use id::ID; | 
			
		
	
		
			
				
					|  |  |  |  | use id::next_id; | 
			
		
	
		
			
				
					|  |  |  |  | use insert::InsertObj; | 
			
		
	
		
			
				
					|  |  |  |  | use insert::InsertValue; | 
			
		
	
		
			
				
					|  |  |  |  | use model::ObjectModel; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | pub mod model; | 
			
		
	
		
			
				
					|  |  |  |  | pub mod data; | 
			
		
	
		
			
				
					|  |  |  |  | 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 { | 
			
		
	
		
			
				
					|  |  |  |  |     obj_models: HashMap<ID, model::ObjectModel>, | 
			
		
	
		
			
				
					|  |  |  |  |     rel_models: HashMap<ID, model::RelationModel>, | 
			
		
	
	
		
			
				
					|  |  |  | @ -76,10 +39,12 @@ pub enum StorageError { | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |     /// Create empty store
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn new() -> Self { | 
			
		
	
		
			
				
					|  |  |  |  |         Self::default() | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /// Define a data object
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn define_object(&mut self, mut tpl: model::ObjectModel) -> Result<ID, StorageError> { | 
			
		
	
		
			
				
					|  |  |  |  |         if let Some(pid) = tpl.parent_tpl_id { | 
			
		
	
		
			
				
					|  |  |  |  |             if !self.obj_models.contains_key(&pid) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -97,6 +62,7 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |         Ok(id) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /// Define a relation between two data objects
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn define_relation(&mut self, mut rel: model::RelationModel) -> Result<ID, StorageError> { | 
			
		
	
		
			
				
					|  |  |  |  |         if !self.obj_models.contains_key(&rel.object_tpl_id) { | 
			
		
	
		
			
				
					|  |  |  |  |             return Err(StorageError::NotExist(format!("source object model {}", rel.object_tpl_id).into())); | 
			
		
	
	
		
			
				
					|  |  |  | @ -116,6 +82,7 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |         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> { | 
			
		
	
		
			
				
					|  |  |  |  |         if !self.obj_models.contains_key(&prop.parent_tpl_id) { | 
			
		
	
		
			
				
					|  |  |  |  |             // Maybe it's attached to a relation?
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -143,6 +110,7 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |         Ok(id) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /// Delete an object definition and associated data
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn undefine_object(&mut self, id: ID) -> Result<ObjectModel, StorageError> { | 
			
		
	
		
			
				
					|  |  |  |  |         return if let Some(t) = self.obj_models.remove(&id) { | 
			
		
	
		
			
				
					|  |  |  |  |             // Remove relation templates
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -167,9 +135,10 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |             Ok(t) | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             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> { | 
			
		
	
		
			
				
					|  |  |  |  |         return if let Some(t) = self.rel_models.remove(&id) { | 
			
		
	
		
			
				
					|  |  |  |  |             // Remove relations
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -185,9 +154,10 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |             Ok(t) | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             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> { | 
			
		
	
		
			
				
					|  |  |  |  |         return if let Some(t) = self.prop_models.remove(&id) { | 
			
		
	
		
			
				
					|  |  |  |  |             // Remove relations
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -195,12 +165,12 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |             Ok(t) | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             Err(StorageError::NotExist(format!("property model {}", id).into())) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         }; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // 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> { | 
			
		
	
		
			
				
					|  |  |  |  |         let obj_model_id = insobj.model_id; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -212,7 +182,7 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |         let object_id = next_id(); | 
			
		
	
		
			
				
					|  |  |  |  |         let object = data::Object { | 
			
		
	
		
			
				
					|  |  |  |  |             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> { | 
			
		
	
	
		
			
				
					|  |  |  | @ -230,7 +200,7 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |                             object_id, | 
			
		
	
		
			
				
					|  |  |  |  |                             model_id: prop.id, | 
			
		
	
		
			
				
					|  |  |  |  |                             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 { | 
			
		
	
	
		
			
				
					|  |  |  | @ -240,7 +210,7 @@ impl InMemoryStorage { | 
			
		
	
		
			
				
					|  |  |  |  |                                 id: next_id(), | 
			
		
	
		
			
				
					|  |  |  |  |                                 object_id, | 
			
		
	
		
			
				
					|  |  |  |  |                                 model_id: prop.id, | 
			
		
	
		
			
				
					|  |  |  |  |                                 value: def.clone() | 
			
		
	
		
			
				
					|  |  |  |  |                                 value: def.clone(), | 
			
		
	
		
			
				
					|  |  |  |  |                             }); | 
			
		
	
		
			
				
					|  |  |  |  |                         } else { | 
			
		
	
		
			
				
					|  |  |  |  |                             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(), | 
			
		
	
		
			
				
					|  |  |  |  |                         object_id, | 
			
		
	
		
			
				
					|  |  |  |  |                         model_id: rel_instance.model_id, | 
			
		
	
		
			
				
					|  |  |  |  |                         related_id: rel_instance.related_id | 
			
		
	
		
			
				
					|  |  |  |  |                         related_id: rel_instance.related_id, | 
			
		
	
		
			
				
					|  |  |  |  |                     }); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
	
		
			
				
					|  |  |  | 
 |