Moved document definitions into separate module.
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s
This commit is contained in:
parent
f46c2929b7
commit
5e448a0071
@ -1,2 +1,3 @@
|
|||||||
pub mod clock;
|
pub mod clock;
|
||||||
pub mod create;
|
pub mod create;
|
||||||
|
pub mod definition;
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
data_director::{Include, Path, RegMsg, Register, RouteID},
|
data_director::{Include, Path, RegMsg, Register, RouteID},
|
||||||
|
document::definition::{DocDef, DocFuncType},
|
||||||
field::Field,
|
field::Field,
|
||||||
message::{
|
message::{
|
||||||
Action, CalcValue, Calculation, DocDef, DocFuncType, InternalRecord, InternalRecords,
|
Action, CalcValue, Calculation, InternalRecord, InternalRecords, Message, MsgAction, Oid,
|
||||||
Message, MsgAction, Oid, Query, Records, Reply, Update,
|
Query, Records, Reply, Update,
|
||||||
},
|
},
|
||||||
mtterror::MTTError,
|
mtterror::MTTError,
|
||||||
name::NameType,
|
name::NameType,
|
||||||
|
|||||||
572
src/document/definition.rs
Normal file
572
src/document/definition.rs
Normal file
@ -0,0 +1,572 @@
|
|||||||
|
use crate::{
|
||||||
|
data_director::{Include, Path},
|
||||||
|
document::create::IndexType,
|
||||||
|
field::{Field, FieldType},
|
||||||
|
message::{Action, CalcValue, MsgAction},
|
||||||
|
mtterror::MTTError,
|
||||||
|
name::{Name, NameType, Names},
|
||||||
|
};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct FieldSetting {
|
||||||
|
fieldtype: FieldType,
|
||||||
|
default_value: CalcValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FieldSetting {
|
||||||
|
fn new(ftype: FieldType) -> Self {
|
||||||
|
Self {
|
||||||
|
fieldtype: ftype,
|
||||||
|
default_value: CalcValue::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_default<CV>(&mut self, holder: CV) -> Result<(), MTTError>
|
||||||
|
where
|
||||||
|
CV: Into<CalcValue>,
|
||||||
|
{
|
||||||
|
let value = holder.into();
|
||||||
|
match &value {
|
||||||
|
CalcValue::Calculate(calc) => {
|
||||||
|
if self.fieldtype != calc.get_type() {
|
||||||
|
return Err(MTTError::FieldInvalidType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CalcValue::Existing(ftype) | CalcValue::FType(ftype) => {
|
||||||
|
if &self.fieldtype != ftype {
|
||||||
|
return Err(MTTError::FieldInvalidType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CalcValue::Value(ref item) => {
|
||||||
|
if item.get_type() != self.fieldtype {
|
||||||
|
return Err(MTTError::FieldInvalidType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CalcValue::None => {}
|
||||||
|
}
|
||||||
|
self.default_value = value;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, value: &Field) -> Result<Field, MTTError> {
|
||||||
|
match value {
|
||||||
|
Field::None => match &self.default_value {
|
||||||
|
CalcValue::None => Err(MTTError::InvalidNone),
|
||||||
|
_ => Ok(self.default_value.get(&Field::None)),
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let vft: FieldType = value.into();
|
||||||
|
if vft != self.fieldtype {
|
||||||
|
return Err(MTTError::DocumentFieldWrongDataType(
|
||||||
|
self.fieldtype.clone(),
|
||||||
|
vft,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(value.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod fieldsettings {
|
||||||
|
use super::*;
|
||||||
|
use crate::message::{Calculation, Operand};
|
||||||
|
use chrono::Utc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validates_field_type() {
|
||||||
|
let fset = FieldSetting::new(FieldType::Uuid);
|
||||||
|
let value: Field = Uuid::new_v4().into();
|
||||||
|
match fset.validate(&value) {
|
||||||
|
Ok(data) => assert_eq!(data, value),
|
||||||
|
Err(err) => unreachable!("got {:?}: should have gotten a value", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validates_for_bad_field_type() {
|
||||||
|
let fset = FieldSetting::new(FieldType::Uuid);
|
||||||
|
let value: Field = "text".into();
|
||||||
|
match fset.validate(&value) {
|
||||||
|
Ok(data) => unreachable!("got {:?}: should have gotten an error", data),
|
||||||
|
Err(err) => match err {
|
||||||
|
MTTError::DocumentFieldWrongDataType(expected, got) => {
|
||||||
|
assert_eq!(expected, FieldType::Uuid);
|
||||||
|
assert_eq!(got, FieldType::StaticString);
|
||||||
|
}
|
||||||
|
_ => unreachable!("got {:?}: should have gotten a value", err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_default_returns_error() {
|
||||||
|
let fset = FieldSetting::new(FieldType::Uuid);
|
||||||
|
match fset.validate(&Field::None) {
|
||||||
|
Ok(data) => unreachable!("got {:?}: should have gotten an error", data),
|
||||||
|
Err(err) => match err {
|
||||||
|
MTTError::InvalidNone => {}
|
||||||
|
_ => unreachable!("got {:?}: should have gotten a invalid none", err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn returns_value_if_default_is_set() {
|
||||||
|
let mut fset = FieldSetting::new(FieldType::StaticString);
|
||||||
|
fset.set_default(FieldType::StaticString).unwrap();
|
||||||
|
match fset.validate(&Field::None) {
|
||||||
|
Ok(data) => assert_eq!(data, "".into()),
|
||||||
|
Err(err) => unreachable!("got {:?}: should have gotten a value", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn returns_default_value() {
|
||||||
|
let mut fset = FieldSetting::new(FieldType::StaticString);
|
||||||
|
let input = "fred";
|
||||||
|
fset.set_default(input).unwrap();
|
||||||
|
match fset.validate(&Field::None) {
|
||||||
|
Ok(data) => assert_eq!(data, input.into()),
|
||||||
|
Err(err) => unreachable!("got {:?}: should have gotten a value", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_default_be_calculated() {
|
||||||
|
let mut fset = FieldSetting::new(FieldType::DateTime);
|
||||||
|
let duration = Duration::from_secs(3600);
|
||||||
|
let mut calc = Calculation::new(Operand::Add);
|
||||||
|
calc.add_value(FieldType::DateTime).unwrap();
|
||||||
|
calc.add_value(duration).unwrap();
|
||||||
|
fset.set_default(calc).unwrap();
|
||||||
|
let start = Utc::now() + duration;
|
||||||
|
let result = match fset.validate(&Field::None).unwrap() {
|
||||||
|
Field::DateTime(data) => data,
|
||||||
|
_ => unreachable!("should return datetime"),
|
||||||
|
};
|
||||||
|
let stop = Utc::now() + duration;
|
||||||
|
assert!(
|
||||||
|
result > start,
|
||||||
|
"{:?} should have been greater than {:?}",
|
||||||
|
result,
|
||||||
|
start
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
result < stop,
|
||||||
|
"{:?} should have been less than {:?}",
|
||||||
|
result,
|
||||||
|
stop
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum DocFuncType {
|
||||||
|
Add,
|
||||||
|
Delete,
|
||||||
|
ExistingQuery(MsgAction),
|
||||||
|
Query,
|
||||||
|
Show,
|
||||||
|
Trigger(MsgAction),
|
||||||
|
Update,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PathAction {
|
||||||
|
path: Path,
|
||||||
|
func_type: DocFuncType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathAction {
|
||||||
|
fn new(path: Path, func_type: DocFuncType) -> Self {
|
||||||
|
Self {
|
||||||
|
path: path,
|
||||||
|
func_type: func_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> Path {
|
||||||
|
self.path.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn doc_function(&self) -> DocFuncType {
|
||||||
|
self.func_type.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DocDef {
|
||||||
|
doc_names: Vec<Name>,
|
||||||
|
field_names: Names,
|
||||||
|
fields: HashMap<Uuid, FieldSetting>,
|
||||||
|
indexes: HashMap<Uuid, IndexType>,
|
||||||
|
routes: Vec<PathAction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocDef {
|
||||||
|
pub fn new(name: Name) -> Self {
|
||||||
|
let names = vec![name];
|
||||||
|
Self::with_names(names)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_names(names: Vec<Name>) -> Self {
|
||||||
|
let routes = vec![
|
||||||
|
PathAction::new(
|
||||||
|
Path::new(
|
||||||
|
Include::All,
|
||||||
|
Include::Just(names[0].clone().into()),
|
||||||
|
Include::Just(Action::Addition),
|
||||||
|
),
|
||||||
|
DocFuncType::Add,
|
||||||
|
),
|
||||||
|
PathAction::new(
|
||||||
|
Path::new(
|
||||||
|
Include::All,
|
||||||
|
Include::Just(names[0].clone().into()),
|
||||||
|
Include::Just(Action::Delete),
|
||||||
|
),
|
||||||
|
DocFuncType::Delete,
|
||||||
|
),
|
||||||
|
PathAction::new(
|
||||||
|
Path::new(
|
||||||
|
Include::All,
|
||||||
|
Include::Just(names[0].clone().into()),
|
||||||
|
Include::Just(Action::Query),
|
||||||
|
),
|
||||||
|
DocFuncType::Query,
|
||||||
|
),
|
||||||
|
PathAction::new(
|
||||||
|
Path::new(
|
||||||
|
Include::All,
|
||||||
|
Include::Just(names[0].clone().into()),
|
||||||
|
Include::Just(Action::Show),
|
||||||
|
),
|
||||||
|
DocFuncType::Show,
|
||||||
|
),
|
||||||
|
PathAction::new(
|
||||||
|
Path::new(
|
||||||
|
Include::All,
|
||||||
|
Include::Just(names[0].clone().into()),
|
||||||
|
Include::Just(Action::Update),
|
||||||
|
),
|
||||||
|
DocFuncType::Update,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
Self {
|
||||||
|
doc_names: names,
|
||||||
|
field_names: Names::new(),
|
||||||
|
fields: HashMap::new(),
|
||||||
|
indexes: HashMap::new(),
|
||||||
|
routes: routes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_document_names(&self) -> &Vec<Name> {
|
||||||
|
&self.doc_names
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_field_names(&self) -> &Names {
|
||||||
|
&self.field_names
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn get_field_names_mut(&mut self) -> &mut Names {
|
||||||
|
&mut self.field_names
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_field(&mut self, name: Name, ftype: FieldType) {
|
||||||
|
let id = self.field_names.add_names([name].to_vec()).unwrap();
|
||||||
|
self.fields.insert(id, FieldSetting::new(ftype));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_field_id<NT>(&self, field_name: NT) -> Result<Uuid, MTTError>
|
||||||
|
where
|
||||||
|
NT: Into<NameType>,
|
||||||
|
{
|
||||||
|
match self.field_names.get_id(field_name) {
|
||||||
|
Ok(data) => Ok(data),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn get_field<NT>(&self, field_name: NT) -> Result<&FieldSetting, MTTError>
|
||||||
|
where
|
||||||
|
NT: Into<NameType>,
|
||||||
|
{
|
||||||
|
let id = match self.field_names.get_id(field_name) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
Ok(self.fields.get(&id).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn get_field_mut<NT>(&mut self, field_name: NT) -> Result<&mut FieldSetting, MTTError>
|
||||||
|
where
|
||||||
|
NT: Into<NameType>,
|
||||||
|
{
|
||||||
|
let id = match self.field_names.get_id(field_name) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
Ok(self.fields.get_mut(&id).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn field_ids(&self) -> HashSet<Uuid> {
|
||||||
|
self.fields.keys().cloned().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate<NT>(&self, field_name: NT, value: &Field) -> Result<Field, MTTError>
|
||||||
|
where
|
||||||
|
NT: Into<NameType>,
|
||||||
|
{
|
||||||
|
let id = match self.field_names.get_id(field_name) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
self.fields.get(&id).unwrap().validate(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_default<CV>(&mut self, field_name: &Name, value: CV) -> Result<(), MTTError>
|
||||||
|
where
|
||||||
|
CV: Into<CalcValue>,
|
||||||
|
{
|
||||||
|
let id = match self.field_names.get_id(field_name) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
match self.fields.get_mut(&id).unwrap().set_default(value) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_index(&mut self, field_name: &Name, index_type: IndexType) -> Result<(), MTTError> {
|
||||||
|
let id = match self.field_names.get_id(field_name) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
self.indexes.insert(id.clone(), index_type);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_indexes(&self) -> &HashMap<Uuid, IndexType> {
|
||||||
|
&self.indexes
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn iter(&self) -> impl Iterator<Item = (&Uuid, &FieldSetting)> {
|
||||||
|
self.fields.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_routes(&self) -> impl Iterator<Item = &PathAction> {
|
||||||
|
self.routes.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_route(&mut self, path: Path, action: DocFuncType) {
|
||||||
|
self.routes.push(PathAction::new(path, action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod docdefs {
|
||||||
|
use super::*;
|
||||||
|
use crate::message::{Query, Update};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_field_be_added() {
|
||||||
|
let docname = Name::english("tester");
|
||||||
|
let mut docdef = DocDef::new(docname);
|
||||||
|
let name = Name::english(Uuid::new_v4().to_string().as_str());
|
||||||
|
let field_type = FieldType::Uuid;
|
||||||
|
docdef.add_field(name.clone(), field_type.clone());
|
||||||
|
let result = docdef.get_field(name).unwrap();
|
||||||
|
match result.validate(&Uuid::new_v4().into()) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => unreachable!("got {:?}: should have been a value", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn produces_error_for_bad_fields() {
|
||||||
|
let docname = Name::english("tester");
|
||||||
|
let docdef = DocDef::new(docname);
|
||||||
|
let name = Name::english(Uuid::new_v4().to_string().as_str());
|
||||||
|
match docdef.get_field(&name) {
|
||||||
|
Ok(_) => unreachable!("should return non existant field error"),
|
||||||
|
Err(err) => match err {
|
||||||
|
MTTError::NameNotFound(data) => assert_eq!(data, name),
|
||||||
|
_ => unreachable!("got {:?}: should have been document field not found", err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_multiple_fields_be_added() {
|
||||||
|
let docname = Name::english("testing");
|
||||||
|
let mut docdef = DocDef::new(docname);
|
||||||
|
let names = ["one", "two", "three"];
|
||||||
|
let field_type = FieldType::StaticString;
|
||||||
|
for name in names.iter() {
|
||||||
|
docdef.add_field(Name::english(name), field_type.clone());
|
||||||
|
}
|
||||||
|
for name in names.iter() {
|
||||||
|
let result = docdef.get_field(Name::english(name)).unwrap();
|
||||||
|
match result.validate(&"".into()) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => unreachable!("got {:?}: should have been a value", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_change_field_default_to_function() {
|
||||||
|
let docname = Name::english("something");
|
||||||
|
let mut docdef = DocDef::new(docname);
|
||||||
|
let name = Name::english("defaultfunction");
|
||||||
|
docdef.add_field(name.clone(), FieldType::StaticString);
|
||||||
|
docdef.set_default(&name, FieldType::StaticString).unwrap();
|
||||||
|
match docdef.get_field(name).unwrap().validate(&Field::None) {
|
||||||
|
Ok(data) => match data {
|
||||||
|
Field::StaticString(result) => assert_eq!(result, ""),
|
||||||
|
_ => unreachable!("got {:?}: should return a static string", data),
|
||||||
|
},
|
||||||
|
Err(err) => unreachable!("got {:?}: should return a value", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn does_set_default_value_error_on_bad_field_name() {
|
||||||
|
let docname = Name::english("something");
|
||||||
|
let mut docdef = DocDef::new(docname);
|
||||||
|
let field_name = Name::english(Uuid::new_v4().to_string().as_str());
|
||||||
|
match docdef.set_default(&field_name, FieldType::Uuid) {
|
||||||
|
Ok(_) => unreachable!("should be an error"),
|
||||||
|
Err(err) => match err {
|
||||||
|
MTTError::NameNotFound(data) => assert_eq!(data, field_name),
|
||||||
|
_ => unreachable!("got {:?}: should have been field not found", err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn does_set_default_value_error_on_bad_field_type() {
|
||||||
|
let docname = Name::english("something");
|
||||||
|
let mut docdef = DocDef::new(docname);
|
||||||
|
let name = Name::english("defaultvalue");
|
||||||
|
docdef.add_field(name.clone(), FieldType::Uuid);
|
||||||
|
match docdef.set_default(&name, "fred") {
|
||||||
|
Ok(data) => unreachable!("got {:?}, should be an error", data),
|
||||||
|
Err(err) => match err {
|
||||||
|
MTTError::FieldInvalidType => {}
|
||||||
|
_ => unreachable!("got {:?}: should have been field not found", err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn does_default_routes_get_set() {
|
||||||
|
let default_num = 5;
|
||||||
|
let docname = Name::english(Uuid::new_v4().to_string().as_str());
|
||||||
|
let docdef = DocDef::new(docname.clone());
|
||||||
|
assert_eq!(
|
||||||
|
docdef.iter_routes().count(),
|
||||||
|
default_num,
|
||||||
|
"routes contained the following:\n{:?}",
|
||||||
|
docdef.routes
|
||||||
|
);
|
||||||
|
let mut actions: HashSet<Action> = HashSet::new();
|
||||||
|
let mut doc_funcs: HashSet<String> = HashSet::new();
|
||||||
|
for path_action in docdef.iter_routes() {
|
||||||
|
let path = path_action.path();
|
||||||
|
match &path.msg_id {
|
||||||
|
Include::All => {}
|
||||||
|
_ => unreachable!("got {:?}, message id should include all", path.msg_id),
|
||||||
|
}
|
||||||
|
match &path.doc {
|
||||||
|
Include::Just(output) => match output {
|
||||||
|
NameType::Name(data) => assert_eq!(data, &docname),
|
||||||
|
_ => unreachable!("got {:?}, name type should be {:?}", path.doc, docname),
|
||||||
|
},
|
||||||
|
_ => unreachable!("got {:?}, name type should be {:?}", path.doc, docname),
|
||||||
|
};
|
||||||
|
match &path.action {
|
||||||
|
Include::Just(output) => match output {
|
||||||
|
Action::Addition => actions.insert(output.clone()),
|
||||||
|
Action::Delete => actions.insert(output.clone()),
|
||||||
|
Action::Query => actions.insert(output.clone()),
|
||||||
|
Action::Show => actions.insert(output.clone()),
|
||||||
|
Action::Update => actions.insert(output.clone()),
|
||||||
|
_ => unreachable!("got {:?} which is not a default action", output),
|
||||||
|
},
|
||||||
|
_ => unreachable!("got {:?}, which is not a default action", path.action),
|
||||||
|
};
|
||||||
|
let file_func = path_action.doc_function();
|
||||||
|
match file_func {
|
||||||
|
DocFuncType::Add => doc_funcs.insert("Add".to_string()),
|
||||||
|
DocFuncType::Delete => doc_funcs.insert("Delete".to_string()),
|
||||||
|
DocFuncType::Query => doc_funcs.insert("Query".to_string()),
|
||||||
|
DocFuncType::Show => doc_funcs.insert("Show".to_string()),
|
||||||
|
DocFuncType::Update => doc_funcs.insert("Update".to_string()),
|
||||||
|
_ => unreachable!("got {:?}, which is not a default function", file_func),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
actions.len(),
|
||||||
|
default_num,
|
||||||
|
"got {:?}, missing some actions",
|
||||||
|
actions
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
doc_funcs.len(),
|
||||||
|
default_num,
|
||||||
|
"got {:?}, missing some actions",
|
||||||
|
doc_funcs
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_route_function() {
|
||||||
|
let docname = Name::english(Uuid::new_v4().to_string().as_str());
|
||||||
|
let mut docdef = DocDef::new(docname.clone());
|
||||||
|
docdef.add_route(
|
||||||
|
Path::new(
|
||||||
|
Include::All,
|
||||||
|
Include::Just(docname.clone().into()),
|
||||||
|
Include::Just(Action::OnQuery),
|
||||||
|
),
|
||||||
|
DocFuncType::Trigger(Update::new(Query::new()).into()),
|
||||||
|
);
|
||||||
|
let path_action = docdef.iter_routes().last().unwrap();
|
||||||
|
let path = path_action.path();
|
||||||
|
match &path.msg_id {
|
||||||
|
Include::All => {}
|
||||||
|
_ => unreachable!("got {:?}, message id should include all", path.msg_id),
|
||||||
|
};
|
||||||
|
match &path.doc {
|
||||||
|
Include::Just(output) => match output {
|
||||||
|
NameType::Name(data) => assert_eq!(data, &docname),
|
||||||
|
_ => unreachable!("got {:?}, name type should be {:?}", path.doc, docname),
|
||||||
|
},
|
||||||
|
_ => unreachable!("got {:?}, name type should be {:?}", path.doc, docname),
|
||||||
|
};
|
||||||
|
match &path.action {
|
||||||
|
Include::Just(output) => match output {
|
||||||
|
Action::OnQuery => {}
|
||||||
|
_ => unreachable!("got {:?} which is not a additional action", output),
|
||||||
|
},
|
||||||
|
_ => unreachable!("got {:?}, which is not on query action", path.action),
|
||||||
|
}
|
||||||
|
let file_func = path_action.doc_function();
|
||||||
|
match file_func {
|
||||||
|
DocFuncType::Trigger(_) => {}
|
||||||
|
_ => unreachable!("got {:?}, which is not a default function", file_func),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
565
src/message.rs
565
src/message.rs
@ -1,6 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
data_director::{Include, Path, RegMsg, Register, Route},
|
data_director::{Include, Path, RegMsg, Register, Route},
|
||||||
document::create::IndexType,
|
document::{
|
||||||
|
create::IndexType,
|
||||||
|
definition::{DocDef, DocFuncType},
|
||||||
|
},
|
||||||
field::{Field, FieldType},
|
field::{Field, FieldType},
|
||||||
mtterror::MTTError,
|
mtterror::MTTError,
|
||||||
name::{Name, NameType, Names},
|
name::{Name, NameType, Names},
|
||||||
@ -435,159 +438,6 @@ mod messages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct FieldSetting {
|
|
||||||
fieldtype: FieldType,
|
|
||||||
default_value: CalcValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FieldSetting {
|
|
||||||
fn new(ftype: FieldType) -> Self {
|
|
||||||
Self {
|
|
||||||
fieldtype: ftype,
|
|
||||||
default_value: CalcValue::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_default<CV>(&mut self, holder: CV) -> Result<(), MTTError>
|
|
||||||
where
|
|
||||||
CV: Into<CalcValue>,
|
|
||||||
{
|
|
||||||
let value = holder.into();
|
|
||||||
match &value {
|
|
||||||
CalcValue::Calculate(calc) => {
|
|
||||||
if self.fieldtype != calc.get_type() {
|
|
||||||
return Err(MTTError::FieldInvalidType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CalcValue::Existing(ftype) | CalcValue::FType(ftype) => {
|
|
||||||
if &self.fieldtype != ftype {
|
|
||||||
return Err(MTTError::FieldInvalidType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CalcValue::Value(ref item) => {
|
|
||||||
if item.get_type() != self.fieldtype {
|
|
||||||
return Err(MTTError::FieldInvalidType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CalcValue::None => {}
|
|
||||||
}
|
|
||||||
self.default_value = value;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(&self, value: &Field) -> Result<Field, MTTError> {
|
|
||||||
match value {
|
|
||||||
Field::None => match &self.default_value {
|
|
||||||
CalcValue::None => Err(MTTError::InvalidNone),
|
|
||||||
_ => Ok(self.default_value.get(&Field::None)),
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let vft: FieldType = value.into();
|
|
||||||
if vft != self.fieldtype {
|
|
||||||
return Err(MTTError::DocumentFieldWrongDataType(
|
|
||||||
self.fieldtype.clone(),
|
|
||||||
vft,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(value.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod fieldsettings {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn validates_field_type() {
|
|
||||||
let fset = FieldSetting::new(FieldType::Uuid);
|
|
||||||
let value: Field = Uuid::new_v4().into();
|
|
||||||
match fset.validate(&value) {
|
|
||||||
Ok(data) => assert_eq!(data, value),
|
|
||||||
Err(err) => unreachable!("got {:?}: should have gotten a value", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn validates_for_bad_field_type() {
|
|
||||||
let fset = FieldSetting::new(FieldType::Uuid);
|
|
||||||
let value: Field = "text".into();
|
|
||||||
match fset.validate(&value) {
|
|
||||||
Ok(data) => unreachable!("got {:?}: should have gotten an error", data),
|
|
||||||
Err(err) => match err {
|
|
||||||
MTTError::DocumentFieldWrongDataType(expected, got) => {
|
|
||||||
assert_eq!(expected, FieldType::Uuid);
|
|
||||||
assert_eq!(got, FieldType::StaticString);
|
|
||||||
}
|
|
||||||
_ => unreachable!("got {:?}: should have gotten a value", err),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn no_default_returns_error() {
|
|
||||||
let fset = FieldSetting::new(FieldType::Uuid);
|
|
||||||
match fset.validate(&Field::None) {
|
|
||||||
Ok(data) => unreachable!("got {:?}: should have gotten an error", data),
|
|
||||||
Err(err) => match err {
|
|
||||||
MTTError::InvalidNone => {}
|
|
||||||
_ => unreachable!("got {:?}: should have gotten a invalid none", err),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn returns_value_if_default_is_set() {
|
|
||||||
let mut fset = FieldSetting::new(FieldType::StaticString);
|
|
||||||
fset.set_default(FieldType::StaticString).unwrap();
|
|
||||||
match fset.validate(&Field::None) {
|
|
||||||
Ok(data) => assert_eq!(data, "".into()),
|
|
||||||
Err(err) => unreachable!("got {:?}: should have gotten a value", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn returns_default_value() {
|
|
||||||
let mut fset = FieldSetting::new(FieldType::StaticString);
|
|
||||||
let input = "fred";
|
|
||||||
fset.set_default(input).unwrap();
|
|
||||||
match fset.validate(&Field::None) {
|
|
||||||
Ok(data) => assert_eq!(data, input.into()),
|
|
||||||
Err(err) => unreachable!("got {:?}: should have gotten a value", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_default_be_calculated() {
|
|
||||||
let mut fset = FieldSetting::new(FieldType::DateTime);
|
|
||||||
let duration = Duration::from_secs(3600);
|
|
||||||
let mut calc = Calculation::new(Operand::Add);
|
|
||||||
calc.add_value(FieldType::DateTime).unwrap();
|
|
||||||
calc.add_value(duration).unwrap();
|
|
||||||
fset.set_default(calc).unwrap();
|
|
||||||
let start = Utc::now() + duration;
|
|
||||||
let result = match fset.validate(&Field::None).unwrap() {
|
|
||||||
Field::DateTime(data) => data,
|
|
||||||
_ => unreachable!("should return datetime"),
|
|
||||||
};
|
|
||||||
let stop = Utc::now() + duration;
|
|
||||||
assert!(
|
|
||||||
result > start,
|
|
||||||
"{:?} should have been greater than {:?}",
|
|
||||||
result,
|
|
||||||
start
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
result < stop,
|
|
||||||
"{:?} should have been less than {:?}",
|
|
||||||
result,
|
|
||||||
stop
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Addition {
|
pub struct Addition {
|
||||||
data: Document,
|
data: Document,
|
||||||
@ -681,411 +531,6 @@ mod additions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum DocFuncType {
|
|
||||||
Add,
|
|
||||||
Delete,
|
|
||||||
ExistingQuery(MsgAction),
|
|
||||||
Query,
|
|
||||||
Show,
|
|
||||||
Trigger(MsgAction),
|
|
||||||
Update,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct PathAction {
|
|
||||||
path: Path,
|
|
||||||
func_type: DocFuncType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PathAction {
|
|
||||||
fn new(path: Path, func_type: DocFuncType) -> Self {
|
|
||||||
Self {
|
|
||||||
path: path,
|
|
||||||
func_type: func_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> Path {
|
|
||||||
self.path.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn doc_function(&self) -> DocFuncType {
|
|
||||||
self.func_type.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct DocDef {
|
|
||||||
doc_names: Vec<Name>,
|
|
||||||
field_names: Names,
|
|
||||||
fields: HashMap<Uuid, FieldSetting>,
|
|
||||||
indexes: HashMap<Uuid, IndexType>,
|
|
||||||
routes: Vec<PathAction>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DocDef {
|
|
||||||
pub fn new(name: Name) -> Self {
|
|
||||||
let names = vec![name];
|
|
||||||
Self::with_names(names)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_names(names: Vec<Name>) -> Self {
|
|
||||||
let routes = vec![
|
|
||||||
PathAction::new(
|
|
||||||
Path::new(
|
|
||||||
Include::All,
|
|
||||||
Include::Just(names[0].clone().into()),
|
|
||||||
Include::Just(Action::Addition),
|
|
||||||
),
|
|
||||||
DocFuncType::Add,
|
|
||||||
),
|
|
||||||
PathAction::new(
|
|
||||||
Path::new(
|
|
||||||
Include::All,
|
|
||||||
Include::Just(names[0].clone().into()),
|
|
||||||
Include::Just(Action::Delete),
|
|
||||||
),
|
|
||||||
DocFuncType::Delete,
|
|
||||||
),
|
|
||||||
PathAction::new(
|
|
||||||
Path::new(
|
|
||||||
Include::All,
|
|
||||||
Include::Just(names[0].clone().into()),
|
|
||||||
Include::Just(Action::Query),
|
|
||||||
),
|
|
||||||
DocFuncType::Query,
|
|
||||||
),
|
|
||||||
PathAction::new(
|
|
||||||
Path::new(
|
|
||||||
Include::All,
|
|
||||||
Include::Just(names[0].clone().into()),
|
|
||||||
Include::Just(Action::Show),
|
|
||||||
),
|
|
||||||
DocFuncType::Show,
|
|
||||||
),
|
|
||||||
PathAction::new(
|
|
||||||
Path::new(
|
|
||||||
Include::All,
|
|
||||||
Include::Just(names[0].clone().into()),
|
|
||||||
Include::Just(Action::Update),
|
|
||||||
),
|
|
||||||
DocFuncType::Update,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
Self {
|
|
||||||
doc_names: names,
|
|
||||||
field_names: Names::new(),
|
|
||||||
fields: HashMap::new(),
|
|
||||||
indexes: HashMap::new(),
|
|
||||||
routes: routes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_document_names(&self) -> &Vec<Name> {
|
|
||||||
&self.doc_names
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_field_names(&self) -> &Names {
|
|
||||||
&self.field_names
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn get_field_names_mut(&mut self) -> &mut Names {
|
|
||||||
&mut self.field_names
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_field(&mut self, name: Name, ftype: FieldType) {
|
|
||||||
let id = self.field_names.add_names([name].to_vec()).unwrap();
|
|
||||||
self.fields.insert(id, FieldSetting::new(ftype));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_field_id<NT>(&self, field_name: NT) -> Result<Uuid, MTTError>
|
|
||||||
where
|
|
||||||
NT: Into<NameType>,
|
|
||||||
{
|
|
||||||
match self.field_names.get_id(field_name) {
|
|
||||||
Ok(data) => Ok(data),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn get_field<NT>(&self, field_name: NT) -> Result<&FieldSetting, MTTError>
|
|
||||||
where
|
|
||||||
NT: Into<NameType>,
|
|
||||||
{
|
|
||||||
let id = match self.field_names.get_id(field_name) {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
|
||||||
Ok(self.fields.get(&id).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn get_field_mut<NT>(&mut self, field_name: NT) -> Result<&mut FieldSetting, MTTError>
|
|
||||||
where
|
|
||||||
NT: Into<NameType>,
|
|
||||||
{
|
|
||||||
let id = match self.field_names.get_id(field_name) {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
|
||||||
Ok(self.fields.get_mut(&id).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn field_ids(&self) -> HashSet<Uuid> {
|
|
||||||
self.fields.keys().cloned().collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate<NT>(&self, field_name: NT, value: &Field) -> Result<Field, MTTError>
|
|
||||||
where
|
|
||||||
NT: Into<NameType>,
|
|
||||||
{
|
|
||||||
let id = match self.field_names.get_id(field_name) {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
|
||||||
self.fields.get(&id).unwrap().validate(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_default<CV>(&mut self, field_name: &Name, value: CV) -> Result<(), MTTError>
|
|
||||||
where
|
|
||||||
CV: Into<CalcValue>,
|
|
||||||
{
|
|
||||||
let id = match self.field_names.get_id(field_name) {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
|
||||||
match self.fields.get_mut(&id).unwrap().set_default(value) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_index(&mut self, field_name: &Name, index_type: IndexType) -> Result<(), MTTError> {
|
|
||||||
let id = match self.field_names.get_id(field_name) {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
|
||||||
self.indexes.insert(id.clone(), index_type);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_indexes(&self) -> &HashMap<Uuid, IndexType> {
|
|
||||||
&self.indexes
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn iter(&self) -> impl Iterator<Item = (&Uuid, &FieldSetting)> {
|
|
||||||
self.fields.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_routes(&self) -> impl Iterator<Item = &PathAction> {
|
|
||||||
self.routes.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_route(&mut self, path: Path, action: DocFuncType) {
|
|
||||||
self.routes.push(PathAction::new(path, action));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod docdefs {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_field_be_added() {
|
|
||||||
let docname = Name::english("tester");
|
|
||||||
let mut docdef = DocDef::new(docname);
|
|
||||||
let name = Name::english(Uuid::new_v4().to_string().as_str());
|
|
||||||
let field_type = FieldType::Uuid;
|
|
||||||
docdef.add_field(name.clone(), field_type.clone());
|
|
||||||
let result = docdef.get_field(name).unwrap();
|
|
||||||
match result.validate(&Uuid::new_v4().into()) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(err) => unreachable!("got {:?}: should have been a value", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn produces_error_for_bad_fields() {
|
|
||||||
let docname = Name::english("tester");
|
|
||||||
let docdef = DocDef::new(docname);
|
|
||||||
let name = Name::english(Uuid::new_v4().to_string().as_str());
|
|
||||||
match docdef.get_field(&name) {
|
|
||||||
Ok(_) => unreachable!("should return non existant field error"),
|
|
||||||
Err(err) => match err {
|
|
||||||
MTTError::NameNotFound(data) => assert_eq!(data, name),
|
|
||||||
_ => unreachable!("got {:?}: should have been document field not found", err),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_multiple_fields_be_added() {
|
|
||||||
let docname = Name::english("testing");
|
|
||||||
let mut docdef = DocDef::new(docname);
|
|
||||||
let names = ["one", "two", "three"];
|
|
||||||
let field_type = FieldType::StaticString;
|
|
||||||
for name in names.iter() {
|
|
||||||
docdef.add_field(Name::english(name), field_type.clone());
|
|
||||||
}
|
|
||||||
for name in names.iter() {
|
|
||||||
let result = docdef.get_field(Name::english(name)).unwrap();
|
|
||||||
match result.validate(&"".into()) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(err) => unreachable!("got {:?}: should have been a value", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_change_field_default_to_function() {
|
|
||||||
let docname = Name::english("something");
|
|
||||||
let mut docdef = DocDef::new(docname);
|
|
||||||
let name = Name::english("defaultfunction");
|
|
||||||
docdef.add_field(name.clone(), FieldType::StaticString);
|
|
||||||
docdef.set_default(&name, FieldType::StaticString).unwrap();
|
|
||||||
match docdef.get_field(name).unwrap().validate(&Field::None) {
|
|
||||||
Ok(data) => match data {
|
|
||||||
Field::StaticString(result) => assert_eq!(result, ""),
|
|
||||||
_ => unreachable!("got {:?}: should return a static string", data),
|
|
||||||
},
|
|
||||||
Err(err) => unreachable!("got {:?}: should return a value", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn does_set_default_value_error_on_bad_field_name() {
|
|
||||||
let docname = Name::english("something");
|
|
||||||
let mut docdef = DocDef::new(docname);
|
|
||||||
let field_name = Name::english(Uuid::new_v4().to_string().as_str());
|
|
||||||
match docdef.set_default(&field_name, FieldType::Uuid) {
|
|
||||||
Ok(_) => unreachable!("should be an error"),
|
|
||||||
Err(err) => match err {
|
|
||||||
MTTError::NameNotFound(data) => assert_eq!(data, field_name),
|
|
||||||
_ => unreachable!("got {:?}: should have been field not found", err),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn does_set_default_value_error_on_bad_field_type() {
|
|
||||||
let docname = Name::english("something");
|
|
||||||
let mut docdef = DocDef::new(docname);
|
|
||||||
let name = Name::english("defaultvalue");
|
|
||||||
docdef.add_field(name.clone(), FieldType::Uuid);
|
|
||||||
match docdef.set_default(&name, "fred") {
|
|
||||||
Ok(data) => unreachable!("got {:?}, should be an error", data),
|
|
||||||
Err(err) => match err {
|
|
||||||
MTTError::FieldInvalidType => {}
|
|
||||||
_ => unreachable!("got {:?}: should have been field not found", err),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn does_default_routes_get_set() {
|
|
||||||
let default_num = 5;
|
|
||||||
let docname = Name::english(Uuid::new_v4().to_string().as_str());
|
|
||||||
let docdef = DocDef::new(docname.clone());
|
|
||||||
assert_eq!(
|
|
||||||
docdef.iter_routes().count(),
|
|
||||||
default_num,
|
|
||||||
"routes contained the following:\n{:?}",
|
|
||||||
docdef.routes
|
|
||||||
);
|
|
||||||
let mut actions: HashSet<Action> = HashSet::new();
|
|
||||||
let mut doc_funcs: HashSet<String> = HashSet::new();
|
|
||||||
for path_action in docdef.iter_routes() {
|
|
||||||
let path = path_action.path();
|
|
||||||
match &path.msg_id {
|
|
||||||
Include::All => {}
|
|
||||||
_ => unreachable!("got {:?}, message id should include all", path.msg_id),
|
|
||||||
}
|
|
||||||
match &path.doc {
|
|
||||||
Include::Just(output) => match output {
|
|
||||||
NameType::Name(data) => assert_eq!(data, &docname),
|
|
||||||
_ => unreachable!("got {:?}, name type should be {:?}", path.doc, docname),
|
|
||||||
},
|
|
||||||
_ => unreachable!("got {:?}, name type should be {:?}", path.doc, docname),
|
|
||||||
};
|
|
||||||
match &path.action {
|
|
||||||
Include::Just(output) => match output {
|
|
||||||
Action::Addition => actions.insert(output.clone()),
|
|
||||||
Action::Delete => actions.insert(output.clone()),
|
|
||||||
Action::Query => actions.insert(output.clone()),
|
|
||||||
Action::Show => actions.insert(output.clone()),
|
|
||||||
Action::Update => actions.insert(output.clone()),
|
|
||||||
_ => unreachable!("got {:?} which is not a default action", output),
|
|
||||||
},
|
|
||||||
_ => unreachable!("got {:?}, which is not a default action", path.action),
|
|
||||||
};
|
|
||||||
let file_func = path_action.doc_function();
|
|
||||||
match file_func {
|
|
||||||
DocFuncType::Add => doc_funcs.insert("Add".to_string()),
|
|
||||||
DocFuncType::Delete => doc_funcs.insert("Delete".to_string()),
|
|
||||||
DocFuncType::Query => doc_funcs.insert("Query".to_string()),
|
|
||||||
DocFuncType::Show => doc_funcs.insert("Show".to_string()),
|
|
||||||
DocFuncType::Update => doc_funcs.insert("Update".to_string()),
|
|
||||||
_ => unreachable!("got {:?}, which is not a default function", file_func),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
assert_eq!(
|
|
||||||
actions.len(),
|
|
||||||
default_num,
|
|
||||||
"got {:?}, missing some actions",
|
|
||||||
actions
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
doc_funcs.len(),
|
|
||||||
default_num,
|
|
||||||
"got {:?}, missing some actions",
|
|
||||||
doc_funcs
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn add_route_function() {
|
|
||||||
let docname = Name::english(Uuid::new_v4().to_string().as_str());
|
|
||||||
let mut docdef = DocDef::new(docname.clone());
|
|
||||||
docdef.add_route(
|
|
||||||
Path::new(
|
|
||||||
Include::All,
|
|
||||||
Include::Just(docname.clone().into()),
|
|
||||||
Include::Just(Action::OnQuery),
|
|
||||||
),
|
|
||||||
DocFuncType::Trigger(Update::new(Query::new()).into()),
|
|
||||||
);
|
|
||||||
let path_action = docdef.iter_routes().last().unwrap();
|
|
||||||
let path = path_action.path();
|
|
||||||
match &path.msg_id {
|
|
||||||
Include::All => {}
|
|
||||||
_ => unreachable!("got {:?}, message id should include all", path.msg_id),
|
|
||||||
};
|
|
||||||
match &path.doc {
|
|
||||||
Include::Just(output) => match output {
|
|
||||||
NameType::Name(data) => assert_eq!(data, &docname),
|
|
||||||
_ => unreachable!("got {:?}, name type should be {:?}", path.doc, docname),
|
|
||||||
},
|
|
||||||
_ => unreachable!("got {:?}, name type should be {:?}", path.doc, docname),
|
|
||||||
};
|
|
||||||
match &path.action {
|
|
||||||
Include::Just(output) => match output {
|
|
||||||
Action::OnQuery => {}
|
|
||||||
_ => unreachable!("got {:?} which is not a additional action", output),
|
|
||||||
},
|
|
||||||
_ => unreachable!("got {:?}, which is not on query action", path.action),
|
|
||||||
}
|
|
||||||
let file_func = path_action.doc_function();
|
|
||||||
match file_func {
|
|
||||||
DocFuncType::Trigger(_) => {}
|
|
||||||
_ => unreachable!("got {:?}, which is not a default function", file_func),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Operand {
|
pub enum Operand {
|
||||||
Add,
|
Add,
|
||||||
@ -1403,7 +848,7 @@ impl Calculation {
|
|||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_type(&self) -> FieldType {
|
pub fn get_type(&self) -> FieldType {
|
||||||
if self.values.is_empty() {
|
if self.values.is_empty() {
|
||||||
FieldType::None
|
FieldType::None
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user