Set readOnly/writeOnly on properties

This commit is contained in:
Graham Esau 2019-10-14 20:00:57 +01:00
parent 68ddfa310f
commit 2bc3957cb8
5 changed files with 55 additions and 24 deletions

View file

@ -126,7 +126,7 @@ impl SchemaGenerator {
pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> Result<SchemaObject> { pub fn root_schema_for<T: ?Sized + JsonSchema>(&mut self) -> Result<SchemaObject> {
let mut schema: SchemaObject = T::json_schema(self)?.into(); let mut schema: SchemaObject = T::json_schema(self)?.into();
let metadata = schema.metadata.get_or_insert_with(Default::default); let metadata = schema.metadata();
metadata.schema = Some("http://json-schema.org/draft-07/schema#".to_owned()); metadata.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
metadata.title = Some(T::schema_name()); metadata.title = Some(T::schema_name());
metadata.definitions.extend(self.definitions().clone()); metadata.definitions.extend(self.definitions().clone());
@ -135,7 +135,7 @@ impl SchemaGenerator {
pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> Result<SchemaObject> { pub fn into_root_schema_for<T: ?Sized + JsonSchema>(mut self) -> Result<SchemaObject> {
let mut schema: SchemaObject = T::json_schema(&mut self)?.into(); let mut schema: SchemaObject = T::json_schema(&mut self)?.into();
let metadata = schema.metadata.get_or_insert_with(Default::default); let metadata = schema.metadata();
metadata.schema = Some("http://json-schema.org/draft-07/schema#".to_owned()); metadata.schema = Some("http://json-schema.org/draft-07/schema#".to_owned());
metadata.title = Some(T::schema_name()); metadata.title = Some(T::schema_name());
metadata.definitions.extend(self.into_definitions()); metadata.definitions.extend(self.into_definitions());

View file

@ -77,6 +77,14 @@ where
} }
} }
macro_rules! get_or_insert_default_fn {
($name:ident, $ret:path) => {
pub fn $name(&mut self) -> &mut $ret {
self.$name.get_or_insert_with(Default::default)
}
};
}
impl SchemaObject { impl SchemaObject {
pub fn new_ref(reference: String) -> Self { pub fn new_ref(reference: String) -> Self {
SchemaObject { SchemaObject {
@ -95,6 +103,13 @@ impl SchemaObject {
}; };
*self == only_ref *self == only_ref
} }
get_or_insert_default_fn!(metadata, Metadata);
get_or_insert_default_fn!(subschemas, SubschemaValidation);
get_or_insert_default_fn!(number, NumberValidation);
get_or_insert_default_fn!(string, StringValidation);
get_or_insert_default_fn!(array, ArrayValidation);
get_or_insert_default_fn!(object, ObjectValidation);
} }
impl From<Schema> for SchemaObject { impl From<Schema> for SchemaObject {

View file

@ -3,16 +3,21 @@
"title": "MyStruct", "title": "MyStruct",
"type": "object", "type": "object",
"required": [ "required": [
"included1", "included",
"included2" "writable"
], ],
"properties": { "properties": {
"included1": { "included": {
"type": "null"
},
"readable": {
"readOnly": true,
"type": "string"
},
"writable": {
"writeOnly": true,
"type": "number", "type": "number",
"format": "float" "format": "float"
},
"included2": {
"type": "null"
} }
} }
} }

View file

@ -9,10 +9,10 @@ struct MyStruct {
#[serde(skip)] #[serde(skip)]
skipped2: bool, skipped2: bool,
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
skipped3: String, readable: String,
#[serde(skip_serializing)] #[serde(skip_serializing)]
included1: f32, writable: f32,
included2: (), included: (),
} }
#[test] #[test]
@ -21,15 +21,11 @@ fn skip_struct_fields() -> TestResult {
} }
#[derive(Debug, JsonSchema)] #[derive(Debug, JsonSchema)]
struct TupleStruct ( struct TupleStruct(
#[schemars(skip)] #[schemars(skip)] i32,
i32, #[serde(skip)] bool,
#[serde(skip)] #[serde(skip_deserializing)] String,
bool, #[serde(skip_serializing)] f32,
#[serde(skip_deserializing)]
String,
#[serde(skip_serializing)]
f32,
(), (),
); );
@ -55,4 +51,3 @@ pub enum MyEnum {
fn skip_enum_variants() -> TestResult { fn skip_enum_variants() -> TestResult {
test_default_generated_schema::<MyEnum>("skip_enum_variants") test_default_generated_schema::<MyEnum>("skip_enum_variants")
} }

View file

@ -267,8 +267,9 @@ fn schema_for_tuple_struct(fields: &[Field]) -> TokenStream {
fn schema_for_struct(fields: &[Field], cattrs: &attr::Container) -> TokenStream { fn schema_for_struct(fields: &[Field], cattrs: &attr::Container) -> TokenStream {
let (flat, nested): (Vec<_>, Vec<_>) = fields let (flat, nested): (Vec<_>, Vec<_>) = fields
.iter() .iter()
.filter(|f| !f.attrs.skip_deserializing()) .filter(|f| !f.attrs.skip_deserializing() || !f.attrs.skip_serializing())
.partition(|f| f.attrs.flatten()); .partition(|f| f.attrs.flatten());
let container_has_default = has_default(cattrs.default()); let container_has_default = has_default(cattrs.default());
let mut required = Vec::new(); let mut required = Vec::new();
let recurse = nested.iter().map(|field| { let recurse = nested.iter().map(|field| {
@ -277,9 +278,24 @@ fn schema_for_struct(fields: &[Field], cattrs: &attr::Container) -> TokenStream
required.push(name.clone()); required.push(name.clone());
} }
let ty = get_json_schema_type(field); let ty = get_json_schema_type(field);
if field.attrs.skip_deserializing() {
quote_spanned! {field.original.span()=>
let mut schema: schemars::schema::SchemaObject = gen.subschema_for::<#ty>()?.into();
schema.metadata().read_only = true;
props.insert(#name.to_owned(), schema.into());
}
} else if field.attrs.skip_serializing() {
quote_spanned! {field.original.span()=>
let mut schema: schemars::schema::SchemaObject = gen.subschema_for::<#ty>()?.into();
schema.metadata().write_only = true;
props.insert(#name.to_owned(), schema.into());
}
} else {
quote_spanned! {field.original.span()=> quote_spanned! {field.original.span()=>
props.insert(#name.to_owned(), gen.subschema_for::<#ty>()?); props.insert(#name.to_owned(), gen.subschema_for::<#ty>()?);
} }
}
}); });
let schema = wrap_schema_fields(quote! { let schema = wrap_schema_fields(quote! {