use serde_json::{json, Value};
use crate::command::cmd::{cmd_insert_many, cmd_update_many};
use crate::command::write::build_insert_doc;
use crate::command::{ensure_context, ERR_NO_BATCH_WRITE, ERR_NO_WRITE};
use crate::computes::{apply_defaults_and_computes, FnRegistry};
use crate::permission::{can_write_schema, Context};
use crate::schema::Registry;
use crate::types::{validate_condition, validate_condition_shape};
use super::{
build_raw_update, build_set_data, has_raw_operators, is_blank_condition, needs_new_id, IdCursor,
};
pub fn plan_insert_many(
schema_name: &str,
registry: &Registry,
ctx: Option<&Context>,
docs: &[Value],
now: i64,
new_ids: &[String],
fn_registry: Option<&dyn FnRegistry>,
) -> Result<Value, String> {
ensure_context(registry, ctx)?;
if docs.is_empty() {
return Ok(json!({ "command": Value::Null, "returns": [] }));
}
let schema = registry.get(schema_name)?;
if !can_write_schema(schema, ctx) {
return Err(ERR_NO_WRITE.to_string());
}
let mut ids = IdCursor::new(new_ids);
let mut processed = Vec::with_capacity(docs.len());
for data in docs {
let new_id = if needs_new_id(schema, data) {
ids.next()?
} else {
""
};
let doc = build_insert_doc(schema, ctx, data, now, new_id)?;
processed.push(Value::Object(doc));
}
let returns = processed
.iter()
.map(|d| apply_defaults_and_computes(d, schema, fn_registry))
.collect::<Result<Vec<_>, _>>()?;
Ok(json!({
"command": cmd_insert_many(schema, &processed),
"returns": returns,
}))
}
pub fn plan_update_many(
schema_name: &str,
registry: &Registry,
ctx: Option<&Context>,
condition: &Value,
data: &Value,
now: i64,
) -> 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(c) = ctx {
let guest = c
.roles
.clone()
.unwrap_or_default()
.iter()
.any(|r| r == "guest");
if guest || !can_write_schema(schema, ctx) {
return Err(ERR_NO_BATCH_WRITE.to_string());
}
}
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 schema.timestamps {
set_data.insert("updatedAt".to_string(), json!(now));
}
json!({ "$set": Value::Object(set_data) })
};
let command = cmd_update_many(schema, condition, &update_doc);
Ok(json!({ "command": command }))
}