Made query work with indexes first.
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s

This commit is contained in:
Jeff Baskin 2025-09-22 10:59:29 -04:00
parent 0c2af3bc96
commit 1326fad904

View File

@ -1395,6 +1395,7 @@ impl DocDef {
fn field_ids(&self) -> HashSet<&String> { fn field_ids(&self) -> HashSet<&String> {
self.fields.keys().collect::<HashSet<&String>>() self.fields.keys().collect::<HashSet<&String>>()
//self.fields.keys().cloned().collect::<HashSet<String>>()
} }
fn validate(&self, field_name: &str, value: Option<Field>) -> Result<Field, MTTError> { fn validate(&self, field_name: &str, value: Option<Field>) -> Result<Field, MTTError> {
@ -2089,6 +2090,7 @@ impl Query {
fn field_ids(&self) -> HashSet<&String> { fn field_ids(&self) -> HashSet<&String> {
self.data.keys().collect::<HashSet<&String>>() self.data.keys().collect::<HashSet<&String>>()
//self.data.keys().cloned().collect::<HashSet<String>>()
} }
} }
@ -2417,6 +2419,18 @@ impl Index {
output output
} }
fn pull(&self, calc: &Calculation) -> HashSet<Oid> {
let mut output = HashSet::new();
for (key, value) in self.data.iter() {
let mut op = calc.clone();
op.add_value(key.clone());
if op.calculate() == true.into() {
output = output.union(&value).cloned().collect();
}
}
output
}
fn remove(&mut self, field: &Field, oid: &Oid) { fn remove(&mut self, field: &Field, oid: &Oid) {
match self.data.get_mut(field) { match self.data.get_mut(field) {
Some(oids) => { Some(oids) => {
@ -2453,6 +2467,18 @@ impl Indexes {
Self { data: output } Self { data: output }
} }
fn index_ids(&self) -> HashSet<&String> {
self.data.keys().collect::<HashSet<&String>>()
}
fn get_index(&self, field_id: &str) -> &Index {
self.data.get(field_id).unwrap()
}
fn pull(&self, field_id: &str, calc: &Calculation) -> HashSet<Oid> {
self.get_index(field_id).pull(calc)
}
fn add_to_index(&mut self, field_name: &str, field: Field, oid: Oid) { fn add_to_index(&mut self, field_name: &str, field: Field, oid: Oid) {
let index = match self.data.get_mut(field_name) { let index = match self.data.get_mut(field_name) {
Some(data) => data, Some(data) => data,
@ -2770,29 +2796,64 @@ impl DocumentFile {
fn run_query(&self, query: &Query) -> Result<HashSet<Oid>, MTTError> { fn run_query(&self, query: &Query) -> Result<HashSet<Oid>, MTTError> {
let query_ids = query.field_ids(); let query_ids = query.field_ids();
let doc_ids = self.docdef.field_ids(); let doc_ids = self.docdef.field_ids();
let index_ids = self.indexes.index_ids();
if !doc_ids.is_superset(&query_ids) { if !doc_ids.is_superset(&query_ids) {
let missed = query_ids.difference(&doc_ids).last().unwrap(); let missed = query_ids.difference(&doc_ids).last().unwrap();
return Err(MTTError::DocumentFieldNotFound(missed.to_string())); return Err(MTTError::DocumentFieldNotFound(missed.to_string()));
} }
let mut oids: HashSet<Oid> = HashSet::new(); let used_indexed = index_ids
'docs: for (oid, doc) in self.docs.iter() { .intersection(&query_ids)
for query_id in query_ids.iter() { .cloned()
let doc_data = doc.get_field(query_id).unwrap(); .collect::<HashSet<&String>>();
let mut operation = query.get(query_id).unwrap(); let used_unindexed = query_ids
match operation.add_value(doc_data.clone()) { .difference(&index_ids)
Ok(_) => {} .cloned()
Err(err) => match err { .collect::<HashSet<&String>>();
MTTError::DocumentFieldWrongDataType(got, expected) => { let mut oids = HashSet::new();
return Err(MTTError::DocumentFieldWrongDataType(expected, got)) if used_indexed.is_empty() {
} 'docs: for (oid, doc) in self.docs.iter() {
_ => return Err(err), for query_id in query_ids.iter() {
}, let doc_data = doc.get_field(query_id).unwrap();
} let mut operation = query.get(query_id).unwrap();
if operation.calculate() == false.into() { match operation.add_value(doc_data.clone()) {
continue 'docs; Ok(_) => {}
Err(err) => match err {
MTTError::DocumentFieldWrongDataType(got, expected) => {
return Err(MTTError::DocumentFieldWrongDataType(expected, got))
}
_ => return Err(err),
},
}
if operation.calculate() == false.into() {
continue 'docs;
}
} }
oids.insert(oid.clone());
}
} else {
let mut first_time = true;
for field_id in used_indexed.iter() {
let op = query.get(field_id).unwrap();
let holder = self.indexes.pull(field_id, &op);
if first_time {
oids = holder;
} else {
oids = oids.intersection(&holder).cloned().collect();
}
first_time = false;
}
for field_id in used_unindexed.iter() {
let mut holder: HashSet<Oid> = HashSet::new();
for oid in oids.iter() {
let doc = self.docs.get(oid).unwrap();
let mut op = query.get(field_id).unwrap().clone();
op.add_value(doc.get_field(field_id).unwrap());
if op.calculate() == true.into() {
holder.insert(oid.clone());
}
}
oids = oids.intersection(&holder).cloned().collect();
} }
oids.insert(oid.clone());
} }
Ok(oids) Ok(oids)
} }
@ -3322,6 +3383,87 @@ mod document_files {
} }
} }
#[test]
fn query_should_work_with_multiple_inexed_fields() {
let mut doc =
TestDocument::new([FieldType::StaticString, FieldType::StaticString].to_vec());
let docdef = doc.get_docdef_mut();
docdef.add_index("field0".to_string(), IndexType::Index);
docdef.add_index("field1".to_string(), IndexType::Index);
doc.start();
let values = [
["a".into(), "a".into()].to_vec(),
["a".into(), "b".into()].to_vec(),
["b".into(), "a".into()].to_vec(),
["b".into(), "b".into()].to_vec(),
];
for value in values.iter() {
doc.populate(value.clone());
}
let mut query = Query::new();
let mut calc = Calculation::new(Operand::Equal);
calc.add_value("a");
query.add("field0".to_string(), calc);
let mut calc = Calculation::new(Operand::Equal);
calc.add_value("b");
query.add("field1".to_string(), calc);
doc.send(query).unwrap();
let result = doc.get_receiver().recv_timeout(TIMEOUT).unwrap();
let action = result.get_action();
match action {
MsgAction::Reply(data) => {
let afield: Field = "a".into();
let bfield: Field = "b".into();
assert_eq!(data.len(), 1, "should return one entry:\n{:?}", action);
for doc in data.iter() {
assert_eq!(doc.get_field("field0").unwrap(), afield);
assert_eq!(doc.get_field("field1").unwrap(), bfield);
}
}
_ => unreachable!("got {:?}: should have been a reply", action),
}
}
#[test]
fn query_should_work_with_mixed_inexed_fields() {
let mut doc =
TestDocument::new([FieldType::StaticString, FieldType::StaticString].to_vec());
let docdef = doc.get_docdef_mut();
docdef.add_index("field0".to_string(), IndexType::Index);
doc.start();
let values = [
["a".into(), "a".into()].to_vec(),
["a".into(), "b".into()].to_vec(),
["b".into(), "a".into()].to_vec(),
["b".into(), "b".into()].to_vec(),
];
for value in values.iter() {
doc.populate(value.clone());
}
let mut query = Query::new();
let mut calc = Calculation::new(Operand::Equal);
calc.add_value("a");
query.add("field0".to_string(), calc);
let mut calc = Calculation::new(Operand::Equal);
calc.add_value("b");
query.add("field1".to_string(), calc);
doc.send(query).unwrap();
let result = doc.get_receiver().recv_timeout(TIMEOUT).unwrap();
let action = result.get_action();
match action {
MsgAction::Reply(data) => {
let afield: Field = "a".into();
let bfield: Field = "b".into();
assert_eq!(data.len(), 1, "should return one entry:\n{:?}", action);
for doc in data.iter() {
assert_eq!(doc.get_field("field0").unwrap(), afield);
assert_eq!(doc.get_field("field1").unwrap(), bfield);
}
}
_ => unreachable!("got {:?}: should have been a reply", action),
}
}
#[test] #[test]
fn errors_on_bad_field_name() { fn errors_on_bad_field_name() {
let (docdef, doc_name) = create_docdef(Vec::new()); let (docdef, doc_name) = create_docdef(Vec::new());