Skip to content

Commit

Permalink
Support IN filter (#220)
Browse files Browse the repository at this point in the history
* feat(raiden): support in operator

* fix(raiden): compose query
  • Loading branch information
KentaKudo authored Jul 31, 2023
1 parent 2851aa8 commit 581f264
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 0 deletions.
44 changes: 44 additions & 0 deletions raiden/src/filter_expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub enum FilterExpressionTypes {
super::Placeholder,
super::AttributeValue,
),
In(Vec<(super::Placeholder, super::AttributeValue)>),
BeginsWith(super::Placeholder, super::AttributeValue),
AttributeExists(),
AttributeNotExists(),
Expand Down Expand Up @@ -171,6 +172,21 @@ impl<T> FilterExpressionBuilder<T> for FilterExpressionFilledOrWaitOperator<T> {
attr_values,
)
}
FilterExpressionTypes::In(attributes) => {
let placeholders = attributes
.iter()
.map(|(placeholder, _)| placeholder.clone())
.collect::<Vec<_>>()
.join(",");
for (placeholder, value) in attributes {
attr_values.insert(placeholder, value);
}
(
format!("{} IN ({})", left_cond, placeholders),
attr_names,
attr_values,
)
}
FilterExpressionTypes::BeginsWith(placeholder, value) => {
attr_values.insert(placeholder.to_string(), value);
(
Expand Down Expand Up @@ -259,6 +275,17 @@ impl<T> FilterExpressionBuilder<T> for FilterExpressionFilled<T> {
left_cond, placeholder1, placeholder2
)
}
FilterExpressionTypes::In(attributes) => {
let placeholders = attributes
.iter()
.map(|(placeholder, _)| placeholder.clone())
.collect::<Vec<_>>()
.join(",");
for (placeholder, value) in attributes {
left_values.insert(placeholder, value);
}
format!("{} IN ({})", attr_name, placeholders)
}
FilterExpressionTypes::BeginsWith(placeholder, value) => {
left_values.insert(placeholder.clone(), value);
format!("begins_with(#{}, {})", attr_name, placeholder)
Expand Down Expand Up @@ -378,6 +405,23 @@ impl<T> FilterExpression<T> {
}
}

pub fn r#in(
self,
values: Vec<impl super::IntoAttribute>,
) -> FilterExpressionFilledOrWaitOperator<T> {
let attributes = values.into_iter().map(|value| {
let placeholder = format!(":value{}", super::generate_value_id());
(placeholder, value.into_attr())
});
let cond = FilterExpressionTypes::In(attributes.collect());
FilterExpressionFilledOrWaitOperator {
attr: self.attr,
is_size: self.is_size,
cond,
_token: std::marker::PhantomData,
}
}

// We can use `begins_with` only with a range key after specifying an EQ condition for the primary key.
pub fn begins_with(
self,
Expand Down
18 changes: 18 additions & 0 deletions raiden/tests/all/filter_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,24 @@ mod tests {
assert_eq!(attribute_values, expected_values);
}

#[test]
fn test_in_filter_expression() {
reset_value_id();

let cond = User::filter_expression(User::name()).r#in(vec!["user1", "user2"]);
let (filter_expression, attribute_names, attribute_values) = cond.build();
let mut expected_names: std::collections::HashMap<String, String> =
std::collections::HashMap::new();
expected_names.insert("#name".to_owned(), "name".to_owned());
let mut expected_values: std::collections::HashMap<String, AttributeValue> =
std::collections::HashMap::new();
expected_values.insert(":value0".to_owned(), "user1".into_attr());
expected_values.insert(":value1".to_owned(), "user2".into_attr());
assert_eq!(filter_expression, "#name IN (:value0,:value1)".to_owned());
assert_eq!(attribute_names, expected_names);
assert_eq!(attribute_values, expected_values);
}

#[test]
fn test_begins_with_filter_expression() {
reset_value_id();
Expand Down
19 changes: 19 additions & 0 deletions raiden/tests/all/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,25 @@ mod tests {
assert_eq!(res.items.len(), 2);
}

#[tokio::test]
async fn test_query_in_filter() {
let client = QueryTestData0::client(Region::Custom {
endpoint: "http://localhost:8000".into(),
name: "ap-northeast-1".into(),
});
let cond = QueryTestData0::key_condition(QueryTestData0::id()).eq("id4");
let filter =
QueryTestData0::filter_expression(QueryTestData0::name()).r#in(vec!["bar0", "bar1"]);
let res = client
.query()
.key_condition(cond)
.filter(filter)
.run()
.await
.unwrap();
assert_eq!(res.items.len(), 2);
}

#[derive(Raiden)]
#[raiden(table_name = "LastEvaluateKeyData")]
#[allow(dead_code)]
Expand Down

0 comments on commit 581f264

Please sign in to comment.