Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix optional type aliases #272

Merged
merged 4 commits into from
Dec 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

### Fixed
- Optional type aliases like `type Email = Option<String>` will not be added to the `required` fields.

## [0.5.0] - 2020-11-28
### Added
Expand Down
5 changes: 5 additions & 0 deletions core/src/v2/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ pub trait Apiv2Schema {
/// Description of this schema. In case the trait is derived, uses the documentation on the type.
const DESCRIPTION: &'static str = "";

/// Indicates the requirement of this schema.
const REQUIRED: bool = true;

/// Returns the raw schema for this object.
fn raw_schema() -> DefaultSchemaRaw {
Default::default()
Expand Down Expand Up @@ -304,6 +307,7 @@ impl<T: TypedData> Apiv2Schema for T {
#[cfg(feature = "nightly")]
impl<T> Apiv2Schema for Option<T> {
default const NAME: Option<&'static str> = None;
default const REQUIRED: bool = false;

default fn raw_schema() -> DefaultSchemaRaw {
Default::default()
Expand All @@ -316,6 +320,7 @@ impl<T> Apiv2Schema for Option<T> {

impl<T: Apiv2Schema> Apiv2Schema for Option<T> {
const NAME: Option<&'static str> = T::NAME;
const REQUIRED: bool = false;

fn raw_schema() -> DefaultSchemaRaw {
T::raw_schema()
Expand Down
33 changes: 9 additions & 24 deletions macros/src/actix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,39 +769,24 @@ fn add_optional_impl(name: &Ident, generics: &Generics) -> proc_macro2::TokenStr
}
}

fn get_field_type(field: &Field) -> (Option<proc_macro2::TokenStream>, bool) {
let mut is_required = true;
fn get_field_type(field: &Field) -> Option<proc_macro2::TokenStream> {
match field.ty {
Type::Path(ref p) => {
let ty = p
.path
.segments
.last()
.expect("expected type for struct field");

if p.path.segments.len() == 1 && &ty.ident == "Option" {
is_required = false;
}
Comment on lines -782 to -784
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is certainly not what I expected in code. I guess you can't always remember how the code evolves.


(Some(address_type_for_fn_call(&field.ty)), is_required)
}
Type::Reference(_) => (Some(address_type_for_fn_call(&field.ty)), is_required),
Type::Path(_) | Type::Reference(_) => Some(address_type_for_fn_call(&field.ty)),
_ => {
emit_warning!(
field.ty.span().unwrap(),
"unsupported field type will be ignored."
);
(None, is_required)
None
}
}
}

/// Generates code for a tuple struct with fields.
fn handle_unnamed_field_struct(fields: &FieldsUnnamed, props_gen: &mut proc_macro2::TokenStream) {
let field = fields.unnamed.iter().next().unwrap();
let (ty_ref, _) = get_field_type(&field);

if let Some(ty_ref) = ty_ref {
if let Some(ty_ref) = get_field_type(&field) {
props_gen.extend(quote!({
schema = #ty_ref::raw_schema();
}));
Expand Down Expand Up @@ -877,7 +862,7 @@ fn handle_field_struct(
field_name = prop.rename(&field_name);
}

let (ty_ref, is_required) = get_field_type(&field);
let ty_ref = get_field_type(&field);

let docs = extract_documentation(&field.attrs);
let docs = docs.trim();
Expand All @@ -897,11 +882,11 @@ fn handle_field_struct(
})
};

if is_required {
gen.extend(quote! {
gen.extend(quote! {
if #ty_ref::REQUIRED {
schema.required.insert(#field_name.into());
});
}
}
});

props_gen.extend(gen);
}
Expand Down
4 changes: 3 additions & 1 deletion tests/test_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use uuid_dev::Uuid;
static CLIENT: Lazy<reqwest::blocking::Client> = Lazy::new(|| reqwest::blocking::Client::new());
static PORTS: Lazy<Mutex<HashSet<u16>>> = Lazy::new(|| Mutex::new(HashSet::new()));

type OptionalUuid = Option<uuid_dev::Uuid>;

#[derive(Deserialize, Serialize, Apiv2Schema)]
#[serde(rename_all = "lowercase")]
enum PetClass {
Expand All @@ -44,7 +46,7 @@ struct Pet {
birthday: chrono_dev::NaiveDate,
updated_on: Option<chrono_dev::NaiveDateTime>,
#[serde(rename = "uuid")]
uid: Option<uuid_dev::Uuid>,
uid: OptionalUuid,
}

impl Default for Pet {
Expand Down