mdmodels_core/json/
validation.rs1use std::error::Error;
25use std::path::PathBuf;
26
27use colored::Colorize;
28use jsonschema::error::ValidationErrorKind;
29use serde_json::Value;
30use std::convert::TryFrom;
31
32use crate::datamodel::DataModel;
33use jsonschema::validator_for;
34
35#[derive(Debug)]
37pub struct ValidationError {
38 pub instance_path: String,
39 pub schema_path: String,
40 pub message: String,
41 pub kind: ValidationErrorKind,
42}
43
44impl std::fmt::Display for ValidationError {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 write!(
47 f,
48 "Validation Error: Instance {} violates schema at {}: {}",
49 self.instance_path.red().bold(),
50 self.schema_path.green().bold(),
51 self.message.yellow().bold()
52 )
53 }
54}
55
56impl From<jsonschema::ValidationError<'_>> for ValidationError {
57 fn from(err: jsonschema::ValidationError) -> Self {
58 ValidationError {
59 instance_path: err.instance_path.to_string(),
60 schema_path: err.schema_path.to_string(),
61 message: err.to_string(),
62 kind: err.kind,
63 }
64 }
65}
66
67pub fn validate_json<T: Into<DatasetInput>>(
79 dataset: T,
80 model: &DataModel,
81 root: Option<String>,
82) -> Result<Vec<ValidationError>, Box<dyn Error>> {
83 let dataset_input: DatasetInput = dataset.into();
85 let value: Value = dataset_input.try_into()?;
86
87 let schema = model.json_schema(root, false)?;
89 let schema_value: Value = serde_json::from_str(&schema)?;
90
91 let validator = validator_for(&schema_value)?;
93
94 let result = validator.iter_errors(&value);
96 let mut errors: Vec<ValidationError> = Vec::new();
97
98 for err in result {
99 errors.push(ValidationError::from(err));
100 }
101
102 Ok(errors)
103}
104
105pub enum DatasetInput {
107 Path(PathBuf),
108 Value(Value),
109 String(String),
110}
111
112impl From<PathBuf> for DatasetInput {
113 fn from(path: PathBuf) -> Self {
115 DatasetInput::Path(path)
116 }
117}
118
119impl From<Value> for DatasetInput {
120 fn from(value: Value) -> Self {
122 DatasetInput::Value(value)
123 }
124}
125
126impl From<&mut Value> for DatasetInput {
127 fn from(value: &mut Value) -> Self {
129 DatasetInput::Value(value.clone())
130 }
131}
132
133impl From<String> for DatasetInput {
134 fn from(string: String) -> Self {
136 DatasetInput::String(string)
137 }
138}
139
140impl TryFrom<DatasetInput> for Value {
141 type Error = Box<dyn Error>;
142
143 fn try_from(input: DatasetInput) -> Result<Self, Self::Error> {
144 match input {
145 DatasetInput::Path(path) => {
146 let content = std::fs::read_to_string(path)?;
148 let value: Value = serde_json::from_str(&content)?;
149 Ok(value)
150 }
151 DatasetInput::Value(value) => Ok(value),
152 DatasetInput::String(string) => {
153 let value: Value = serde_json::from_str(&string)?;
154 Ok(value)
155 }
156 }
157 }
158}