I'm looking to get my feet wet in Rust by working on a small service that's returning some data, based on some sorting and filter options, that are passed in as a json structure.
Given a Vector data
and this rather simple json example
{
"filters": {
"year": {
"$and": [{
"$gte": 1990
}, {
"$lte": 2000
}]
}
}
}
I'm looking to generate this closure in the filter function:
data.iter().filter(|m| m.year >= gte && m.year <= lte)
To handle the json data, I'm looking to use the serde_json crate. But in regards to actually creating that filter, I'm a little lost on how to best approach this. I will expect nested filters, and the usual ors, nots, eqs, and so on...
While I did come up with a solution and would like to politely request a code review, I'm still looking for an overall better approach on how to handle this type of challenge.
I don't have a stackexchange account, so posting it here.
I have rewitten construct_filter
and one_point_of_success
a bit:
impl RecsysObject {
fn construct_filter(&self, movie: &Media) -> bool {
if self.filters.is_none() {
return true;
}
let f = self.filters.clone().unwrap();
if f.get("year").is_none() {
return true;
}
let yf = f.get("year").unwrap();
if let Some(year) = yf.eq {
return movie.year == year;
}
if yf.and.is_none() {
return true;
}
let rangefilter = yf.and.clone().unwrap();
for rf in rangefilter {
match rf {
LogicFilter::LT(val) if movie.year >= val {
return false;
}
LogicFilter::GT(val) => if movie.year <= val {
return false;
}
_ => {}
}
}
true
}
}
#[post("/", data = "<object>")]
fn one_point_of_success(allmovies: State<Vec<Media>>, object: JSON<RecsysObject>) -> JSON<Value> {
let mut results = allmovies
.iter()
.filter(|m| object.construct_filter(m))
.collect::<Vec<_>>();
if let Some(v) = object.sort.clone() {
if let Some(hmap) = v.get(0) {
match hmap.get("property") {
None => {
if hmap.get("type").unwrap() == "popularity" {
match hmap.get("order") {
Some(order) => {
if order == "ascending" {
results.sort_by(|a, b| a.rating.cmp(&b.rating));
}
}
_ => {} // already sorted
}
}
}
_ => {
if hmap.get("property").unwrap() == "metadata.releaseDate" {
match hmap.get("order") {
Some(order) => {
if order == "ascending" {
results.sort_by(|a, b| a.year.cmp(&b.year));
} else {
results.sort_by(|a, b| b.year.cmp(&a.year));
}
}
_ => {
results.sort_by(|a, b| b.year.cmp(&a.year));
}
}
}
}
}
}
}
JSON(json!(results.iter().skip(object.page.unwrap_or(0) * object.page_size.unwrap_or(10)) // first page is page 0
.take(object.page_size.unwrap_or(10)).collect::<Vec<_>>()))
}
1 Like
Thank you for improving the readability. While the construct_filter is now a lot cleaner, I've noticed a significant drop in performance.