Rebuilt record to include field names.
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s

This commit is contained in:
Jeff Baskin 2025-10-13 14:13:10 -04:00
parent 96ac523898
commit 7755947816

View File

@ -27,6 +27,7 @@ enum MTTError {
DocumentFieldWrongDataType(FieldType, FieldType), DocumentFieldWrongDataType(FieldType, FieldType),
DocumentNotFound(String), DocumentNotFound(String),
FieldDuplicate(String, Field), FieldDuplicate(String, Field),
FieldMissingData,
NameDuplicate(Name), NameDuplicate(Name),
NameInvalidID(Uuid), NameInvalidID(Uuid),
NameMissingTranslation(Language), NameMissingTranslation(Language),
@ -237,6 +238,7 @@ struct Message {
msg_id: Uuid, msg_id: Uuid,
document_id: NameType, document_id: NameType,
action: MsgAction, action: MsgAction,
// session: Option<?>
} }
impl Message { impl Message {
@ -752,7 +754,6 @@ mod names {
let id = names.add_name(english.clone()).unwrap(); let id = names.add_name(english.clone()).unwrap();
let result = names.add_translation(english, japanese.clone()).unwrap(); let result = names.add_translation(english, japanese.clone()).unwrap();
assert_eq!(result, id); assert_eq!(result, id);
println!("\n{:?}", names);
let output = names.get_name(&id, &Language::from_639_1("ja").unwrap()); let output = names.get_name(&id, &Language::from_639_1("ja").unwrap());
assert_eq!(output.unwrap().to_string(), alt); assert_eq!(output.unwrap().to_string(), alt);
assert_eq!(names.get_id(&japanese).unwrap(), id); assert_eq!(names.get_id(&japanese).unwrap(), id);
@ -2378,6 +2379,14 @@ impl DocDef {
&self.doc_name &self.doc_name
} }
fn get_field_names(&self) -> &Names {
&self.field_names
}
fn get_field_names_mut(&mut self) -> &mut Names {
&mut self.field_names
}
fn add_field(&mut self, name: Name, ftype: FieldType) { fn add_field(&mut self, name: Name, ftype: FieldType) {
let id = self.field_names.add_name(name).unwrap(); let id = self.field_names.add_name(name).unwrap();
self.fields.insert(id, FieldSetting::new(ftype)); self.fields.insert(id, FieldSetting::new(ftype));
@ -2406,9 +2415,8 @@ impl DocDef {
Ok(self.fields.get_mut(&id).unwrap()) Ok(self.fields.get_mut(&id).unwrap())
} }
fn field_ids(&self) -> HashSet<&Uuid> { fn field_ids(&self) -> HashSet<Uuid> {
self.fields.keys().collect() self.fields.keys().cloned().collect()
//self.fields.keys().cloned().collect::<HashSet<String>>()
} }
fn validate<NT>(&self, field_name: NT, value: Option<Field>) -> Result<Field, MTTError> where NT: Into<NameType> { fn validate<NT>(&self, field_name: NT, value: Option<Field>) -> Result<Field, MTTError> where NT: Into<NameType> {
@ -2417,15 +2425,6 @@ impl DocDef {
Err(err) => return Err(err), Err(err) => return Err(err),
}; };
self.fields.get(&id).unwrap().validate(value) self.fields.get(&id).unwrap().validate(value)
/*
let setting = match self.get_field(field_name) {
Ok(data) => data,
Err(err) => return Err(err),
};
setting.validate(value)
*/
} }
fn set_default(&mut self, field_name: &Name, value: Calculation) -> Result<(), MTTError> { fn set_default(&mut self, field_name: &Name, value: Calculation) -> Result<(), MTTError> {
@ -3296,6 +3295,213 @@ mod replies {
} }
} }
#[derive(Clone, Debug)]
struct Record {
names: Names,
data: HashMap<Uuid, Field>
}
impl Record {
fn new(names: Names) -> Self {
Self {
names: names,
data: HashMap::new(),
}
}
fn insert<NT, F>(&mut self, field_id: NT, data: F) -> Result<(), MTTError> where F: Into<Field>, NT: Into<NameType> {
let id = match self.names.get_id(field_id) {
Ok(data) => data,
Err(err) => return Err(err),
};
self.data.insert(id, data.into());
Ok(())
}
fn get<NT>(&self, field_id: NT) -> Result<Field, MTTError> where NT: Into<NameType> {
let id = match self.names.get_id(field_id) {
Ok(data) => data,
Err(err) => return Err(err),
};
match self.data.get(&id) {
Some(data) => Ok(data.clone()),
None => Err(MTTError::FieldMissingData),
}
}
}
#[derive(Clone, Debug)]
struct Records {
names: Names,
records: Vec<Record>,
}
impl Records {
fn new(names: Names) -> Self {
Self {
names: names,
records: Vec::new(),
}
}
fn len(&self) -> usize {
0
}
fn add<NT, F>(&mut self, name: NT, data: F) -> Result<(), MTTError> where F: Into<Field>, NT: Into<NameType> {
Ok(())
}
fn get<NT>(&self, rec_num: usize, field_name: NT) -> Result<&Field, MTTError> where NT: Into<NameType> {
Err(MTTError::QueryCannotChangeData)
}
fn submit(&mut self) {
}
fn iter(&self) -> impl Iterator<Item = usize> {
RecordsIter::new(self)
}
}
struct RecordsIter {
position: usize,
rec_count: usize,
}
impl RecordsIter {
fn new(records: &Records) -> Self {
Self {
position: 0,
rec_count: records.len(),
}
}
}
impl Iterator for RecordsIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
self.position += 1;
if self.position < self.rec_count {
Some(self.position)
} else {
None
}
}
}
#[cfg(test)]
mod records {
use super::*;
#[test]
fn can_create_a_record() {
let mut names = Names::new();
let count = 5;
let mut ids: HashSet<Uuid> = HashSet::new();
while ids.len() < count {
ids.insert(Uuid::new_v4());
}
let mut name_ids: HashMap<Name, Uuid> = HashMap::new();
for id in ids.iter() {
let name = Name::english(id.to_string());
let field_id = names.add_name(name.clone()).unwrap();
name_ids.insert(name, field_id);
}
let mut rec = Record::new(names);
for id in ids.iter() {
let name = Name::english(id.to_string());
rec.insert(name, id.clone());
}
for (name, id) in name_ids.iter() {
let id1 = rec.get(name).unwrap();
let id2 = rec.get(id).unwrap();
assert_eq!(id1, id2, "id and name should produce the same result");
match id1 {
Field::Uuid(data) => {
assert_eq!(data.to_string(), name.to_string(), "for this case, name and data should match");
assert!(ids.contains(&data), "{:?} not in {:?}", id1, ids);
ids.remove(&data);
},
_ => unreachable!("got {:?}, should have been uuid", id1),
}
}
assert_eq!(ids.len(), 0, "did not pull {:?}", ids);
}
#[test]
fn does_insert_error_on_bad_field_name() {
let names = Names::new();
let mut rec = Record::new(names);
let name = Name::english("wrong".to_string());
match rec.insert(name.clone(), "bad") {
Ok(_) => unreachable!("should return not found error"),
Err(err) => match err {
MTTError::NameNotFound(data) => assert_eq!(data, name),
_ => unreachable!("got {:?}, should have been not found", err),
}
}
}
#[test]
fn does_get_error_on_bad_field_name() {
let names = Names::new();
let mut rec = Record::new(names);
let name = Name::english("missing".to_string());
match rec.get(&name) {
Ok(_) => unreachable!("should return not found error"),
Err(err) => match err {
MTTError::NameNotFound(data) => assert_eq!(data, name),
_ => unreachable!("got {:?}, should have been not found", err),
}
}
}
#[test]
fn does_get_error_on_missing_data() {
let mut names = Names::new();
let name = Name::english("empty".to_string());
names.add_name(name.clone()).unwrap();
let mut rec = Record::new(names);
match rec.get(&name) {
Ok(_) => unreachable!("should return not found error"),
Err(err) => match err {
MTTError::FieldMissingData => {},
_ => unreachable!("got {:?}, should have been not found", err),
}
}
}
#[test]
fn can_create_empty_record() {
let rec = Records::new(Names::new());
assert_eq!(rec.len(), 0);
}
#[test]
#[ignore]
fn can_have_multiple_rows() {
let mut names = Names::new();
let name = Name::english("field".to_string());
let mut recs = Records::new(names);
let data: [Field; 3] = ["one".into(), "two".into(), "three".into()];
for item in data.iter() {
recs.add(&name, item.clone());
recs.submit();
}
assert_eq!(recs.len(), data.len(), "does not contain the correct number of records");
for rec_num in recs.iter() {
assert!(data.contains(recs.get(rec_num, &name).unwrap()));
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Document { struct Document {
data: HashMap<NameType, CalcValue>, data: HashMap<NameType, CalcValue>,
@ -3334,6 +3540,10 @@ impl Document {
fn iter(&self) -> DocIter { fn iter(&self) -> DocIter {
DocIter::new(self) DocIter::new(self)
} }
fn is_empty(&self) -> bool {
self.data.is_empty()
}
} }
struct DocIter { struct DocIter {
@ -3724,7 +3934,7 @@ mod indexes {
struct DocumentFile { struct DocumentFile {
docdef: DocDef, docdef: DocDef,
docs: HashMap<Oid, Document>, docs: HashMap<Oid, HashMap<Uuid, Field>>,
indexes: Indexes, indexes: Indexes,
queue: Queue, queue: Queue,
rx: Receiver<Message>, rx: Receiver<Message>,
@ -3813,11 +4023,13 @@ impl DocumentFile {
&self.docdef &self.docdef
} }
/*
fn get_documents<'a>(&self) -> impl Iterator<Item = (&Oid, &Document)> { fn get_documents<'a>(&self) -> impl Iterator<Item = (&Oid, &Document)> {
self.docs.iter() self.docs.iter()
} }
*/
fn validate<NT>(&self, field_name: NT, value: Option<Field>) -> Result<Field, MTTError> where NT: Into<NameType> { fn validate<NT>(&self, field_name: NT, value: Option<Field>) -> Result<(Uuid, Field), MTTError> where NT: Into<NameType> {
let field_id = match self.docdef.get_field_id(field_name) { let field_id = match self.docdef.get_field_id(field_name) {
Ok(data) => data, Ok(data) => data,
Err(err) => return Err(err), Err(err) => return Err(err),
@ -3830,7 +4042,7 @@ impl DocumentFile {
Ok(_) => {} Ok(_) => {}
Err(err) => return Err(err), Err(err) => return Err(err),
} }
Ok(output) Ok((field_id, output))
} }
fn add_field_to_error(key: String, err: MTTError) -> MTTError { fn add_field_to_error(key: String, err: MTTError) -> MTTError {
@ -3852,6 +4064,46 @@ impl DocumentFile {
} }
fn add_document(&mut self, addition: &Addition) -> MsgAction { fn add_document(&mut self, addition: &Addition) -> MsgAction {
let mut holder: HashMap<Uuid, Field> = HashMap::new();
let doc = addition.get_document();
for (field, value) in doc.iter() {
match self.validate(field, Some(value)) {
Ok((id, data)) => {holder.insert(id, data);},
Err(err) => return MsgAction::Error(err),
}
}
let requested: HashSet<Uuid> = holder.keys().cloned().collect();
let all_fields = self.docdef.field_ids();
for field in all_fields.difference(&requested).cloned() {
match self.validate(field, None) {
Ok((id, data)) => {holder.insert(id, data);},
Err(err) => return MsgAction::Error(err),
}
}
let mut reply = Reply::new();
if !holder.is_empty() {
let mut oid = Oid::new();
while self.docs.contains_key(&oid) {
oid = Oid::new();
}
self.docs.insert(oid, holder);
/*
self.docs.insert(oid.clone(), holder.clone());
for (key, value) in holder.iter() {
self.add_to_index(&key, value.clone(), oid.clone());
}
reply.add(holder);
*/
}
reply.into()
/*
let mut holder = Document::new(); let mut holder = Document::new();
let doc = addition.get_document(); let doc = addition.get_document();
for (key, value) in doc.iter() { for (key, value) in doc.iter() {
@ -3872,6 +4124,8 @@ impl DocumentFile {
} }
} }
let mut oid = Oid::new(); let mut oid = Oid::new();
let mut reply = Reply::new();
if !holder.is_empty() {
while self.docs.contains_key(&oid) { while self.docs.contains_key(&oid) {
oid = Oid::new(); oid = Oid::new();
} }
@ -3879,18 +4133,21 @@ impl DocumentFile {
for (key, value) in holder.iter() { for (key, value) in holder.iter() {
self.add_to_index(&key, value.clone(), oid.clone()); self.add_to_index(&key, value.clone(), oid.clone());
} }
let mut reply = Reply::new();
reply.add(holder); reply.add(holder);
}
reply.into() reply.into()
*/
} }
fn delete(&mut self, delete: &Delete) -> MsgAction { fn delete(&mut self, delete: &Delete) -> MsgAction {
let mut reply = Reply::new(); let mut reply = Reply::new();
/*
let oids = self.run_query(delete.get_query()).unwrap(); let oids = self.run_query(delete.get_query()).unwrap();
for oid in oids.iter() { for oid in oids.iter() {
reply.add(self.docs.get(oid).unwrap().clone()); reply.add(self.docs.get(oid).unwrap().clone());
self.docs.remove(oid); self.docs.remove(oid);
} }
*/
reply.into() reply.into()
} }
@ -3915,11 +4172,10 @@ impl DocumentFile {
oids = oids.intersection(&holder).cloned().collect(); oids = oids.intersection(&holder).cloned().collect();
} }
for (field_id, calculation) in unindexed.iter() { for (field_id, calculation) in unindexed.iter() {
let mut holder: HashSet<Oid> = HashSet::new();
for oid in oids.clone().iter() { for oid in oids.clone().iter() {
let doc = self.docs.get(oid).unwrap(); let doc = self.docs.get(oid).unwrap();
let mut calc = calculation.clone(); let mut calc = calculation.clone();
calc.add_value(doc.get_field(field_id).unwrap()); calc.add_value(doc.get(field_id).unwrap().clone());
if calc.calculate() == false.into() { if calc.calculate() == false.into() {
oids.remove(oid); oids.remove(oid);
} }
@ -4002,7 +4258,7 @@ impl DocumentFile {
Ok(result) => { Ok(result) => {
let mut reply = Reply::new(); let mut reply = Reply::new();
for oid in result.iter() { for oid in result.iter() {
reply.add(self.docs.get(oid).unwrap().clone()); //reply.add(self.docs.get(oid).unwrap().clone());
} }
reply.into() reply.into()
} }
@ -4011,6 +4267,7 @@ impl DocumentFile {
} }
fn update(&mut self, update: &Update) -> MsgAction { fn update(&mut self, update: &Update) -> MsgAction {
/*
let oids = match self.run_query(update.get_query()) { let oids = match self.run_query(update.get_query()) {
Ok(result) => result, Ok(result) => result,
Err(err) => return err.into(), Err(err) => return err.into(),
@ -4050,6 +4307,8 @@ impl DocumentFile {
} }
} }
reply.into() reply.into()
*/
Reply::new().into()
} }
} }
@ -4223,8 +4482,11 @@ mod document_files {
test_doc.start(); test_doc.start();
let queue = test_doc.get_queue(); let queue = test_doc.get_queue();
let msg_actions = [ let msg_actions = [
MsgAction::Show, MsgAction::Addition(Addition::new()),
MsgAction::Delete(Delete::new()),
MsgAction::Query(Query::new()), MsgAction::Query(Query::new()),
MsgAction::Show,
MsgAction::Update(Update::new()),
]; ];
for msg_action in msg_actions.iter() { for msg_action in msg_actions.iter() {
let msg = Message::new(name.clone(), msg_action.clone()); let msg = Message::new(name.clone(), msg_action.clone());
@ -4235,7 +4497,7 @@ mod document_files {
}; };
assert_eq!(result.get_message_id(), msg.get_message_id(), "for {:?} response and reply ids should equal", msg_action); assert_eq!(result.get_message_id(), msg.get_message_id(), "for {:?} response and reply ids should equal", msg_action);
match result.get_action() { match result.get_action() {
MsgAction::Reply(data) => assert_eq!(data.len(), 0), MsgAction::Reply(data) => assert_eq!(data.len(), 0, "for {:?} got {:?}", msg_action, result),
_ => unreachable!( _ => unreachable!(
"for {:?} got {:?}: should have received a reply", "for {:?} got {:?}: should have received a reply",
msg_action, msg_action,
@ -4258,8 +4520,11 @@ mod document_files {
queue.send(setup).unwrap(); queue.send(setup).unwrap();
test_doc.get_receiver().recv_timeout(TIMEOUT).unwrap(); test_doc.get_receiver().recv_timeout(TIMEOUT).unwrap();
let msg_actions = [ let msg_actions = [
MsgAction::Show, MsgAction::Addition(Addition::new()),
MsgAction::Delete(Delete::new()),
MsgAction::Query(Query::new()), MsgAction::Query(Query::new()),
MsgAction::Show,
MsgAction::Update(Update::new()),
]; ];
for msg_action in msg_actions.iter() { for msg_action in msg_actions.iter() {
let msg = Message::new(alt.clone(), msg_action.clone()); let msg = Message::new(alt.clone(), msg_action.clone());
@ -4275,12 +4540,39 @@ mod document_files {
} }
#[test] #[test]
#[ignore]
fn can_document_be_added() { fn can_document_be_added() {
let doc_name = Name::english("document".to_string()); let doc_name = Name::english("document".to_string());
let mut docdef = DocDef::new(doc_name.clone()); let mut docdef = DocDef::new(doc_name.clone());
let name = Name::english("field".to_string()); let name = Name::english("field".to_string());
let data = Uuid::new_v4(); let data = Uuid::new_v4();
docdef.add_field(name, FieldType::Uuid); docdef.add_field(name.clone(), FieldType::Uuid);
let mut test_doc: TestDocument = docdef.clone().into();
test_doc.start();
let queue = test_doc.get_queue();
let mut new_doc = Addition::new();
new_doc.add_field(name.clone(), data.clone());
let msg = Message::new(doc_name, new_doc);
queue.send(msg.clone()).unwrap();
let result = test_doc.get_receiver().recv_timeout(TIMEOUT).unwrap();
assert_eq!(result.get_message_id(), msg.get_message_id());
match result.get_action() {
MsgAction::Reply(output) => {
assert_eq!(output.len(), 1);
let holder = output.iter().next().unwrap();
match holder.get_field(name.clone()) {
Some(field) => match field {
Field::Uuid(store) => assert_eq!(store, data),
_ => unreachable!(
"got {:?}: should have received uuid",
holder.get_field(name).unwrap()
),
},
None => unreachable!("{:?} did not contain field '{:?}'", holder, name),
}
}
_ => unreachable!("\n\ngot {:?}\n\nfor {:?}\n\nshould have been a reply", result, docdef),
}
/* /*
let (queue, rx) = test_doc(doc_name, docdef, standard_routes()); let (queue, rx) = test_doc(doc_name, docdef, standard_routes());