//! Data model structs and enums use std::fmt; use std::fmt::{Display, Formatter}; use serde::{Deserialize, Serialize}; use super::data::TypedValue; use super::ID; use crate::id::HaveId; use std::cmp::Ordering; /// Get a description of a struct pub trait Describe { /// Short but informative description for error messages fn describe(&self) -> String; } /// Object template #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ObjectModel { /// PK #[serde(default)] pub id: ID, /// Template name, unique within the database pub name: String, /// Property to use as the name in relation selectors #[serde(default)] pub name_property: Option, /// Sort key, smaller go first pub sort_key : i64, } /// Relation between templates #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RelationModel { /// PK #[serde(default)] pub id: ID, /// Object template ID pub object: ID, /// Relation name, unique within the parent object pub name: String, /// Relation name when viewed from the other side, unique within the related object's relations pub reciprocal_name: String, /// Relation is optional pub optional: bool, /// Relation can be multiple pub multiple: bool, /// Related object template ID pub related: ID, /// Sort key, smaller go first pub sort_key : i64, } /// Property definition #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct PropertyModel { /// PK #[serde(default)] pub id: ID, /// Object or Reference template ID pub object: ID, /// Property name, unique within the parent object or reference pub name: String, /// Property is optional pub optional: bool, /// Property can be multiple pub multiple: bool, /// Value must be unique among instances of the parent model pub unique: bool, /// Property data type pub data_type: DataType, /// Default value, used for newly created objects pub default: TypedValue, /// Sort key, smaller go first pub sort_key : i64, /// Additional presentational and data type specific config pub options : PropertyOptions, } /// Additional presentational and data type specific config that shouldn't affect queries and such #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] pub struct PropertyOptions { /// String should be shown as multi-line pub multiline : bool, } /// Value data type #[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)] pub enum DataType { /// Text String, /// Integer Integer, /// Floating point number Decimal, /// Boolean yes/no Boolean, } impl Display for ObjectModel { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "object \"{}\" ({})", self.name, self.id) } } impl Display for RelationModel { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "relation \"{}\" ({})", self.name, self.id) } } impl Display for PropertyModel { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "property \"{}\" ({})", self.name, self.id) } } impl HaveId for ObjectModel { fn get_id(&self) -> ID { self.id } } impl HaveId for RelationModel { fn get_id(&self) -> ID { self.id } } impl HaveId for PropertyModel { fn get_id(&self) -> ID { self.id } } // TODO find some less shitty way to do sorting impl PropertyModel { /// Get sort pub fn order(one : &Self, another: &Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } // stupid intensifies pub fn order_refs(one : &&Self, another: &&Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } // hello pub fn order_refs2(one : &&&Self, another: &&&Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } } impl ObjectModel { /// Get sort pub fn order(one : &Self, another: &Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } // stupid intensifies pub fn order_refs(one : &&Self, another: &&Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } // hello pub fn order_refs2(one : &&&Self, another: &&&Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } } impl RelationModel { /// Get sort pub fn order(one : &Self, another: &Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } // stupid intensifies pub fn order_refs(one : &&Self, another: &&Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } // hello pub fn order_refs2(one : &&&Self, another: &&&Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.name.cmp(&another.name)) } // more stupid pub fn reciprocal_order(one : &Self, another: &Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.reciprocal_name.cmp(&another.reciprocal_name)) } pub fn reciprocal_order_refs(one : &&Self, another: &&Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.reciprocal_name.cmp(&another.reciprocal_name)) } pub fn reciprocal_order_refs2(one : &&&Self, another: &&&Self) -> Ordering { one.sort_key.cmp(&another.sort_key) .then_with(|| one.reciprocal_name.cmp(&another.reciprocal_name)) } }