mod cmd;
mod count;
mod finalize;
mod mutate;
mod mutation;
mod query;
mod triggers;
mod write;
mod write_links;
use crate::permission::Context;
use crate::schema::{Profile, Registry};
pub use cmd::{
apply_route_override, cmd_aggregate, cmd_count_documents, cmd_delete_many, cmd_find,
cmd_find_one, cmd_find_one_and_update, cmd_insert_many, cmd_insert_one, cmd_update_many,
};
pub use count::{plan_query_with_count, CountQueryPlan};
pub use finalize::{finalize_query, prepare_query, strip_query};
pub use mutate::{
plan_archive_docs, plan_insert_many, plan_remove, plan_update, plan_update_many, plan_upsert,
};
pub use mutation::plan_mutation;
pub use query::{
build_plan, check_readable_relations, has_pipeline, plan_query, plan_query_ast_mut,
plan_query_mut, plan_query_one, resolve_page, restore_sort_order, sorts_by_relation, Mode,
Page, QueryPlan,
};
pub use triggers::{before_probe_fields, expand_schedule_triggers, expand_triggers, has_triggers};
pub use write::{check_write_perm, plan_count, plan_exists, plan_insert, Probe};
pub use write_links::{
err_write_cross_source, resolve_write_links, WriteLinkPolicy, WriteLinks,
ERR_WRITE_CROSS_SOURCE_PREFIX,
};
pub const ERR_PERM_PREFIX: &str = "ERR_PERMISSION:";
pub const ERR_PERMISSION: &str = "ERR_PERMISSION:无访问权限";
pub const ERR_NO_WRITE: &str = "ERR_PERMISSION:无写入权限";
pub const ERR_NO_DELETE: &str = "ERR_PERMISSION:无删除权限";
pub const ERR_NO_BATCH_WRITE: &str = "ERR_PERMISSION:无批量写入权限";
pub const ERR_NO_CONTEXT: &str =
"ERR_NO_CONTEXT:require_context 已开启,调用必须携带用户上下文(内部调用请传 {\"internal\": true})";
pub fn ensure_context(registry: &Registry, ctx: Option<&Context>) -> Result<(), String> {
if registry.require_context() && ctx.is_none() {
return Err(ERR_NO_CONTEXT.to_string());
}
ensure_profile_ctx(registry, ctx)
}
pub const ERR_TEXT2QUERY: &str = "ERR_TEXT2QUERY:";
pub const T2Q_MAX_ROWS: f64 = 1000.0;
pub const T2Q_MAX_DEPTH: usize = 3;
pub const T2Q_MAX_FEDERATION_ROWS: usize = 10_000;
pub fn ensure_profile_ctx(registry: &Registry, ctx: Option<&Context>) -> Result<(), String> {
if registry.profile() == Profile::Text2Query && ctx.is_none() {
return Err(format!("{ERR_TEXT2QUERY}text2query 档必须携带用户上下文"));
}
Ok(())
}
pub fn forbid_t2q(registry: &Registry, feature: &str) -> Result<(), String> {
if registry.profile() == Profile::Text2Query {
return Err(format!(
"{ERR_TEXT2QUERY}text2query 档禁用 [{feature}](功能收缩)"
));
}
Ok(())
}
pub fn forbid_t2q_shape(profile: Profile, feature: &str, detail: String) -> Result<(), String> {
if profile == Profile::Text2Query {
return Err(format!(
"{ERR_TEXT2QUERY}text2query 档功能收缩 [{feature}]:{detail}"
));
}
Ok(())
}
pub fn ensure_route_override_allowed(registry: &Registry, present: bool) -> Result<(), String> {
if present && registry.profile() == Profile::Text2Query {
return Err(format!(
"{ERR_TEXT2QUERY}text2query 档禁用 route_override(受信参数,禁 AI 侧指定)"
));
}
Ok(())
}
pub const PHASE1_IDS: &str = "{{phase1.ids}}";
pub fn step_id_placeholder(idx: usize) -> String {
format!("{{{{step.{}._id}}}}", idx)
}
pub const MAX_PAGE_SIZE: f64 = 5000.0;