a small relational database with user-editable schema for manual data entry
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
yopa/yopa/src/model.rs

220 lines
5.8 KiB

//! 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<ID>,
/// 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))
}
}