Started to add the functionality to allow default functions.
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s

This commit is contained in:
Jeff Baskin 2025-09-18 13:30:20 -04:00
parent a157d5cc67
commit 85e12e20d4
3 changed files with 431 additions and 1 deletions

61
Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
@ -577,6 +577,7 @@ dependencies = [
"clap",
"http-body-util",
"isolang",
"rand",
"serde_json",
"tokio",
"tower",
@ -685,6 +686,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
@ -709,6 +719,35 @@ version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rand"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.5.13"
@ -1239,3 +1278,23 @@ checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags",
]
[[package]]
name = "zerocopy"
version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View File

@ -10,6 +10,7 @@ axum = ">=0.8.0"
chrono = { version = ">=0.4.40", features = ["now"] }
clap = { version = ">=4.5.1", features = ["derive"] }
isolang = ">=2.4.0"
rand = ">=0.9.2"
serde_json = ">=1.0.140"
tokio = { version = ">=1.36.0", features = ["full"] }
tower-cookies = ">=0.11.0"

View File

@ -6,6 +6,7 @@ use std::{
Arc, RwLock,
},
thread::spawn,
time::Duration,
};
use uuid::Uuid;
@ -951,7 +952,10 @@ impl CreateDoc {
#[derive(Clone, Debug, PartialEq)]
enum FieldType {
Boolean,
DateTime,
Duration,
Integer,
None,
StaticString,
Uuid,
@ -960,7 +964,10 @@ enum FieldType {
impl FieldType {
fn get_default(&self) -> Field {
match self {
FieldType::Boolean => false.into(),
FieldType::DateTime => Utc::now().into(),
FieldType::Duration => Duration::from_secs(0).into(),
FieldType::Integer => 0.into(),
FieldType::None => Field::None,
FieldType::StaticString => "".into(),
FieldType::Uuid => Uuid::new_v4().into(),
@ -971,7 +978,10 @@ impl FieldType {
impl From<&Field> for FieldType {
fn from(value: &Field) -> Self {
match value {
Field::Boolean(_) => Self::Boolean,
Field::DateTime(_) => Self::DateTime,
Field::Duration(_) => Self::Duration,
Field::Integer(_) => Self::Integer,
Field::None => Self::None,
Field::StaticString(_) => Self::StaticString,
Field::Uuid(_) => Self::Uuid,
@ -1017,7 +1027,10 @@ mod fieldtypes {
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum Field {
Boolean(bool),
DateTime(DateTime<Utc>),
Duration(Duration),
Integer(u128),
None,
StaticString(String),
Uuid(Uuid),
@ -1029,12 +1042,24 @@ impl Field {
}
}
impl From<bool> for Field {
fn from(value: bool) -> Self {
Self::Boolean(value)
}
}
impl From<DateTime<Utc>> for Field {
fn from(value: DateTime<Utc>) -> Self {
Self::DateTime(value)
}
}
impl From<Duration> for Field {
fn from(value: Duration) -> Self {
Self::Duration(value)
}
}
impl From<String> for Field {
fn from(value: String) -> Self {
Self::StaticString(value)
@ -1053,6 +1078,12 @@ impl From<Uuid> for Field {
}
}
impl From<u128> for Field {
fn from(value: u128) -> Self {
Self::Integer(value)
}
}
#[cfg(test)]
mod fields {
use super::*;
@ -1091,6 +1122,17 @@ mod fields {
}
assert_eq!(result.get_type(), FieldType::Uuid);
}
#[test]
fn create_from_datatime() {
let data = Utc::now();
let result: Field = data.into();
match result.clone() {
Field::DateTime(output) => assert_eq!(output, data),
_ => unreachable!("got {:?}: should have been uuid", result),
}
assert_eq!(result.get_type(), FieldType::DateTime);
}
}
#[derive(Clone, Debug)]
@ -1212,6 +1254,31 @@ mod fieldsettings {
Err(err) => unreachable!("got {:?}: should have gotten a value", err),
}
}
//#[test]
fn can_default_be_calculated() {
let mut fset = FieldSetting::new(FieldType::DateTime);
fset.set_default(None);
let duration = Duration::from_secs(3600);
let start = Utc::now() + duration;
let result = match fset.validate(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)]
@ -1476,6 +1543,8 @@ mod docdefs {
#[derive(Clone, Debug)]
enum Operand {
Add,
Assign,
Equal,
}
@ -1483,6 +1552,7 @@ impl Operand {
fn validate(&self, x: &Field, y: &Field) -> bool {
match self {
Self::Equal => x == y,
_ => false,
}
}
}
@ -1508,6 +1578,306 @@ mod operands {
}
}
#[derive(Clone, Debug)]
enum CalcValue {
FType(FieldType),
Value(Field),
}
impl CalcValue {
fn get(&self) -> Field {
match self {
Self::FType(ftype) => ftype.get_default(),
Self::Value(field) => field.clone(),
}
}
}
impl From<Field> for CalcValue {
fn from(value: Field) -> Self {
Self::Value(value)
}
}
impl From<FieldType> for CalcValue {
fn from(value: FieldType) -> Self {
Self::FType(value)
}
}
impl From<bool> for CalcValue {
fn from(value: bool) -> Self {
let output: Field = value.into();
Self::from(output).into()
}
}
impl From<DateTime<Utc>> for CalcValue {
fn from(value: DateTime<Utc>) -> Self {
let output: Field = value.into();
Self::from(output).into()
}
}
impl From<Duration> for CalcValue {
fn from(value: Duration) -> Self {
let output: Field = value.into();
Self::from(output).into()
}
}
impl From<u128> for CalcValue {
fn from(value: u128) -> Self {
let output: Field = value.into();
Self::from(output).into()
}
}
impl From<&str> for CalcValue {
fn from(value: &str) -> Self {
let output: Field = value.into();
Self::from(output).into()
}
}
impl From<String> for CalcValue {
fn from(value: String) -> Self {
let output: Field = value.into();
Self::from(output).into()
}
}
impl From<Uuid> for CalcValue {
fn from(value: Uuid) -> Self {
let output: Field = value.into();
Self::from(output).into()
}
}
#[cfg(test)]
mod calcvalues {
use super::*;
#[test]
fn from_uuid() {
let value = Uuid::new_v4();
let expected: Field = value.into();
let result: CalcValue = value.into();
match result {
CalcValue::FType(_) => unreachable!("got {:?}, should have gotten a field", result),
CalcValue::Value(data) => assert_eq!(data, expected),
}
}
#[test]
fn from_str() {
let value = "something";
let expected: Field = value.into();
let result: CalcValue = value.into();
match result {
CalcValue::FType(_) => unreachable!("got {:?}, should have gotten a field", result),
CalcValue::Value(data) => assert_eq!(data, expected),
}
}
#[test]
fn from_string() {
let value = "data".to_string();
let expected: Field = value.clone().into();
let result: CalcValue = value.into();
match result {
CalcValue::FType(_) => unreachable!("got {:?}, should have gotten a field", result),
CalcValue::Value(data) => assert_eq!(data, expected),
}
}
#[test]
fn from_boolean() {
let value = true;
let expected: Field = value.clone().into();
let result: CalcValue = value.into();
match result {
CalcValue::FType(_) => unreachable!("got {:?}, should have gotten a field", result),
CalcValue::Value(data) => assert_eq!(data, expected),
}
}
#[test]
fn from_datetime() {
let value = Utc::now();
let expected: Field = value.clone().into();
let result: CalcValue = value.into();
match result {
CalcValue::FType(_) => unreachable!("got {:?}, should have gotten a field", result),
CalcValue::Value(data) => assert_eq!(data, expected),
}
}
#[test]
fn from_duration() {
let value = Duration::from_secs(5);
let expected: Field = value.clone().into();
let result: CalcValue = value.into();
match result {
CalcValue::FType(_) => unreachable!("got {:?}, should have gotten a field", result),
CalcValue::Value(data) => assert_eq!(data, expected),
}
}
#[test]
fn from_integer() {
let value: u128 = 5;
let expected: Field = value.clone().into();
let result: CalcValue = value.into();
match result {
CalcValue::FType(_) => unreachable!("got {:?}, should have gotten a field", result),
CalcValue::Value(data) => assert_eq!(data, expected),
}
}
}
#[derive(Clone, Debug)]
struct Calculation {
operation: Operand,
values: Vec<CalcValue>,
}
impl Calculation {
fn new(operand: Operand) -> Self {
Self {
operation: operand,
values: Vec::new(),
}
}
fn get_fields(&self) -> Vec<Field> {
let mut output = Vec::new();
for item in self.values.iter() {
output.push(item.get());
}
output
}
fn add_value<CV>(&mut self, data: CV) -> Result<(), MTTError>
where
CV: Into<CalcValue>,
{
let holder: CalcValue = data.into();
if self.values.len() == 0 {
self.values.push(holder);
} else {
match self.operation {
Operand::Add => {
if self.values[0].get().get_type() == holder.get().get_type() {
self.values.push(holder);
} else {
return Err(MTTError::DocumentFieldWrongDataType(
FieldType::None,
FieldType::None,
));
}
}
_ => self.values.push(holder),
}
}
Ok(())
}
fn calculate(&self) -> Field {
match self.operation {
Operand::Add => {
let values = self.get_fields();
match values[0].get_type() {
FieldType::Integer => {
let mut output: u128 = 0;
for item in values.iter() {
match item {
Field::Integer(data) => output += data,
_ => unreachable! {"got {:?} expected Integer", item},
}
}
output.into()
}
_ => unreachable!("{:?} does not handle addition", values[0].get_type()),
}
}
Operand::Assign => self.values[0].get(),
Operand::Equal => { self.values[0].get() == self.values[1].get() }.into(),
}
}
}
#[cfg(test)]
mod calculations {
use super::*;
use rand::random;
#[test]
fn can_assign_value() {
let mut calc = Calculation::new(Operand::Assign);
let data: Field = Uuid::new_v4().into();
calc.add_value(data.clone());
let result = calc.calculate();
assert_eq!(result, data);
}
#[test]
fn can_assign_default_function() {
let mut calc = Calculation::new(Operand::Assign);
calc.add_value(FieldType::Uuid);
let result1 = calc.calculate();
let result2 = calc.calculate();
assert_ne!(result1, result2);
}
#[test]
fn can_equal_true() {
let mut calc = Calculation::new(Operand::Equal);
let data: Field = Uuid::new_v4().into();
calc.add_value(data.clone());
calc.add_value(data.clone());
let expected: Field = true.into();
let result = calc.calculate();
assert_eq!(result, expected);
}
#[test]
fn can_equal_false() {
let mut calc = Calculation::new(Operand::Equal);
let value1: Field = "fred".into();
let value2: Field = "barney".into();
calc.add_value(value1);
calc.add_value(value2);
let expected: Field = false.into();
let result = calc.calculate();
assert_eq!(result, expected);
}
#[test]
fn can_add_numbers() {
let mut calc = Calculation::new(Operand::Add);
let value1: u128 = random::<u8>().into();
let value2: u128 = random::<u8>().into();
let expected: Field = { value1 + value2 }.into();
let value1: Field = value1.into();
let value2: Field = value2.into();
calc.add_value(value1);
calc.add_value(value2);
let result = calc.calculate();
assert_eq!(result, expected);
}
#[test]
fn returns_error_on_mismatch() {
let mut calc = Calculation::new(Operand::Add);
calc.add_value(Uuid::nil());
match calc.add_value("mismatch") {
Ok(_) => unreachable!("should have returned an error"),
Err(_) => {}
}
}
}
#[derive(Clone, Debug)]
struct Operation {
field_name: String,