feat(mongo): preserve BSON types when cloning and saving documents
This commit is contained in:
12 files changed
+239
-36
No files matched your search
@@ -1651,6 +1651,21 @@ pub async fn insert_document(
|
||||
Ok(format!("{}", result.inserted_id))
|
||||
}
|
||||
|
||||
/// Inserts a document from canonical Extended JSON without interpreting
|
||||
/// Mongo shell-like strings such as `ISODate(...)`.
|
||||
pub async fn insert_document_extended_json(
|
||||
client: &Client,
|
||||
database: &str,
|
||||
collection: &str,
|
||||
doc_json: &str,
|
||||
) -> Result<String, String> {
|
||||
let value: serde_json::Value = serde_json::from_str(doc_json).map_err(|e| format!("Invalid JSON: {e}"))?;
|
||||
let doc = json_object_to_document_extended_json(&value).map_err(|e| format!("Invalid document: {e}"))?;
|
||||
let col = client.database(database).collection::<Document>(collection);
|
||||
let result = col.insert_one(doc).await.map_err(|e| e.to_string())?;
|
||||
Ok(format!("{}", result.inserted_id))
|
||||
}
|
||||
|
||||
pub async fn insert_documents(
|
||||
client: &Client,
|
||||
database: &str,
|
||||
@@ -3492,6 +3507,21 @@ mod tests {
|
||||
assert!(matches!(doc.get("count"), Some(Bson::Int64(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_object_to_document_extended_json_keeps_shell_date_strings_literal() {
|
||||
let value = serde_json::json!({
|
||||
"date_text": "ISODate(\"2026-08-10T00:00:00.000Z\")",
|
||||
"actual_date": { "$date": "2026-08-10T00:00:00.000Z" },
|
||||
});
|
||||
let doc = json_object_to_document_extended_json(&value).unwrap();
|
||||
|
||||
assert!(matches!(
|
||||
doc.get("date_text"),
|
||||
Some(Bson::String(value)) if value == "ISODate(\"2026-08-10T00:00:00.000Z\")"
|
||||
));
|
||||
assert!(matches!(doc.get("actual_date"), Some(Bson::DateTime(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gridfs_file_id_accepts_extended_json_object_id() {
|
||||
let id = parse_gridfs_file_id(r#"{"$oid":"507f1f77bcf86cd799439011"}"#).unwrap();
|
||||
|
||||
@@ -524,6 +524,27 @@ pub async fn insert_document_core(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn insert_document_preserving_bson_types_core(
|
||||
state: &AppState,
|
||||
connection_id: &str,
|
||||
database: &str,
|
||||
collection: &str,
|
||||
doc_json: &str,
|
||||
routing: Option<&str>,
|
||||
) -> Result<String, String> {
|
||||
ensure_document_pool(state, connection_id).await?;
|
||||
let connections = state.connections.read().await;
|
||||
match connections.get(connection_id).ok_or("Not found")? {
|
||||
PoolKind::MongoDb(client) => {
|
||||
mongo_driver::insert_document_extended_json(client, database, collection, doc_json).await
|
||||
}
|
||||
_ => {
|
||||
drop(connections);
|
||||
insert_document_core(state, connection_id, database, collection, doc_json, routing).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_document_core(
|
||||
state: &AppState,
|
||||
connection_id: &str,
|
||||
|
||||
@@ -87,6 +87,7 @@ pub struct DocumentInsertRequest {
|
||||
pub collection: String,
|
||||
pub doc_json: String,
|
||||
pub routing: Option<String>,
|
||||
pub preserve_bson_types: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -222,15 +223,27 @@ pub async fn insert_document(
|
||||
Json(req): Json<DocumentInsertRequest>,
|
||||
) -> Result<Json<String>, AppError> {
|
||||
ensure_writable(&state.app, &req.connection_id, "Insert").await?;
|
||||
let result = dbx_core::document_ops::insert_document_core(
|
||||
&state.app,
|
||||
&req.connection_id,
|
||||
&req.database,
|
||||
&req.collection,
|
||||
&req.doc_json,
|
||||
req.routing.as_deref(),
|
||||
)
|
||||
.await
|
||||
let result = if req.preserve_bson_types.unwrap_or(false) {
|
||||
dbx_core::document_ops::insert_document_preserving_bson_types_core(
|
||||
&state.app,
|
||||
&req.connection_id,
|
||||
&req.database,
|
||||
&req.collection,
|
||||
&req.doc_json,
|
||||
req.routing.as_deref(),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
dbx_core::document_ops::insert_document_core(
|
||||
&state.app,
|
||||
&req.connection_id,
|
||||
&req.database,
|
||||
&req.collection,
|
||||
&req.doc_json,
|
||||
req.routing.as_deref(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
.map_err(AppError::from)?;
|
||||
Ok(Json(result))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user