Skip to content

Commit

Permalink
refactor: somewhat cleaner approach
Browse files Browse the repository at this point in the history
  • Loading branch information
drahnr committed Apr 12, 2023
1 parent af28d71 commit f67be29
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 53 deletions.
61 changes: 52 additions & 9 deletions progenitor-impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use proc_macro2::TokenStream;
use quote::quote;
use serde::Deserialize;
use thiserror::Error;
use typify::{TypeDetails, TypeId};
use typify::{TypeSpace, TypeSpaceSettings};

use crate::to_schema::ToSchema;
Expand Down Expand Up @@ -40,6 +41,7 @@ pub type Result<T> = std::result::Result<T, Error>;

pub struct Generator {
type_space: TypeSpace,
forms: HashSet<TypeId>,
settings: GenerationSettings,
uses_futures: bool,
uses_websockets: bool,
Expand Down Expand Up @@ -163,6 +165,7 @@ impl Default for Generator {
type_space: TypeSpace::new(
TypeSpaceSettings::default().with_type_mod("types"),
),
forms: Default::default(),
settings: Default::default(),
uses_futures: Default::default(),
uses_websockets: Default::default(),
Expand Down Expand Up @@ -204,6 +207,7 @@ impl Generator {
Self {
type_space: TypeSpace::new(&type_settings),
settings: settings.clone(),
forms: Default::default(),
uses_futures: false,
uses_websockets: false,
}
Expand Down Expand Up @@ -262,6 +266,43 @@ impl Generator {

let types = self.type_space.to_stream();

let extra_impl = TokenStream::from_iter(
self.forms
.iter()
.map(|type_id| {
let typ = self.get_type_space().get_type(type_id).unwrap();
let form_name = typ.name();
let td = typ.details();
let TypeDetails::Struct(tstru) = td else { unreachable!() };
let properties = indexmap::IndexMap::<&'_ str, _>::from_iter(
tstru
.properties()
.filter_map(|(prop_name, prop_id)| {
self.get_type_space()
.get_type(&prop_id).ok()
.map(|prop_typ| (prop_name, prop_typ))
})
);
let properties = syn::punctuated::Punctuated::<_, syn::Token![,]>::from_iter(
properties
.into_iter()
.map(|(prop_name, prop_ty)| {
let ident = quote::format_ident!("{}", prop_name);
quote!{ (#prop_name, &self. #ident) }
}));

let form_name = quote::format_ident!("{}",typ.name());

quote! {
impl #form_name {
pub fn as_form<'f>(&'f self) -> impl std::iter::Iterator<Item=(&'static str, &'f [u8])> {
[#properties]
.into_iter()
.filter_map(|(name, val)| val.as_ref().map(|val| (name, val.as_slice())))
}
}
}
}));
// Generate an implementation of a `Self::as_inner` method, if an inner
// type is defined.
let maybe_inner = self.settings.inner_type.as_ref().map(|inner| {
Expand Down Expand Up @@ -290,20 +331,20 @@ impl Generator {
});

let client_docstring = {
let mut s = format!("Client for {}", spec.info.title);
let mut doc = format!("Client for {}", spec.info.title);

if let Some(ss) = &spec.info.description {
s.push_str("\n\n");
s.push_str(ss);
if let Some(desc) = &spec.info.description {
doc.push_str("\n\n");
doc.push_str(desc);
}
if let Some(ss) = &spec.info.terms_of_service {
s.push_str("\n\n");
s.push_str(ss);
if let Some(tos) = &spec.info.terms_of_service {
doc.push_str("\n\n");
doc.push_str(tos);
}

s.push_str(&format!("\n\nVersion: {}", &spec.info.version));
doc.push_str(&format!("\n\nVersion: {}", &spec.info.version));

s
doc
};

let version_str = &spec.info.version;
Expand All @@ -325,6 +366,8 @@ impl Generator {
use std::convert::TryFrom;

#types

#extra_impl
}

#[derive(Clone, Debug)]
Expand Down
73 changes: 29 additions & 44 deletions progenitor-impl/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use indexmap::{IndexMap, IndexSet};
use openapiv3::{Components, Parameter, ReferenceOr, Response, StatusCode};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
use typify::{TypeId, TypeSpace};
use typify::{TypeId, TypeSpace, TypeSpacePatch};

use crate::{
template::PathTemplate,
Expand Down Expand Up @@ -105,7 +105,7 @@ pub struct OperationParameter {
#[derive(Debug, Eq, PartialEq)]
pub enum OperationParameterType {
Type(TypeId),
Form(IndexSet<String>),
Form(TypeId),
RawBody,
}

Expand Down Expand Up @@ -585,27 +585,15 @@ impl Generator {
.map(|param| {
let name = format_ident!("{}", param.name);
match &param.typ {
OperationParameterType::Type(type_id) => {
OperationParameterType::Type(type_id)
| OperationParameterType::Form(type_id) => {
let typ = self
.type_space
.get_type(type_id)
.expect("TypeIDs are _never_ deleted. qed")
.parameter_ident_with_lifetime("a");
quote! { #name: #typ}
}
OperationParameterType::Form(keys) => {
let ts = TokenStream::from_iter(
itertools::Itertools::intersperse(
keys.iter().map(|form_prop_name| {
let form_prop_name =
format_ident!("{}", form_prop_name);
quote! { #form_prop_name: Vec<u8> }
}),
quote! {, },
),
);
ts
}
OperationParameterType::RawBody => {
quote! { #name: B }
}
Expand Down Expand Up @@ -935,15 +923,11 @@ impl Generator {
OperationParameterKind::Body(
BodyContentType::FormData
),
OperationParameterType::Form(map),
OperationParameterType::Form(_),
) => {
let form_prop_names = map.iter().cloned().map(|form_prop_name| {
let ident= format_ident!("{}", form_prop_name);
quote! { (#form_prop_name, #ident) }
});
Some(quote! {
// This uses progenitor_client::RequestBuilderExt which sets up a simple form data based on bytes
.form_from_raw(vec![ #(#form_prop_names),* ])?
.form_from_raw(body.as_form())?
})},
(OperationParameterKind::Body(_), _) => {
unreachable!("invalid body kind/type combination")
Expand Down Expand Up @@ -1408,7 +1392,8 @@ impl Generator {
.params
.iter()
.map(|param| match &param.typ {
OperationParameterType::Type(type_id) => {
OperationParameterType::Type(type_id)
| OperationParameterType::Form(type_id) => {
let ty = self.type_space.get_type(type_id)?;

// For body parameters only, if there's a builder we'll
Expand All @@ -1425,10 +1410,6 @@ impl Generator {
}
}

OperationParameterType::Form(_form) => {
todo!("Form is nit expected here")
}

OperationParameterType::RawBody => {
cloneable = false;
Ok(quote! { Result<reqwest::Body, String> })
Expand All @@ -1441,7 +1422,8 @@ impl Generator {
.params
.iter()
.map(|param| match &param.typ {
OperationParameterType::Type(type_id) => {
OperationParameterType::Type(type_id)
| OperationParameterType::Form(type_id) => {
let ty = self.type_space.get_type(type_id)?;
let details = ty.details();
let optional =
Expand All @@ -1460,9 +1442,6 @@ impl Generator {
Ok(quote! { Err(#err_msg.to_string()) })
}
}
OperationParameterType::Form(_form) => {
todo!("Form is nit expected here")
}
OperationParameterType::RawBody => {
let err_msg = format!("{} was not initialized", param.name);
Ok(quote! { Err(#err_msg.to_string()) })
Expand All @@ -1474,7 +1453,8 @@ impl Generator {
.params
.iter()
.map(|param| match &param.typ {
OperationParameterType::Type(type_id) => {
OperationParameterType::Type(type_id)
| OperationParameterType::Form(type_id) => {
let ty = self.type_space.get_type(type_id)?;
if ty.builder().is_some() {
let type_name = ty.ident();
Expand All @@ -1488,14 +1468,6 @@ impl Generator {
}
}

OperationParameterType::Form(_form) => {
todo!("Form is nit expected here")
}

OperationParameterType::Form(_form) => {
todo!("Form is nit expected here")
}

OperationParameterType::RawBody => Ok(quote! {}),
})
.collect::<Result<Vec<_>>>()?;
Expand All @@ -1508,11 +1480,12 @@ impl Generator {
.map(|param| {
let param_name = format_ident!("{}", param.name);
match &param.typ {
OperationParameterType::Type(type_id) => {
OperationParameterType::Type(type_id)
| OperationParameterType::Form(type_id) => {
let ty = self.type_space.get_type(type_id)?;
let details = ty.details();
match (&details, ty.builder()) {
// TODO right now optional body paramters are not
// TODO right now optional body parameters are not
// addressed
(typify::TypeDetails::Option(_), Some(_)) => {
unreachable!()
Expand Down Expand Up @@ -1596,7 +1569,7 @@ impl Generator {
}
}

OperationParameterType::Form(form_keys) => {
OperationParameterType::Form(type_id) => {
let err_msg = format!(
"conversion to `reqwest::Body` for {} failed",
param.name,
Expand Down Expand Up @@ -2161,7 +2134,19 @@ impl Generator {
schema
))),
}?;
OperationParameterType::Form(mapped)

let form_name = sanitize(
&format!(
"{}-form",
operation.operation_id.as_ref().unwrap(),
),
Case::Pascal,
);
let type_id = self
.type_space
.add_type_with_name(&schema.to_schema(), Some(form_name))?;
self.forms.insert(type_id.clone());
OperationParameterType::Form(type_id)
}
BodyContentType::Json | BodyContentType::FormUrlencoded => {
// TODO it would be legal to have the encoding field set for
Expand Down

0 comments on commit f67be29

Please sign in to comment.