use serde_json::{json, Value};
use stillwater::Validation;
use crate::error::{SchemaError, SchemaErrors};
use crate::interop::ToJsonSchema;
use crate::path::JsonPath;
use crate::schema::SchemaLike;
use crate::validation::ValidationContext;
pub struct RefSchema {
name: String,
}
impl RefSchema {
pub fn new(name: impl Into<String>) -> Self {
Self { name: name.into() }
}
pub fn name(&self) -> &str {
&self.name
}
}
impl SchemaLike for RefSchema {
type Output = Value;
fn validate(&self, _value: &Value, path: &JsonPath) -> Validation<Value, SchemaErrors> {
Validation::Failure(SchemaErrors::single(
SchemaError::new(
path.clone(),
format!(
"reference to '{}' cannot be validated without a registry. \
Use SchemaRegistry::validate() instead",
self.name
),
)
.with_code("missing_registry"),
))
}
fn validate_to_value(&self, value: &Value, path: &JsonPath) -> Validation<Value, SchemaErrors> {
self.validate(value, path)
}
fn validate_with_context(
&self,
value: &Value,
path: &JsonPath,
context: &ValidationContext,
) -> Validation<Value, SchemaErrors> {
if context.depth() >= context.max_depth() {
return Validation::Failure(SchemaErrors::single(
SchemaError::new(
path.clone(),
format!(
"maximum reference depth {} exceeded at path '{}'",
context.max_depth(),
path
),
)
.with_code("max_depth_exceeded"),
));
}
let schema = match context.registry().get_schema(&self.name) {
Some(s) => s,
None => {
return Validation::Failure(SchemaErrors::single(
SchemaError::new(
path.clone(),
format!("schema '{}' not found in registry", self.name),
)
.with_code("missing_reference"),
))
}
};
schema.validate_value_with_context(value, path, &context.increment_depth())
}
fn validate_to_value_with_context(
&self,
value: &Value,
path: &JsonPath,
context: &ValidationContext,
) -> Validation<Value, SchemaErrors> {
self.validate_with_context(value, path, context)
}
fn collect_refs(&self, refs: &mut Vec<String>) {
refs.push(self.name.clone());
}
}
impl ToJsonSchema for RefSchema {
fn to_json_schema(&self) -> Value {
json!({
"$ref": format!("#/$defs/{}", self.name)
})
}
}