Allow making a schema to fail by returning an Err
This commit is contained in:
parent
2aa1835240
commit
51ed13218c
8 changed files with 149 additions and 99 deletions
26
schemars/src/error.rs
Normal file
26
schemars/src/error.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use std::fmt;
|
||||||
|
use std::error::Error;
|
||||||
|
use crate::schema::Schema;
|
||||||
|
|
||||||
|
pub type Result<T = Schema> = std::result::Result<T, MakeSchemaError>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MakeSchemaError {
|
||||||
|
msg: &'static str,
|
||||||
|
schema: Schema
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MakeSchemaError {
|
||||||
|
pub fn new(msg: &'static str, schema: Schema) -> MakeSchemaError {
|
||||||
|
MakeSchemaError { msg, schema }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for MakeSchemaError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{} Schema: {:?}", self.msg, self.schema)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for MakeSchemaError {
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::make_schema::{MakeSchema, SchemaTypeId};
|
use crate::make_schema::{MakeSchema, SchemaTypeId};
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
|
use crate::{MakeSchemaError, Result};
|
||||||
use std::collections::BTreeMap as Map;
|
use std::collections::BTreeMap as Map;
|
||||||
use std::collections::BTreeSet as Set;
|
use std::collections::BTreeSet as Set;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
@ -88,7 +89,7 @@ impl SchemaGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subschema_for<T: ?Sized + MakeSchema>(&mut self) -> Schema {
|
pub fn subschema_for<T: ?Sized + MakeSchema>(&mut self) -> Result {
|
||||||
if !T::is_referenceable() {
|
if !T::is_referenceable() {
|
||||||
return T::make_schema(self);
|
return T::make_schema(self);
|
||||||
}
|
}
|
||||||
|
@ -97,30 +98,40 @@ impl SchemaGenerator {
|
||||||
let name = self
|
let name = self
|
||||||
.definitions
|
.definitions
|
||||||
.get(&type_id)
|
.get(&type_id)
|
||||||
.map(|(n, _)| n.clone())
|
.map(|(n, _)| Ok(n.clone()))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
let name = self.make_unique_name::<T>();
|
let name = self.make_unique_name::<T>();
|
||||||
self.insert_new_subschema_for::<T>(type_id, name.clone());
|
self.insert_new_subschema_for::<T>(type_id, name.clone())?;
|
||||||
name
|
Ok(name)
|
||||||
});
|
})?;
|
||||||
let reference = format!("{}{}", self.settings().definitions_path, name);
|
let reference = format!("{}{}", self.settings().definitions_path, name);
|
||||||
SchemaRef { reference }.into()
|
Ok(SchemaRef { reference }.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_new_subschema_for<T: ?Sized + MakeSchema>(
|
fn insert_new_subschema_for<T: ?Sized + MakeSchema>(
|
||||||
&mut self,
|
&mut self,
|
||||||
type_id: SchemaTypeId,
|
type_id: SchemaTypeId,
|
||||||
name: String,
|
name: String,
|
||||||
) {
|
) -> Result<String> {
|
||||||
self.names.insert(name.clone());
|
self.names.insert(name.clone());
|
||||||
let dummy = Schema::Bool(false);
|
let dummy = Schema::Bool(false);
|
||||||
// insert into definitions BEFORE calling make_schema to avoid infinite recursion
|
// insert into definitions BEFORE calling make_schema to avoid infinite recursion
|
||||||
self.definitions.insert(type_id.clone(), (name, dummy));
|
|
||||||
|
|
||||||
let schema = T::make_schema(self);
|
|
||||||
self.definitions
|
self.definitions
|
||||||
.entry(type_id)
|
.insert(type_id.clone(), (name.clone(), dummy));
|
||||||
.and_modify(|(_, s)| *s = schema);
|
|
||||||
|
match T::make_schema(self) {
|
||||||
|
Ok(schema) => {
|
||||||
|
self.definitions
|
||||||
|
.entry(type_id)
|
||||||
|
.and_modify(|(_, s)| *s = schema);
|
||||||
|
Ok(name)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
self.names.remove(&name);
|
||||||
|
self.definitions.remove(&type_id);
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn definitions(&self) -> Map<String, Schema> {
|
pub fn definitions(&self) -> Map<String, Schema> {
|
||||||
|
@ -131,52 +142,64 @@ impl SchemaGenerator {
|
||||||
Map::from_iter(self.definitions.into_iter().map(|(_, v)| v))
|
Map::from_iter(self.definitions.into_iter().map(|(_, v)| v))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_schema_for<T: ?Sized + MakeSchema>(&mut self) -> Schema {
|
pub fn root_schema_for<T: ?Sized + MakeSchema>(&mut self) -> Result {
|
||||||
let schema = T::make_schema(self);
|
let schema = T::make_schema(self)?;
|
||||||
if let Schema::Object(mut o) = schema {
|
Ok(match schema {
|
||||||
o.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
|
Schema::Object(mut o) => {
|
||||||
o.title = Some(T::schema_name());
|
o.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
|
||||||
o.definitions.extend(self.definitions());
|
o.title = Some(T::schema_name());
|
||||||
return Schema::Object(o);
|
o.definitions.extend(self.definitions());
|
||||||
}
|
Schema::Object(o)
|
||||||
schema
|
}
|
||||||
|
schema => schema,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_root_schema_for<T: ?Sized + MakeSchema>(mut self) -> Schema {
|
pub fn into_root_schema_for<T: ?Sized + MakeSchema>(mut self) -> Result {
|
||||||
let schema = T::make_schema(&mut self);
|
let schema = T::make_schema(&mut self)?;
|
||||||
if let Schema::Object(mut o) = schema {
|
Ok(match schema {
|
||||||
o.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
|
Schema::Object(mut o) => {
|
||||||
o.title = Some(T::schema_name());
|
o.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
|
||||||
o.definitions.extend(self.into_definitions());
|
o.title = Some(T::schema_name());
|
||||||
return Schema::Object(o);
|
o.definitions.extend(self.into_definitions());
|
||||||
}
|
Schema::Object(o)
|
||||||
schema
|
}
|
||||||
|
schema => schema,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn try_get_schema_object<'a>(
|
pub(crate) fn get_schema_object<'a>(&'a self, mut schema: &'a Schema) -> Result<SchemaObject> {
|
||||||
&'a self,
|
|
||||||
mut schema: &'a Schema,
|
|
||||||
) -> Option<SchemaObject> {
|
|
||||||
loop {
|
loop {
|
||||||
match schema {
|
match schema {
|
||||||
Schema::Object(o) => return Some(o.clone()),
|
Schema::Object(o) => return Ok(o.clone()),
|
||||||
Schema::Bool(true) => return Some(Default::default()),
|
Schema::Bool(true) => return Ok(Default::default()),
|
||||||
Schema::Bool(false) => {
|
Schema::Bool(false) => {
|
||||||
return Some(SchemaObject {
|
return Ok(SchemaObject {
|
||||||
not: Some(Schema::Bool(true).into()),
|
not: Some(Schema::Bool(true).into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Schema::Ref(r) => {
|
Schema::Ref(r) => {
|
||||||
let definitions_path_len = self.settings().definitions_path.len();
|
let definitions_path_len = self.settings().definitions_path.len();
|
||||||
let name = r.reference.get(definitions_path_len..)?;
|
let name = r.reference.get(definitions_path_len..).ok_or_else(|| {
|
||||||
|
MakeSchemaError::new(
|
||||||
|
"Could not extract referenced schema name.",
|
||||||
|
Schema::Ref(r.clone()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
// FIXME this is pretty inefficient
|
// FIXME this is pretty inefficient
|
||||||
schema = self
|
schema = self
|
||||||
.definitions
|
.definitions
|
||||||
.values()
|
.values()
|
||||||
.filter(|(n, _)| n == name)
|
.filter(|(n, _)| n == name)
|
||||||
.map(|(_, s)| s)
|
.map(|(_, s)| s)
|
||||||
.next()?;
|
.next()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
MakeSchemaError::new(
|
||||||
|
"Could not find referenced schema.",
|
||||||
|
Schema::Ref(r.clone()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,12 @@ pub mod gen;
|
||||||
pub mod make_schema;
|
pub mod make_schema;
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
|
|
||||||
|
mod error;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
|
pub use error::*;
|
||||||
|
|
||||||
pub use make_schema::MakeSchema;
|
pub use make_schema::MakeSchema;
|
||||||
|
|
||||||
pub use schemars_derive::*;
|
pub use schemars_derive::*;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use schemars::schema_for;
|
use schemars::{schema_for, schema::Schema};
|
||||||
use schemars::schema::Schema;
|
use std::error::Error;
|
||||||
use serde_json::Result;
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let schema = schema_for!(Schema);
|
let schema = schema_for!(Schema)?;
|
||||||
let json = serde_json::to_string_pretty(&schema)?;
|
let json = serde_json::to_string_pretty(&schema)?;
|
||||||
println!("{}", json);
|
println!("{}", json);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::gen::{BoolSchemas, SchemaGenerator};
|
use crate::gen::{BoolSchemas, SchemaGenerator};
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
|
use crate::Result;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::collections::BTreeMap as Map;
|
use std::collections::BTreeMap as Map;
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ pub trait MakeSchema {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema;
|
fn make_schema(gen: &mut SchemaGenerator) -> Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! no_ref_schema {
|
macro_rules! no_ref_schema {
|
||||||
|
@ -52,12 +53,12 @@ macro_rules! simple_impl {
|
||||||
impl MakeSchema for $type {
|
impl MakeSchema for $type {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(_: &mut SchemaGenerator) -> Schema {
|
fn make_schema(_: &mut SchemaGenerator) -> Result {
|
||||||
SchemaObject {
|
Ok(SchemaObject {
|
||||||
instance_type: Some(InstanceType::$instance_type.into()),
|
instance_type: Some(InstanceType::$instance_type.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.into()
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -85,16 +86,16 @@ simple_impl!(() => Null);
|
||||||
impl MakeSchema for char {
|
impl MakeSchema for char {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(_: &mut SchemaGenerator) -> Schema {
|
fn make_schema(_: &mut SchemaGenerator) -> Result {
|
||||||
let mut extensions = Map::new();
|
let mut extensions = Map::new();
|
||||||
extensions.insert("minLength".to_owned(), json!(1));
|
extensions.insert("minLength".to_owned(), json!(1));
|
||||||
extensions.insert("maxLength".to_owned(), json!(1));
|
extensions.insert("maxLength".to_owned(), json!(1));
|
||||||
SchemaObject {
|
Ok(SchemaObject {
|
||||||
instance_type: Some(InstanceType::String.into()),
|
instance_type: Some(InstanceType::String.into()),
|
||||||
extensions,
|
extensions,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.into()
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,15 +105,15 @@ impl MakeSchema for char {
|
||||||
impl<T> MakeSchema for [T; 0] {
|
impl<T> MakeSchema for [T; 0] {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(_: &mut SchemaGenerator) -> Schema {
|
fn make_schema(_: &mut SchemaGenerator) -> Result {
|
||||||
let mut extensions = Map::new();
|
let mut extensions = Map::new();
|
||||||
extensions.insert("maxItems".to_owned(), json!(0));
|
extensions.insert("maxItems".to_owned(), json!(0));
|
||||||
SchemaObject {
|
Ok(SchemaObject {
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
instance_type: Some(InstanceType::Array.into()),
|
||||||
extensions,
|
extensions,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.into()
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,16 +123,16 @@ macro_rules! array_impls {
|
||||||
impl<T: MakeSchema> MakeSchema for [T; $len] {
|
impl<T: MakeSchema> MakeSchema for [T; $len] {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn make_schema(gen: &mut SchemaGenerator) -> Result {
|
||||||
let mut extensions = Map::new();
|
let mut extensions = Map::new();
|
||||||
extensions.insert("minItems".to_owned(), json!($len));
|
extensions.insert("minItems".to_owned(), json!($len));
|
||||||
extensions.insert("maxItems".to_owned(), json!($len));
|
extensions.insert("maxItems".to_owned(), json!($len));
|
||||||
SchemaObject {
|
Ok(SchemaObject {
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
instance_type: Some(InstanceType::Array.into()),
|
||||||
items: Some(gen.subschema_for::<T>().into()),
|
items: Some(gen.subschema_for::<T>()?.into()),
|
||||||
extensions,
|
extensions,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.into()
|
}.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
|
@ -153,19 +154,19 @@ macro_rules! tuple_impls {
|
||||||
impl<$($name: MakeSchema),+> MakeSchema for ($($name,)+) {
|
impl<$($name: MakeSchema),+> MakeSchema for ($($name,)+) {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn make_schema(gen: &mut SchemaGenerator) -> Result {
|
||||||
let mut extensions = Map::new();
|
let mut extensions = Map::new();
|
||||||
extensions.insert("minItems".to_owned(), json!($len));
|
extensions.insert("minItems".to_owned(), json!($len));
|
||||||
extensions.insert("maxItems".to_owned(), json!($len));
|
extensions.insert("maxItems".to_owned(), json!($len));
|
||||||
let items = vec![
|
let items = vec![
|
||||||
$(gen.subschema_for::<$name>()),+
|
$(gen.subschema_for::<$name>()?),+
|
||||||
];
|
];
|
||||||
SchemaObject {
|
Ok(SchemaObject {
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
instance_type: Some(InstanceType::Array.into()),
|
||||||
items: Some(items.into()),
|
items: Some(items.into()),
|
||||||
extensions,
|
extensions,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.into()
|
}.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
|
@ -201,13 +202,12 @@ macro_rules! seq_impl {
|
||||||
{
|
{
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema
|
fn make_schema(gen: &mut SchemaGenerator) -> Result {
|
||||||
{
|
Ok(SchemaObject {
|
||||||
SchemaObject {
|
|
||||||
instance_type: Some(InstanceType::Array.into()),
|
instance_type: Some(InstanceType::Array.into()),
|
||||||
items: Some(gen.subschema_for::<T>().into()),
|
items: Some(gen.subschema_for::<T>()?.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.into()
|
}.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -231,9 +231,8 @@ macro_rules! map_impl {
|
||||||
{
|
{
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema
|
fn make_schema(gen: &mut SchemaGenerator) -> Result {
|
||||||
{
|
let subschema = gen.subschema_for::<V>()?;
|
||||||
let subschema = gen.subschema_for::<V>();
|
|
||||||
let make_schema_bool = gen.settings().bool_schemas == BoolSchemas::AdditionalPropertiesOnly
|
let make_schema_bool = gen.settings().bool_schemas == BoolSchemas::AdditionalPropertiesOnly
|
||||||
&& subschema == gen.schema_for_any();
|
&& subschema == gen.schema_for_any();
|
||||||
let mut extensions = Map::new();
|
let mut extensions = Map::new();
|
||||||
|
@ -245,11 +244,11 @@ macro_rules! map_impl {
|
||||||
json!(subschema)
|
json!(subschema)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
SchemaObject {
|
Ok(SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
extensions,
|
extensions,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.into()
|
}.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -267,28 +266,25 @@ impl<T: MakeSchema> MakeSchema for Option<T> {
|
||||||
T::is_referenceable()
|
T::is_referenceable()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn make_schema(gen: &mut SchemaGenerator) -> Result {
|
||||||
let mut schema = gen.subschema_for::<T>();
|
let mut schema = gen.subschema_for::<T>()?;
|
||||||
if gen.settings().option_add_null_type {
|
if gen.settings().option_add_null_type {
|
||||||
schema = match schema {
|
schema = match schema {
|
||||||
Schema::Bool(true) => Schema::Bool(true),
|
Schema::Bool(true) => Schema::Bool(true),
|
||||||
Schema::Bool(false) => <()>::make_schema(gen),
|
Schema::Bool(false) => <()>::make_schema(gen)?,
|
||||||
schema => SchemaObject {
|
schema => SchemaObject {
|
||||||
any_of: Some(vec![schema, <()>::make_schema(gen)]),
|
any_of: Some(vec![schema, <()>::make_schema(gen)?]),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if gen.settings().option_nullable {
|
if gen.settings().option_nullable {
|
||||||
let deref = gen.try_get_schema_object(&schema);
|
let mut deref = gen.get_schema_object(&schema)?;
|
||||||
debug_assert!(deref.is_some(), "Could not get schema object: {:?}", schema);
|
deref.extensions.insert("nullable".to_owned(), json!(true));
|
||||||
if let Some(mut deref) = deref {
|
schema = Schema::Object(deref);
|
||||||
deref.extensions.insert("nullable".to_owned(), json!(true));
|
|
||||||
schema = Schema::Object(deref);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
schema
|
Ok(schema)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +298,7 @@ macro_rules! deref_impl {
|
||||||
{
|
{
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn make_schema(gen: &mut SchemaGenerator) -> Result {
|
||||||
gen.subschema_for::<T>()
|
gen.subschema_for::<T>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,7 +317,7 @@ deref_impl!(<'a, T: ToOwned> MakeSchema for std::borrow::Cow<'a, T>);
|
||||||
impl MakeSchema for serde_json::Value {
|
impl MakeSchema for serde_json::Value {
|
||||||
no_ref_schema!();
|
no_ref_schema!();
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn make_schema(gen: &mut SchemaGenerator) -> Result {
|
||||||
gen.schema_for_any()
|
Ok(gen.schema_for_any())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use schemars::{schema_for, MakeSchema};
|
use schemars::{schema_for, MakeSchema};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)]
|
||||||
struct Flat {
|
struct Flat {
|
||||||
|
@ -32,6 +33,7 @@ struct Deep3 {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "flattening is not yet implemented"]
|
#[ignore = "flattening is not yet implemented"]
|
||||||
fn flatten_schema() {
|
fn flatten_schema() -> Result<(), Box<dyn Error>> {
|
||||||
assert_eq!(schema_for!(Flat), schema_for!(Deep1));
|
assert_eq!(schema_for!(Flat)?, schema_for!(Deep1)?);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,14 @@ use schemars::schema::*;
|
||||||
use schemars::{gen, schema_for};
|
use schemars::{gen, schema_for};
|
||||||
use serde_json::{from_str, to_string_pretty};
|
use serde_json::{from_str, to_string_pretty};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn schema_matches_default_settings() -> Result<(), Box<dyn std::error::Error>> {
|
fn schema_matches_default_settings() -> Result<(), Box<dyn Error>> {
|
||||||
let expected_json = fs::read_to_string("tests/schema.json")?;
|
let expected_json = fs::read_to_string("tests/schema.json")?;
|
||||||
let expected: Schema = from_str(&expected_json)?;
|
let expected: Schema = from_str(&expected_json)?;
|
||||||
|
|
||||||
let actual = schema_for!(Schema);
|
let actual = schema_for!(Schema)?;
|
||||||
fs::write("tests/schema.actual.json", to_string_pretty(&actual)?)?;
|
fs::write("tests/schema.actual.json", to_string_pretty(&actual)?)?;
|
||||||
|
|
||||||
assert_eq!(actual, expected, "Generated schema did not match saved schema - generated schema has been written to \"tests/schema.actual.json\".");
|
assert_eq!(actual, expected, "Generated schema did not match saved schema - generated schema has been written to \"tests/schema.actual.json\".");
|
||||||
|
@ -17,13 +18,13 @@ fn schema_matches_default_settings() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn schema_matches_openapi3() -> Result<(), Box<dyn std::error::Error>> {
|
fn schema_matches_openapi3() -> Result<(), Box<dyn Error>> {
|
||||||
let expected_json = fs::read_to_string("tests/schema-openapi3.json")?;
|
let expected_json = fs::read_to_string("tests/schema-openapi3.json")?;
|
||||||
let expected: Schema = from_str(&expected_json)?;
|
let expected: Schema = from_str(&expected_json)?;
|
||||||
|
|
||||||
let actual = gen::SchemaSettings::openapi3()
|
let actual = gen::SchemaSettings::openapi3()
|
||||||
.into_generator()
|
.into_generator()
|
||||||
.into_root_schema_for::<Schema>();
|
.into_root_schema_for::<Schema>()?;
|
||||||
fs::write(
|
fs::write(
|
||||||
"tests/schema-openapi3.actual.json",
|
"tests/schema-openapi3.actual.json",
|
||||||
to_string_pretty(&actual)?,
|
to_string_pretty(&actual)?,
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt
|
||||||
let impl_block = quote! {
|
let impl_block = quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics schemars::MakeSchema for #name #ty_generics #where_clause {
|
impl #impl_generics schemars::MakeSchema for #name #ty_generics #where_clause {
|
||||||
fn make_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
fn make_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::Result {
|
||||||
#schema
|
#schema
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -53,11 +53,11 @@ fn add_trait_bounds(generics: &mut Generics) {
|
||||||
|
|
||||||
fn wrap_schema_fields(schema_contents: TokenStream) -> TokenStream {
|
fn wrap_schema_fields(schema_contents: TokenStream) -> TokenStream {
|
||||||
quote! {
|
quote! {
|
||||||
schemars::schema::SchemaObject {
|
Ok(schemars::schema::SchemaObject {
|
||||||
#schema_contents
|
#schema_contents
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.into()
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,19 +131,19 @@ fn schema_for_untagged_enum(variants: &[Variant]) -> TokenStream {
|
||||||
fn schema_for_untagged_enum_variant(variant: &Variant) -> TokenStream {
|
fn schema_for_untagged_enum_variant(variant: &Variant) -> TokenStream {
|
||||||
match variant.style {
|
match variant.style {
|
||||||
Style::Unit => quote! {
|
Style::Unit => quote! {
|
||||||
gen.subschema_for::<()>()
|
gen.subschema_for::<()>()?
|
||||||
},
|
},
|
||||||
Style::Newtype => {
|
Style::Newtype => {
|
||||||
let f = &variant.fields[0];
|
let f = &variant.fields[0];
|
||||||
let ty = f.ty;
|
let ty = f.ty;
|
||||||
quote_spanned! {f.original.span()=>
|
quote_spanned! {f.original.span()=>
|
||||||
gen.subschema_for::<#ty>()
|
gen.subschema_for::<#ty>()?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Tuple => {
|
Style::Tuple => {
|
||||||
let types = variant.fields.iter().map(|f| f.ty);
|
let types = variant.fields.iter().map(|f| f.ty);
|
||||||
quote! {
|
quote! {
|
||||||
gen.subschema_for::<(#(#types),*)>()
|
gen.subschema_for::<(#(#types),*)>()?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Struct => schema_for_struct(&variant.fields),
|
Style::Struct => schema_for_struct(&variant.fields),
|
||||||
|
@ -155,7 +155,7 @@ fn schema_for_struct(fields: &[Field]) -> TokenStream {
|
||||||
let name = f.attrs.name().deserialize_name();
|
let name = f.attrs.name().deserialize_name();
|
||||||
let ty = f.ty;
|
let ty = f.ty;
|
||||||
quote_spanned! {f.original.span()=>
|
quote_spanned! {f.original.span()=>
|
||||||
props.insert(#name.to_owned(), gen.subschema_for::<#ty>());
|
props.insert(#name.to_owned(), gen.subschema_for::<#ty>()?);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
wrap_schema_fields(quote! {
|
wrap_schema_fields(quote! {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue