diff --git a/schemars/src/make_schema.rs b/schemars/src/make_schema.rs index 4bb6137..5b5dc35 100644 --- a/schemars/src/make_schema.rs +++ b/schemars/src/make_schema.rs @@ -262,6 +262,8 @@ map_impl!( MakeSchema f impl MakeSchema for Option { fn is_referenceable() -> bool { + // TODO only really needs to be referenceable with option_nullable enabled. + // TODO what if T is Box and U is referenceable? T::is_referenceable() } @@ -279,10 +281,11 @@ impl MakeSchema for Option { } } if gen.settings().option_nullable { - let mut deref = gen.try_get_schema_object(&schema); + let deref = gen.try_get_schema_object(&schema); debug_assert!(deref.is_some(), "Could not get schema object: {:?}", schema); - if let Some(ref mut schema) = deref { - schema.extensions.insert("nullable".to_owned(), json!(true)); + if let Some(mut deref) = deref { + deref.extensions.insert("nullable".to_owned(), json!(true)); + schema = Schema::Object(deref); } }; schema diff --git a/schemars/src/schema.rs b/schemars/src/schema.rs index 2ae521c..4c298bc 100644 --- a/schemars/src/schema.rs +++ b/schemars/src/schema.rs @@ -4,8 +4,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::BTreeMap as Map; -// TODO use serde_json::Map (or some other wrapper) instead of BTreeMap to ensure preserve_order is possible - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, MakeSchema)] #[serde(untagged)] pub enum Schema { diff --git a/schemars/tests/schema-openapi3.json b/schemars/tests/schema-openapi3.json new file mode 100644 index 0000000..dac35e0 --- /dev/null +++ b/schemars/tests/schema-openapi3.json @@ -0,0 +1,191 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "schemars__schema__Schema", + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/schemars__schema__SchemaRef" + }, + { + "$ref": "#/components/schemas/schemars__schema__SchemaObject" + } + ], + "definitions": { + "core__option__Option_schemars__schema__SingleOrVec_schemars__schema__InstanceType__": { + "anyOf": [ + { + "$ref": "#/components/schemas/schemars__schema__InstanceType" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/schemars__schema__InstanceType" + } + } + ], + "nullable": true + }, + "core__option__Option_schemars__schema__SingleOrVec_schemars__schema__Schema__": { + "anyOf": [ + { + "$ref": "#/components/schemas/schemars__schema__Schema" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/schemars__schema__Schema" + } + } + ], + "nullable": true + }, + "schemars__schema__InstanceType": { + "enum": [ + "null", + "boolean", + "object", + "array", + "number", + "string", + "integer" + ] + }, + "schemars__schema__Schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/schemars__schema__SchemaRef" + }, + { + "$ref": "#/components/schemas/schemars__schema__SchemaObject" + } + ] + }, + "schemars__schema__SchemaObject": { + "properties": { + "$id": { + "type": "string", + "nullable": true + }, + "$schema": { + "type": "string", + "nullable": true + }, + "allOf": { + "type": "array", + "items": { + "$ref": "#/components/schemas/schemars__schema__Schema" + }, + "nullable": true + }, + "anyOf": { + "type": "array", + "items": { + "$ref": "#/components/schemas/schemars__schema__Schema" + }, + "nullable": true + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/schemars__schema__Schema" + } + }, + "description": { + "type": "string", + "nullable": true + }, + "enum": { + "type": "array", + "items": {}, + "nullable": true + }, + "extensions": { + "type": "object", + "additionalProperties": true + }, + "items": { + "$ref": "#/components/schemas/core__option__Option_schemars__schema__SingleOrVec_schemars__schema__Schema__" + }, + "not": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/schemars__schema__SchemaRef" + }, + { + "$ref": "#/components/schemas/schemars__schema__SchemaObject" + } + ], + "nullable": true + }, + "oneOf": { + "type": "array", + "items": { + "$ref": "#/components/schemas/schemars__schema__Schema" + }, + "nullable": true + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/schemars__schema__Schema" + } + }, + "required": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "type": { + "$ref": "#/components/schemas/core__option__Option_schemars__schema__SingleOrVec_schemars__schema__InstanceType__" + } + } + }, + "schemars__schema__SchemaRef": { + "properties": { + "$ref": { + "type": "string" + } + } + }, + "schemars__schema__SingleOrVec_schemars__schema__InstanceType_": { + "anyOf": [ + { + "$ref": "#/components/schemas/schemars__schema__InstanceType" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/schemars__schema__InstanceType" + } + } + ] + }, + "schemars__schema__SingleOrVec_schemars__schema__Schema_": { + "anyOf": [ + { + "$ref": "#/components/schemas/schemars__schema__Schema" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/schemars__schema__Schema" + } + } + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/test.rs b/schemars/tests/test.rs index 13e8502..9bb82de 100644 --- a/schemars/tests/test.rs +++ b/schemars/tests/test.rs @@ -1,5 +1,5 @@ use schemars::schema::*; -use schemars::schema_for; +use schemars::{gen, schema_for}; use serde_json::{from_str, to_string_pretty}; use std::fs; @@ -8,7 +8,7 @@ mod tests { use super::*; #[test] - fn schema_matches() -> Result<(), Box> { + fn schema_matches_default_settings() -> Result<(), Box> { let expected_json = fs::read_to_string("tests/schema.json")?; let expected: Schema = from_str(&expected_json)?; @@ -18,4 +18,21 @@ mod tests { assert_eq!(actual, expected, "\n\nGenerated schema did not match saved schema - generated schema has been written to \"tests/schema.actual.json\"."); Ok(()) } + + #[test] + fn schema_matches_openapi3() -> Result<(), Box> { + let expected_json = fs::read_to_string("tests/schema-openapi3.json")?; + let expected: Schema = from_str(&expected_json)?; + + let actual = gen::SchemaSettings::openapi3() + .into_generator() + .into_root_schema_for::(); + fs::write( + "tests/schema-openapi3.actual.json", + to_string_pretty(&actual)?, + )?; + + assert_eq!(actual, expected, "\n\nGenerated schema did not match saved schema - generated schema has been written to \"tests/schema-openapi3.actual.json\"."); + Ok(()) + } }