moon_zod/core/pipe.mbt

60 lines
1.6 KiB
Plaintext

///|
/// Chain two schemas: validate the input against `self`, then validate the
/// result against `output`. Errors from each stage are reported independently.
///
/// Unlike `.transform()`, `.pipe()` creates a clear two-stage pipeline where
/// the output schema can have its own rules — errors are attributed to the
/// correct stage.
///
/// # Example
/// ```mbt nocheck
/// let s = string()
/// .transform(fn(s) { Ok(Json::string(s.length().to_string())) })
/// .pipe(number().min(5))
/// // string check → transform → number check(.min(5))
/// ```
pub fn Schema::pipe(self : Schema, output : Schema) -> Schema {
{
schema_type: PipeType(
self,
TransformClosure::{ f: fn(v) { Ok(v) } },
output,
),
rules: [],
description: self.description,
required_error: self.required_error,
invalid_type_error: self.invalid_type_error,
name: self.name,
brand: self.brand,
}
}
///|
pub fn Schema::parse_pipe(
_self : Schema,
input_schema : Schema,
bridge : TransformClosure,
output_schema : Schema,
json : Json,
path_stack : Array[String],
) -> RawSchemaResult {
match parse_inner(input_schema, json, path_stack) {
Err(e) => Err(e)
Ok(parsed) =>
match (bridge.f)(parsed) {
Err(msg) => {
let path = format_path(path_stack)
Err([
RawIssue::{
code: IssueCode::Custom,
path,
message: msg,
input: json,
},
])
}
Ok(bridged) => parse_inner(output_schema, bridged, path_stack)
}
}
}