fix(mongodb): support legacy update commands

This commit is contained in:
t8y2 committed 2026-07-31 21:41:09 +08:00
1 parent 89133a22d5
commit ee26b2a580
2 files changed
+110 -19

No files matched your search

+26 -19
View File
@@ -1230,16 +1230,22 @@ pub async fn update_documents(
serde_json::from_str(update_json).map_err(|e| format!("Invalid update JSON: {e}"))?;
let filter = json_filter_to_document(&filter_value).map_err(|e| format!("Invalid filter: {e}"))?;
let update = json_update_to_modifications(&update_value).map_err(|e| format!("Invalid update: {e}"))?;
let array_filters = parse_update_array_filters(options_json)?;
let ParsedMongoUpdateOptions { upsert, array_filters } = parse_update_options(options_json)?;
let col = client.database(database).collection::<Document>(collection);
let result = if many {
let mut action = col.update_many(filter, update);
if let Some(upsert) = upsert {
action = action.upsert(upsert);
}
if let Some(filters) = array_filters {
action = action.array_filters(filters);
}
action.await.map_err(|e| e.to_string())?
} else {
let mut action = col.update_one(filter, update);
if let Some(upsert) = upsert {
action = action.upsert(upsert);
}
if let Some(filters) = array_filters {
action = action.array_filters(filters);
}
@@ -1249,17 +1255,24 @@ pub async fn update_documents(
}
#[derive(Default, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[serde(rename_all = "camelCase")]
struct MongoUpdateOptions {
upsert: Option<bool>,
array_filters: Option<Vec<serde_json::Value>>,
}
fn parse_update_array_filters(options_json: Option<&str>) -> Result<Option<Vec<Document>>, String> {
#[derive(Debug, Default)]
struct ParsedMongoUpdateOptions {
upsert: Option<bool>,
array_filters: Option<Vec<Document>>,
}
fn parse_update_options(options_json: Option<&str>) -> Result<ParsedMongoUpdateOptions, String> {
let Some(raw) = options_json.filter(|value| !value.trim().is_empty()) else {
return Ok(None);
return Ok(ParsedMongoUpdateOptions::default());
};
let options: MongoUpdateOptions = serde_json::from_str(raw).map_err(|e| format!("Invalid update options: {e}"))?;
options
let array_filters = options
.array_filters
.map(|filters| {
filters
@@ -1268,7 +1281,8 @@ fn parse_update_array_filters(options_json: Option<&str>) -> Result<Option<Vec<D
.collect::<Result<Vec<_>, _>>()
.map_err(|e| format!("Invalid arrayFilters: {e}"))
})
.transpose()
.transpose()?;
Ok(ParsedMongoUpdateOptions { upsert: options.upsert, array_filters })
}
#[derive(Debug, Default, Deserialize)]
@@ -2021,20 +2035,13 @@ mod tests {
}
#[test]
fn update_options_parse_array_filters() {
let filters = parse_update_array_filters(Some(r#"{"arrayFilters":[{"item.id":322678},{"item.active":true}]}"#))
.unwrap()
.unwrap();
fn update_options_parse_upsert_and_array_filters() {
let options =
parse_update_options(Some(r#"{"upsert":true,"arrayFilters":[{"item.id":322678},{"item.active":true}]}"#))
.unwrap();
assert_eq!(filters, vec![doc! { "item.id": 322678_i64 }, doc! { "item.active": true }]);
}
#[test]
fn update_options_reject_unsupported_fields() {
let error = parse_update_array_filters(Some(r#"{"upsert":true}"#)).unwrap_err();
assert!(error.starts_with("Invalid update options:"));
assert!(error.contains("unknown field `upsert`"));
assert_eq!(options.upsert, Some(true));
assert_eq!(options.array_filters.unwrap(), vec![doc! { "item.id": 322678_i64 }, doc! { "item.active": true }]);
}
#[test]