use serde_json::{json, Map, Value};
use crate::permission::{filter_writable_data, Context};
use crate::schema::Schema;
use crate::types::is_truthy;
mod many;
mod single;
mod upsert;
pub use many::{plan_insert_many, plan_update_many};
pub use single::{plan_archive_docs, plan_remove, plan_update};
pub use upsert::plan_upsert;
pub(in crate::command) use upsert::{
build_upsert_conditions, build_upsert_update, upsert_one_update,
};
pub(in crate::command) struct IdCursor<'a> {
ids: &'a [String],
pos: usize,
}
impl<'a> IdCursor<'a> {
pub(in crate::command) fn new(ids: &'a [String]) -> Self {
Self { ids, pos: 0 }
}
pub(in crate::command) fn next(&mut self) -> Result<&'a str, String> {
let id = self
.ids
.get(self.pos)
.ok_or_else(|| "Host 供给的 newId 数量不足".to_string())?;
self.pos += 1;
Ok(id)
}
}
pub(in crate::command) fn needs_new_id(schema: &Schema, data: &Value) -> bool {
!data.get("_id").map(is_truthy).unwrap_or(false) && !schema.id_prefix.is_empty()
}
pub(in crate::command) fn is_blank_condition(v: &Value) -> bool {
match v {
Value::Null => true,
Value::Array(a) => a.is_empty(),
Value::Object(o) if o.is_empty() => true,
Value::Object(o) => {
!o.iter().any(|(_, v)| match v {
Value::Array(a) => !a.is_empty(),
_ => true,
})
}
_ => false,
}
}
pub(in crate::command) fn remove_undefined(obj: &Value) -> Value {
match obj.as_object() {
Some(o) => Value::Object(
o.iter()
.filter(|(_, v)| !v.is_null())
.map(|(k, v)| (k.clone(), v.clone()))
.collect(),
),
None => obj.clone(),
}
}
pub(in crate::command) fn has_trim_str(v: &Value) -> bool {
is_truthy(v)
&& match v {
Value::String(s) => !s.trim().is_empty(),
_ => true,
}
}
pub(in crate::command) fn object_of(v: &Value) -> Map<String, Value> {
v.as_object().cloned().unwrap_or_default()
}
fn has_raw_operators(data: &Value) -> bool {
data.as_object()
.map(|o| o.keys().any(|k| k.starts_with('$')))
.unwrap_or(false)
}
fn find_one_and_update_options(options: &Value) -> Value {
let mut m = Map::new();
m.insert("returnDocument".to_string(), json!("after"));
if let Some(o) = options.as_object() {
for (k, v) in o {
m.insert(k.clone(), v.clone());
}
}
Value::Object(m)
}
fn build_raw_update(schema: &Schema, ctx: Option<&Context>, data: &Value, now: i64) -> Value {
let mut data = data.clone();
if ctx.is_some() {
if let Some(set_part) = data.get("$set").filter(|v| !v.is_null()).cloned() {
let filtered = filter_writable_data(schema, ctx, &set_part);
data["$set"] = remove_undefined(&filtered);
}
}
if schema.timestamps {
let set_part = data.get("$set").cloned().unwrap_or_else(|| json!({}));
let mut merged = object_of(&set_part);
merged.insert("updatedAt".to_string(), json!(now));
data["$set"] = Value::Object(merged);
}
data
}
fn build_set_data(schema: &Schema, ctx: Option<&Context>, data: &Value) -> Map<String, Value> {
let src = match ctx {
Some(_) => filter_writable_data(schema, ctx, data),
None => data.clone(),
};
let mut set_data = object_of(&remove_undefined(&src));
set_data.remove("_id");
set_data
}