Progress
This commit is contained in:
parent
07e825bcd4
commit
4a1db65877
File diff suppressed because it is too large
Load Diff
|
@ -156,7 +156,7 @@ impl types::Type {
|
|||
&self.get_type_info().description,
|
||||
quote! {
|
||||
#[serde(rename = #orig_name)]
|
||||
#name_snake: #type_name
|
||||
pub #name_snake: #type_name
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -223,6 +223,69 @@ impl<'a> GroupMethod<'a> {
|
|||
Self { group, method }
|
||||
}
|
||||
|
||||
fn generate_method(&self) -> TokenStream {
|
||||
let method_name = self.method.name_snake();
|
||||
let structs = self.method.structs();
|
||||
let enums = self.method.enums();
|
||||
let builder = self.generate_request_builder();
|
||||
let response_struct = self.generate_response_struct();
|
||||
let request_method = self.generate_request_method();
|
||||
|
||||
quote! {
|
||||
pub mod #method_name {
|
||||
#structs
|
||||
#enums
|
||||
#builder
|
||||
#response_struct
|
||||
#request_method
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_request_method(&self) -> TokenStream {
|
||||
let method_name = self.method.name_snake();
|
||||
|
||||
let parameters = self
|
||||
.method
|
||||
.types
|
||||
.mandatory_params()
|
||||
.iter()
|
||||
.map(|param| param.to_parameter())
|
||||
.collect();
|
||||
|
||||
let form_builder = self.mandatory_parameters_as_form_builder();
|
||||
|
||||
let method_impl = if self.method.types.optional_parameters().is_empty() {
|
||||
self.generate_send_method(
|
||||
&method_name,
|
||||
parameters,
|
||||
quote! { self.auth },
|
||||
quote! { form },
|
||||
quote! {
|
||||
let form = reqwest::multipart::Form::new();
|
||||
#form_builder
|
||||
},
|
||||
)
|
||||
} else {
|
||||
quote! {
|
||||
pub fn #method_name(&self, #(#parameters),*) -> Builder<'_> {
|
||||
let form = reqwest::multipart::Form::new();
|
||||
#form_builder
|
||||
Builder { group: self, form }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let group_struct_name = self.group.struct_name();
|
||||
let method_impl_with_docs = util::add_docs(&self.method.description, method_impl);
|
||||
|
||||
quote! {
|
||||
impl<'a> super::#group_struct_name<'a> {
|
||||
#method_impl_with_docs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_response_struct(&self) -> TokenStream {
|
||||
let response = match self.method.types.response() {
|
||||
Some(res) => res,
|
||||
|
@ -239,20 +302,26 @@ impl<'a> GroupMethod<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn generate_optional_builder(&self) -> TokenStream {
|
||||
let optional_params = match self.method.types.optional_parameters() {
|
||||
Some(params) => params,
|
||||
None => return quote! {},
|
||||
};
|
||||
/// Returns a TokenStream containing a request builder if there are optional
|
||||
/// parameters, otherwise an empty TokenStream is returned.
|
||||
fn generate_request_builder(&self) -> TokenStream {
|
||||
let optional_params = self.method.types.optional_parameters();
|
||||
if optional_params.is_empty() {
|
||||
return quote! {};
|
||||
}
|
||||
|
||||
let builder_methods = optional_params
|
||||
.iter()
|
||||
.map(|param| param.generate_optional_builder_method_with_docs());
|
||||
|
||||
let group_name = self.group.struct_name();
|
||||
let mandatory_params = self.mandatory_parameters();
|
||||
let mandatory_param_form_builder = self.mandatory_parameters_as_form_builder();
|
||||
let send_method = self.generate_optional_builder_send_method();
|
||||
let send_method = self.generate_send_method(
|
||||
&util::to_ident("send"),
|
||||
vec![],
|
||||
quote! { self.group.auth },
|
||||
quote! { self.form },
|
||||
quote! {},
|
||||
);
|
||||
|
||||
quote! {
|
||||
pub struct Builder<'a> {
|
||||
|
@ -261,104 +330,55 @@ impl<'a> GroupMethod<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Builder<'a> {
|
||||
pub fn new(group: &'a super::#group_name, #mandatory_params) -> Self {
|
||||
let form = reqwest::multipart::Form::new();
|
||||
#mandatory_param_form_builder
|
||||
Self { group, form }
|
||||
}
|
||||
|
||||
#send_method
|
||||
|
||||
#(#builder_methods)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_optional_builder_send_method(&self) -> TokenStream {
|
||||
fn generate_send_method(
|
||||
&self,
|
||||
method_name: &Ident,
|
||||
parameters: Vec<TokenStream>,
|
||||
auth_access: TokenStream,
|
||||
form_access: TokenStream,
|
||||
form_factory: TokenStream,
|
||||
) -> TokenStream {
|
||||
let method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url);
|
||||
|
||||
match self.method.types.response() {
|
||||
Some(_) => {
|
||||
quote! {
|
||||
pub async fn send(self) -> super::super::Result<Response> {
|
||||
let res = self
|
||||
.group
|
||||
.auth
|
||||
.authenticated_client(#method_url)
|
||||
.multipart(self.form)
|
||||
.send()
|
||||
.await?
|
||||
.json::<Response>()
|
||||
.await?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
quote! {
|
||||
pub async fn send(self) -> super::super::Result<String> {
|
||||
let res = self
|
||||
.group
|
||||
.auth
|
||||
.authenticated_client(#method_url)
|
||||
.multipart(self.form)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mandatory_parameters(&self) -> TokenStream {
|
||||
let mandatory_params = match self.method.types.mandatory_params() {
|
||||
Some(p) => p,
|
||||
None => return quote! {},
|
||||
let (response_type, response_parse) = match self.method.types.response() {
|
||||
Some(_) => (quote! { Response }, quote! { .json::<Response>() }),
|
||||
None => (quote! { String }, quote! { .text() }),
|
||||
};
|
||||
|
||||
let params = mandatory_params.iter().map(|param| param.to_parameter());
|
||||
|
||||
quote! {
|
||||
#(#params),*
|
||||
pub async fn #method_name(self, #(#parameters),*) -> super::super::Result<#response_type> {
|
||||
#form_factory
|
||||
let res = #auth_access
|
||||
.authenticated_client(#method_url)
|
||||
.multipart(#form_access)
|
||||
.send()
|
||||
.await?
|
||||
#response_parse
|
||||
.await?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mandatory_parameters_as_form_builder(&self) -> TokenStream {
|
||||
let mandatory_params = match self.method.types.mandatory_params() {
|
||||
Some(p) => p,
|
||||
None => return quote! {},
|
||||
};
|
||||
|
||||
let builder = mandatory_params
|
||||
.iter()
|
||||
let builder = self
|
||||
.method
|
||||
.types
|
||||
.mandatory_params()
|
||||
.into_iter()
|
||||
.map(|param| param.generate_form_builder(quote! { form }));
|
||||
|
||||
quote! {
|
||||
#(let #builder)*
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_method(&self) -> TokenStream {
|
||||
let method_name = self.method.name_snake();
|
||||
let structs = self.method.structs();
|
||||
let enums = self.method.enums();
|
||||
let builder = self.generate_optional_builder();
|
||||
let response_struct = self.generate_response_struct();
|
||||
|
||||
quote! {
|
||||
pub mod #method_name {
|
||||
#structs
|
||||
#enums
|
||||
#builder
|
||||
#response_struct
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl types::Type {
|
||||
|
|
|
@ -13,6 +13,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "id",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"ID of the search job",
|
||||
),
|
||||
|
@ -22,6 +23,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "limit",
|
||||
is_optional: true,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"max number of results to return. 0 or negative means no limit",
|
||||
),
|
||||
|
@ -31,6 +33,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "offset",
|
||||
is_optional: true,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)",
|
||||
),
|
||||
|
@ -47,6 +50,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "descrLink",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"URL of the torrent's description page",
|
||||
),
|
||||
|
@ -56,6 +60,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "fileName",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Name of the file",
|
||||
),
|
||||
|
@ -65,6 +70,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "fileSize",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Size of the file in Bytes",
|
||||
),
|
||||
|
@ -74,6 +80,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "fileUrl",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Torrent download link (usually either .torrent file or magnet link)",
|
||||
),
|
||||
|
@ -83,6 +90,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "nbLeechers",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Number of leechers",
|
||||
),
|
||||
|
@ -92,6 +100,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "nbSeeders",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Number of seeders",
|
||||
),
|
||||
|
@ -101,6 +110,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "siteUrl",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"URL of the torrent site",
|
||||
),
|
||||
|
@ -117,6 +127,7 @@ ApiMethod {
|
|||
type_info: TypeInfo {
|
||||
name: "results",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Array of result objects- see table below",
|
||||
),
|
||||
|
@ -128,6 +139,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "status",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Current status of the search job (either Running or Stopped)",
|
||||
),
|
||||
|
@ -137,6 +149,7 @@ ApiMethod {
|
|||
TypeInfo {
|
||||
name: "total",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Total number of results. If the status is Running this number may continue to increase",
|
||||
),
|
||||
|
|
|
@ -27,21 +27,30 @@ impl CompositeTypes {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parameters(&self) -> Option<&Vec<types::Type>> {
|
||||
self.composite_types.iter().find_map(|type_| match type_ {
|
||||
CompositeType::Parameters(p) => Some(&p.types),
|
||||
_ => None,
|
||||
})
|
||||
pub fn parameters(&self) -> Vec<&types::Type> {
|
||||
self.composite_types
|
||||
.iter()
|
||||
.find_map(|type_| match type_ {
|
||||
CompositeType::Parameters(p) => Some(p.types.iter().collect()),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn optional_parameters(&self) -> Option<Vec<&types::Type>> {
|
||||
pub fn optional_parameters(&self) -> Vec<&types::Type> {
|
||||
self.parameters()
|
||||
.map(|params| params.iter().filter(|param| param.is_optional()).collect())
|
||||
.iter()
|
||||
.filter(|param| param.is_optional())
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn mandatory_params(&self) -> Option<Vec<&types::Type>> {
|
||||
pub fn mandatory_params(&self) -> Vec<&types::Type> {
|
||||
self.parameters()
|
||||
.map(|params| params.iter().filter(|param| !param.is_optional()).collect())
|
||||
.iter()
|
||||
.filter(|param| !param.is_optional())
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn response(&self) -> Option<&Vec<types::Type>> {
|
||||
|
@ -386,11 +395,6 @@ mod tests {
|
|||
".check"
|
||||
);
|
||||
|
||||
// prevent user from accidentally leaving the current macro in a test
|
||||
if Path::new(file).exists() {
|
||||
panic!("Test case already exists: {file}");
|
||||
}
|
||||
|
||||
fs::write(file, api_method_as_str).unwrap();
|
||||
fs::write(tree_file, tree_as_str).unwrap();
|
||||
};
|
||||
|
|
|
@ -16,16 +16,16 @@ pub struct TypeDescription {
|
|||
pub struct TypeInfo {
|
||||
pub name: String,
|
||||
pub is_optional: bool,
|
||||
// is_list: bool,
|
||||
pub is_list: bool,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
impl TypeInfo {
|
||||
pub fn new(name: &str, is_optional: bool, description: Option<String>) -> Self {
|
||||
pub fn new(name: &str, is_optional: bool, is_list: bool, description: Option<String>) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
is_optional,
|
||||
// is_list,
|
||||
is_list,
|
||||
description,
|
||||
}
|
||||
}
|
||||
|
@ -74,10 +74,6 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
// pub fn is_list(&self) -> bool {
|
||||
// self.get_type_info().is_list || matches!(self, Type::StringArray(_))
|
||||
// }
|
||||
|
||||
pub fn to_borrowed_type(&self) -> String {
|
||||
match self {
|
||||
Type::Number(_) => "i32".into(),
|
||||
|
@ -116,7 +112,12 @@ impl Type {
|
|||
.trim();
|
||||
|
||||
let is_optional = name.contains(OPTIONAL);
|
||||
let create_type_info = || TypeInfo::new(type_name, is_optional, description.clone());
|
||||
let is_list = description
|
||||
.clone()
|
||||
.map(|desc| desc.contains("array"))
|
||||
.unwrap_or(false);
|
||||
let create_type_info =
|
||||
|| TypeInfo::new(type_name, is_optional, is_list, description.clone());
|
||||
|
||||
let create_object_type = |name: &str| {
|
||||
Some(Type::Object(Object {
|
||||
|
@ -126,6 +127,7 @@ impl Type {
|
|||
};
|
||||
|
||||
match type_as_str {
|
||||
"raw" => None,
|
||||
"bool" => Some(Type::Bool(create_type_info())),
|
||||
"integer" | "number" | "int" => Some(Type::Number(create_type_info())),
|
||||
"string" => Some(Type::String(create_type_info())),
|
||||
|
|
Loading…
Reference in New Issue
Block a user