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> {
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> {
@ -2089,6 +2090,7 @@ impl Query {
fn field_ids(&self) -> HashSet<&String> {
self.data.keys().collect::<HashSet<&String>>()
//self.data.keys().cloned().collect::<HashSet<String>>()
}
}
@ -2417,6 +2419,18 @@ impl Index {
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) {
match self.data.get_mut(field) {
Some(oids) => {
@ -2453,6 +2467,18 @@ impl Indexes {
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) {
let index = match self.data.get_mut(field_name) {
Some(data) => data,
@ -2770,29 +2796,64 @@ impl DocumentFile {
fn run_query(&self, query: &Query) -> Result<HashSet<Oid>, MTTError> {
let query_ids = query.field_ids();
let doc_ids = self.docdef.field_ids();
let index_ids = self.indexes.index_ids();
if !doc_ids.is_superset(&query_ids) {
let missed = query_ids.difference(&doc_ids).last().unwrap();
return Err(MTTError::DocumentFieldNotFound(missed.to_string()));
}
let mut oids: HashSet<Oid> = HashSet::new();
'docs: for (oid, doc) in self.docs.iter() {
for query_id in query_ids.iter() {
let doc_data = doc.get_field(query_id).unwrap();
let mut operation = query.get(query_id).unwrap();
match operation.add_value(doc_data.clone()) {
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;
let used_indexed = index_ids
.intersection(&query_ids)
.cloned()
.collect::<HashSet<&String>>();
let used_unindexed = query_ids
.difference(&index_ids)
.cloned()
.collect::<HashSet<&String>>();
let mut oids = HashSet::new();
if used_indexed.is_empty() {
'docs: for (oid, doc) in self.docs.iter() {
for query_id in query_ids.iter() {
let doc_data = doc.get_field(query_id).unwrap();
let mut operation = query.get(query_id).unwrap();
match operation.add_value(doc_data.clone()) {
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)
}
@ -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]
fn errors_on_bad_field_name() {
let (docdef, doc_name) = create_docdef(Vec::new());