Skip to content

Commit

Permalink
Add tests for the various types and support human dates
Browse files Browse the repository at this point in the history
Signed-off-by: Jim Crossley <[email protected]>
  • Loading branch information
jcrossley3 committed Oct 22, 2024
1 parent 2504e9c commit 494acd5
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 33 deletions.
84 changes: 53 additions & 31 deletions common/src/db/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,35 @@ impl Query {
/// returning true if the context is successfully matched by the
/// query, by either a filter or a full-text search of all the
/// values of type Value::String.
pub fn apply(&self, context: HashMap<&'static str, Value>) -> bool {
pub fn apply(&self, context: &HashMap<&'static str, Value>) -> bool {
use Operator::*;
self.parse().iter().all(|c| match c {
Constraint {
field: Some(f),
op: Some(o),
value: vs,
} => context.get(f.as_str()).is_some_and(|field| match o {
Equal => vs.iter().any(|v| field.eq(v)),
NotEqual => vs.iter().all(|v| field.ne(v)),
Like => vs.iter().any(|v| field.contains(v)),
NotLike => vs.iter().all(|v| !field.contains(v)),
GreaterThan => vs.iter().all(|v| field.gt(v)),
GreaterThanOrEqual => vs.iter().all(|v| field.ge(v)),
LessThan => vs.iter().all(|v| field.lt(v)),
LessThanOrEqual => vs.iter().all(|v| field.le(v)),
self.parse().iter().all(|c| {
log::debug!("{c:?}");
match c {
Constraint {
field: Some(f),
op: Some(o),
value: vs,
} => context.get(f.as_str()).is_some_and(|field| match o {
Equal => vs.iter().any(|v| field.eq(v)),
NotEqual => vs.iter().all(|v| field.ne(v)),
Like => vs.iter().any(|v| field.contains(v)),
NotLike => vs.iter().all(|v| !field.contains(v)),
GreaterThan => vs.iter().all(|v| field.gt(v)),
GreaterThanOrEqual => vs.iter().all(|v| field.ge(v)),
LessThan => vs.iter().all(|v| field.lt(v)),
LessThanOrEqual => vs.iter().all(|v| field.le(v)),
_ => false,
}),
Constraint {
field: None,
value: vs,
..
} => context
.values()
.any(|field| vs.iter().any(|v| field.contains(v))),
_ => false,
}),
Constraint {
field: None,
value: vs,
..
} => context
.values()
.any(|field| vs.iter().any(|v| field.contains(v))),
_ => false,
}
})
}

Expand Down Expand Up @@ -235,7 +238,7 @@ pub enum Value<'a> {
String(&'a str),
Int(i32),
Float(f64),
Date(OffsetDateTime),
Date(&'a OffsetDateTime),
}

impl Value<'_> {
Expand All @@ -259,10 +262,7 @@ impl PartialEq<String> for Value<'_> {
Ok(i) => v.eq(&i),
_ => false,
},
Self::Date(v) => match OffsetDateTime::parse(rhs, &Rfc3339) {
Ok(i) => v.eq(&i),
_ => false,
},
Self::Date(_) => false, // impractical, given the granularity
}
}
}
Expand All @@ -279,8 +279,14 @@ impl PartialOrd<String> for Value<'_> {
Ok(i) => v.partial_cmp(&i),
_ => None,
},
Self::Date(v) => match OffsetDateTime::parse(rhs, &Rfc3339) {
Ok(i) => v.partial_cmp(&i),
Self::Date(v) => match from_human_time(&v.to_string()) {
Ok(ParseResult::DateTime(field)) => {
if let Ok(ParseResult::DateTime(other)) = from_human_time(rhs) {
field.partial_cmp(&other)
} else {
None
}
}
_ => None,
},
}
Expand Down Expand Up @@ -1124,6 +1130,22 @@ mod tests {
Ok(())
}

#[test(tokio::test)]
async fn apply_to_context() -> Result<(), anyhow::Error> {
let now = time::OffsetDateTime::now_utc();
let context = HashMap::from([
("id", Value::String("foo")),
("count", Value::Int(42)),
("score", Value::Float(6.66)),
("published", Value::Date(&now)),
]);
assert!(q("oo|aa|bb&count<100&count>10&id=foo").apply(&context));
assert!(q("score=6.66").apply(&context));
assert!(q("count>=42&count<=42").apply(&context));
assert!(q("published>2 days ago&published<in 1 week").apply(&context));

Ok(())
}
/////////////////////////////////////////////////////////////////////////
// Test helpers
/////////////////////////////////////////////////////////////////////////
Expand Down
4 changes: 2 additions & 2 deletions modules/analysis/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ impl AnalysisService {
.node_indices()
.filter(|&i| {
graph.node_weight(i).is_some_and(|node| {
query.apply(HashMap::from([
query.apply(&HashMap::from([
("sbom_id", Value::String(&node.sbom_id)),
("node_id", Value::String(&node.node_id)),
("name", Value::String(&node.name)),
Expand Down Expand Up @@ -601,7 +601,7 @@ impl AnalysisService {
.node_indices()
.filter(|&i| {
graph.node_weight(i).is_some_and(|node| {
query.apply(HashMap::from([
query.apply(&HashMap::from([
("sbom_id", Value::String(&node.sbom_id)),
("node_id", Value::String(&node.node_id)),
("name", Value::String(&node.name)),
Expand Down

0 comments on commit 494acd5

Please sign in to comment.