use serde_json::{json, Value};
use crate::command::cmd::{cmd_delete_many, cmd_find, cmd_find_one_and_update, cmd_insert_many};
use crate::command::write::{check_write_perm, Probe};
use crate::command::{ensure_context, ERR_NO_BATCH_WRITE, ERR_NO_DELETE, ERR_NO_WRITE};
use crate::permission::Context;
use crate::schema::Registry;
use crate::types::{validate_condition, validate_condition_shape};
use super::{
build_raw_update, build_set_data, find_one_and_update_options, has_raw_operators,
is_blank_condition, object_of,
};
#[allow(clippy::too_many_arguments)]
pub fn plan_update(
schema_name: &str,
registry: &Registry,
ctx: Option<&Context>,
condition: &Value,
data: &Value,
options: &Value,
now: i64,
probe: Probe,
) -> Result<Value, String> {
ensure_context(registry, ctx)?;
let schema = registry.get(schema_name)?;
validate_condition(condition)?;
validate_condition_shape(schema, condition, registry.profile())?;
if let Some(cmd) = check_write_perm(schema, ctx, condition, ERR_NO_WRITE, probe)? {
return Ok(json!({ "needsProbe": cmd }));
}
let update_doc = if has_raw_operators(data) {
build_raw_update(schema, ctx, data, now)
} else {
let mut set_data = build_set_data(schema, ctx, data);
if set_data.is_empty() {
return Err("没有提供要更新的字段".to_string());
}
if schema.timestamps {
set_data.insert("updatedAt".to_string(), json!(now));
}
json!({ "$set": Value::Object(set_data) })
};
let command = cmd_find_one_and_update(
schema,
condition,
&update_doc,
&find_one_and_update_options(options),
);
Ok(json!({ "command": command }))
}
pub fn plan_remove(
schema_name: &str,
registry: &Registry,
ctx: Option<&Context>,
condition: &Value,
probe: Probe,
) -> Result<Value, String> {
ensure_context(registry, ctx)?;
let schema = registry.get(schema_name)?;
validate_condition(condition)?;
validate_condition_shape(schema, condition, registry.profile())?;
if is_blank_condition(condition) {
return Err(ERR_NO_BATCH_WRITE.to_string());
}
if let Some(cmd) = check_write_perm(schema, ctx, condition, ERR_NO_DELETE, probe)? {
return Ok(json!({ "needsProbe": cmd }));
}
let archive_name = format!("{}Deleted", schema_name);
let (archive_collection, find_command) = if registry.has(&archive_name) {
let arch = registry.get(&archive_name)?;
(
json!(arch.collection),
Some(cmd_find(schema, condition, None)),
)
} else {
(Value::Null, None)
};
let delete_command = cmd_delete_many(schema, condition);
Ok(json!({
"archiveCollection": archive_collection,
"findCommand": find_command,
"deleteCommand": delete_command,
}))
}
pub fn plan_archive_docs(
schema_name: &str,
registry: &Registry,
docs: &[Value],
now: i64,
) -> Result<Value, String> {
let archive_name = format!("{}Deleted", schema_name);
let arch = registry.get(&archive_name)?;
let archived: Vec<Value> = docs
.iter()
.map(|d| {
let mut o = object_of(d);
o.insert("deletedAt".to_string(), json!(now));
Value::Object(o)
})
.collect();
let mut command = cmd_insert_many(arch, &archived);
if let Some(obj) = command.as_object_mut() {
obj.insert("upsertById".to_string(), json!(true));
}
Ok(json!({ "command": command }))
}