mod filter;
mod log;
mod map;
#[cfg(test)]
pub(crate) mod one_task;
mod parse;
mod paths;
mod publish;
mod validation;
mod xml;
pub(crate) use filter::FilterConfig;
pub(crate) use log::LogConfig;
pub(crate) use map::MapConfig;
pub(crate) use parse::ParseConfig;
pub(crate) use publish::PublishConfig;
pub(crate) use validation::ValidationConfig;
use crate::base::Result;
use crate::expr::{CompileCx, ExprVisitor, FieldSpec};
use crate::function::{FunctionConfig, FunctionSpec, Outcome, SyncCtx};
use serde_json::Value;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum BuiltinKind {
Map,
Validation,
Filter,
Log,
ParseJson,
ParseXml,
PublishJson,
PublishXml,
}
impl BuiltinKind {
pub(crate) const ALL: [Self; 8] = [
Self::Map,
Self::Validation,
Self::Filter,
Self::Log,
Self::ParseJson,
Self::ParseXml,
Self::PublishJson,
Self::PublishXml,
];
pub(crate) fn from_name(name: &str) -> Option<Self> {
Self::ALL.into_iter().find(|kind| kind.name() == name)
}
pub(crate) fn name(self) -> &'static str {
crate::def::BUILTIN_FUNCTIONS[self as usize]
}
pub(crate) fn spec(self) -> FunctionSpec {
let (category, description) = match self {
Self::Map => (
"transform",
"Writes the results of JSONLogic to context paths, or removes them.",
),
Self::Validation => (
"validate",
"Checks rules against the message and records an error for each that fails.",
),
Self::Filter => (
"control",
"Halts the workflow, or skips the task, when its condition is not met.",
),
Self::Log => (
"observe",
"Emits a log line, with structured fields, at a chosen level.",
),
Self::ParseJson => (
"parse",
"Reads a JSON value from the payload or the context into `data`.",
),
Self::ParseXml => (
"parse",
"Parses an XML string from the payload or the context into `data`.",
),
Self::PublishJson => (
"publish",
"Serializes a value under `data` to a JSON string under `data`.",
),
Self::PublishXml => (
"publish",
"Serializes a value under `data` to an XML string under `data`.",
),
};
FunctionSpec::default()
.with_category(category)
.with_description(description)
}
pub(crate) fn fields(self) -> &'static [FieldSpec] {
match self {
Self::Map => MapConfig::fields(),
Self::Validation => ValidationConfig::fields(),
Self::Filter => FilterConfig::fields(),
Self::Log => LogConfig::fields(),
Self::ParseJson | Self::ParseXml => ParseConfig::fields(),
Self::PublishJson | Self::PublishXml => PublishConfig::fields(),
}
}
pub(crate) fn compile(self, input: &Value, cx: &mut CompileCx<'_>) -> Option<Builtin> {
match self {
Self::Map => MapConfig::compile(input, cx).map(Builtin::Map),
Self::Validation => ValidationConfig::compile(input, cx).map(Builtin::Validation),
Self::Filter => FilterConfig::compile(input, cx).map(|c| Builtin::Filter(c.into())),
Self::Log => LogConfig::compile(input, cx).map(|c| Builtin::Log(c.into())),
Self::ParseJson => {
ParseConfig::compile(input, cx).map(|c| Builtin::ParseJson(c.into()))
}
Self::ParseXml => ParseConfig::compile(input, cx).map(|c| Builtin::ParseXml(c.into())),
Self::PublishJson => {
PublishConfig::compile_for(input, false, cx).map(|c| Builtin::PublishJson(c.into()))
}
Self::PublishXml => {
PublishConfig::compile_for(input, true, cx).map(|c| Builtin::PublishXml(c.into()))
}
}
}
}
#[derive(Debug)]
pub(crate) enum Builtin {
Map(MapConfig),
Validation(ValidationConfig),
Filter(Box<FilterConfig>),
Log(Box<LogConfig>),
ParseJson(Box<ParseConfig>),
ParseXml(Box<ParseConfig>),
PublishJson(Box<PublishConfig>),
PublishXml(Box<PublishConfig>),
#[cfg(test)]
Fault,
}
impl Builtin {
#[cfg(test)]
pub(crate) fn kind(&self) -> BuiltinKind {
match self {
Self::Map(_) | Self::Fault => BuiltinKind::Map,
Self::Validation(_) => BuiltinKind::Validation,
Self::Filter(_) => BuiltinKind::Filter,
Self::Log(_) => BuiltinKind::Log,
Self::ParseJson(_) => BuiltinKind::ParseJson,
Self::ParseXml(_) => BuiltinKind::ParseXml,
Self::PublishJson(_) => BuiltinKind::PublishJson,
Self::PublishXml(_) => BuiltinKind::PublishXml,
}
}
pub(crate) fn call<'p>(&'p self, cx: &mut SyncCtx<'_, '_, 'p>) -> Result<Outcome> {
match self {
Self::Map(c) => c.call(cx),
Self::Validation(c) => c.call(cx),
Self::Filter(c) => c.call(cx),
Self::Log(c) => c.call(cx),
Self::ParseJson(c) => c.json(cx),
Self::ParseXml(c) => c.xml(cx),
Self::PublishJson(c) => c.json(cx),
Self::PublishXml(c) => c.xml(cx),
#[cfg(test)]
Self::Fault => {
let target: crate::expr::Path = "data.a".parse().expect("a path");
cx.write(&target, datavalue::OwnedDataValue::from_i64(1), None);
Err(crate::Error::service("BROKE", "after its writes"))
}
}
}
pub(crate) fn visit(&self, v: &mut dyn ExprVisitor) {
match self {
Self::Map(c) => c.visit(v),
Self::Validation(c) => c.visit(v),
Self::Filter(c) => c.visit(v),
Self::Log(c) => c.visit(v),
Self::ParseJson(c) | Self::ParseXml(c) => c.visit(v),
Self::PublishJson(c) | Self::PublishXml(c) => c.visit(v),
#[cfg(test)]
Self::Fault => {}
}
}
}
#[cfg(test)]
mod tests;