Ensure all schema types are set to nullable when appropriate
This commit is contained in:
parent
1f514f2be7
commit
650c434c1a
3 changed files with 64 additions and 25 deletions
|
@ -89,7 +89,7 @@ impl SchemaGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subschema_for<T: ?Sized + MakeSchema>(&mut self) -> Schema {
|
pub fn subschema_for<T: ?Sized + MakeSchema>(&mut self) -> Schema {
|
||||||
if !T::generates_ref_schema() {
|
if !T::is_referenceable() {
|
||||||
return T::make_schema(self);
|
return T::make_schema(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,6 @@ impl SchemaGenerator {
|
||||||
.map(|(n, _)| n.clone())
|
.map(|(n, _)| n.clone())
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
let name = self.make_unique_name::<T>();
|
let name = self.make_unique_name::<T>();
|
||||||
self.names.insert(name.clone());
|
|
||||||
self.insert_new_subschema_for::<T>(type_id, name.clone());
|
self.insert_new_subschema_for::<T>(type_id, name.clone());
|
||||||
name
|
name
|
||||||
});
|
});
|
||||||
|
@ -113,6 +112,7 @@ impl SchemaGenerator {
|
||||||
type_id: SchemaTypeId,
|
type_id: SchemaTypeId,
|
||||||
name: String,
|
name: String,
|
||||||
) {
|
) {
|
||||||
|
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));
|
self.definitions.insert(type_id.clone(), (name, dummy));
|
||||||
|
@ -153,6 +153,35 @@ impl SchemaGenerator {
|
||||||
schema
|
schema
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn try_get_schema_object<'a>(
|
||||||
|
&'a self,
|
||||||
|
mut schema: &'a Schema,
|
||||||
|
) -> Option<SchemaObject> {
|
||||||
|
loop {
|
||||||
|
match schema {
|
||||||
|
Schema::Object(o) => return Some(o.clone()),
|
||||||
|
Schema::Bool(true) => return Some(Default::default()),
|
||||||
|
Schema::Bool(false) => {
|
||||||
|
return Some(SchemaObject {
|
||||||
|
not: Some(Schema::Bool(true).into()),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Schema::Ref(r) => {
|
||||||
|
let definitions_path_len = self.settings().definitions_path.len();
|
||||||
|
let name = r.reference.get(definitions_path_len..)?;
|
||||||
|
// FIXME this is pretty inefficient
|
||||||
|
schema = self
|
||||||
|
.definitions
|
||||||
|
.values()
|
||||||
|
.filter(|(n, _)| n == name)
|
||||||
|
.map(|(_, s)| s)
|
||||||
|
.next()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn make_unique_name<T: ?Sized + MakeSchema>(&mut self) -> String {
|
fn make_unique_name<T: ?Sized + MakeSchema>(&mut self) -> String {
|
||||||
let base_name = T::schema_name();
|
let base_name = T::schema_name();
|
||||||
if self.names.contains(&base_name) {
|
if self.names.contains(&base_name) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub trait MakeSchema {
|
||||||
core::any::type_name::<Self>().replace(|c: char| !c.is_ascii_alphanumeric(), "_")
|
core::any::type_name::<Self>().replace(|c: char| !c.is_ascii_alphanumeric(), "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generates_ref_schema() -> bool {
|
fn is_referenceable() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ pub trait MakeSchema {
|
||||||
|
|
||||||
macro_rules! no_ref_schema {
|
macro_rules! no_ref_schema {
|
||||||
() => {
|
() => {
|
||||||
fn generates_ref_schema() -> bool {
|
fn is_referenceable() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -261,13 +261,15 @@ map_impl!(<K: Eq + core::hash::Hash, V, H: core::hash::BuildHasher> MakeSchema f
|
||||||
////////// OPTION //////////
|
////////// OPTION //////////
|
||||||
|
|
||||||
impl<T: MakeSchema> MakeSchema for Option<T> {
|
impl<T: MakeSchema> MakeSchema for Option<T> {
|
||||||
no_ref_schema!();
|
fn is_referenceable() -> bool {
|
||||||
|
T::is_referenceable()
|
||||||
|
}
|
||||||
|
|
||||||
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn make_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||||
let settings = gen.settings();
|
let settings = gen.settings();
|
||||||
let make_any_of = settings.option_any_of_null;
|
let make_any_of = settings.option_any_of_null;
|
||||||
let set_nullable = settings.option_nullable;
|
let set_nullable = settings.option_nullable;
|
||||||
let mut schema = match gen.subschema_for::<T>() {
|
let schema = match gen.subschema_for::<T>() {
|
||||||
Schema::Bool(true) => true.into(),
|
Schema::Bool(true) => true.into(),
|
||||||
Schema::Bool(false) => <()>::make_schema(gen),
|
Schema::Bool(false) => <()>::make_schema(gen),
|
||||||
schema => {
|
schema => {
|
||||||
|
@ -283,9 +285,11 @@ impl<T: MakeSchema> MakeSchema for Option<T> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if set_nullable {
|
if set_nullable {
|
||||||
// FIXME still need to handle ref schemas here
|
let deref = gen.try_get_schema_object(&schema);
|
||||||
if let Schema::Object(ref mut o) = schema {
|
debug_assert!(deref.is_some(), "Could not get schema object: {:?}", schema);
|
||||||
o.extensions.insert("nullable".to_owned(), true.into());
|
if let Some(mut schema) = deref {
|
||||||
|
schema.extensions.insert("nullable".to_owned(), json!(true));
|
||||||
|
return Schema::Object(schema);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
schema
|
schema
|
||||||
|
|
|
@ -13,6 +13,26 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
"core__option__Option_schemars__schema__SingleOrVec_schemars__schema__InstanceType__": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/schemars__schema__SingleOrVec_schemars__schema__InstanceType_"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"core__option__Option_schemars__schema__SingleOrVec_schemars__schema__Schema__": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/schemars__schema__SingleOrVec_schemars__schema__Schema_"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"schemars__schema__InstanceType": {
|
"schemars__schema__InstanceType": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"null",
|
"null",
|
||||||
|
@ -117,14 +137,7 @@
|
||||||
"additionalProperties": true
|
"additionalProperties": true
|
||||||
},
|
},
|
||||||
"items": {
|
"items": {
|
||||||
"anyOf": [
|
"$ref": "#/definitions/core__option__Option_schemars__schema__SingleOrVec_schemars__schema__Schema__"
|
||||||
{
|
|
||||||
"$ref": "#/definitions/schemars__schema__SingleOrVec_schemars__schema__Schema_"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"not": {
|
"not": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
|
@ -179,14 +192,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"anyOf": [
|
"$ref": "#/definitions/core__option__Option_schemars__schema__SingleOrVec_schemars__schema__InstanceType__"
|
||||||
{
|
|
||||||
"$ref": "#/definitions/schemars__schema__SingleOrVec_schemars__schema__InstanceType_"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue