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,
|
&self.get_type_info().description,
|
||||||
quote! {
|
quote! {
|
||||||
#[serde(rename = #orig_name)]
|
#[serde(rename = #orig_name)]
|
||||||
#name_snake: #type_name
|
pub #name_snake: #type_name
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -223,6 +223,69 @@ impl<'a> GroupMethod<'a> {
|
||||||
Self { group, method }
|
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 {
|
fn generate_response_struct(&self) -> TokenStream {
|
||||||
let response = match self.method.types.response() {
|
let response = match self.method.types.response() {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
|
@ -239,20 +302,26 @@ impl<'a> GroupMethod<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_optional_builder(&self) -> TokenStream {
|
/// Returns a TokenStream containing a request builder if there are optional
|
||||||
let optional_params = match self.method.types.optional_parameters() {
|
/// parameters, otherwise an empty TokenStream is returned.
|
||||||
Some(params) => params,
|
fn generate_request_builder(&self) -> TokenStream {
|
||||||
None => return quote! {},
|
let optional_params = self.method.types.optional_parameters();
|
||||||
};
|
if optional_params.is_empty() {
|
||||||
|
return quote! {};
|
||||||
|
}
|
||||||
|
|
||||||
let builder_methods = optional_params
|
let builder_methods = optional_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|param| param.generate_optional_builder_method_with_docs());
|
.map(|param| param.generate_optional_builder_method_with_docs());
|
||||||
|
|
||||||
let group_name = self.group.struct_name();
|
let group_name = self.group.struct_name();
|
||||||
let mandatory_params = self.mandatory_parameters();
|
let send_method = self.generate_send_method(
|
||||||
let mandatory_param_form_builder = self.mandatory_parameters_as_form_builder();
|
&util::to_ident("send"),
|
||||||
let send_method = self.generate_optional_builder_send_method();
|
vec![],
|
||||||
|
quote! { self.group.auth },
|
||||||
|
quote! { self.form },
|
||||||
|
quote! {},
|
||||||
|
);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
pub struct Builder<'a> {
|
pub struct Builder<'a> {
|
||||||
|
@ -261,104 +330,55 @@ impl<'a> GroupMethod<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Builder<'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
|
#send_method
|
||||||
|
|
||||||
#(#builder_methods)*
|
#(#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);
|
let method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url);
|
||||||
|
|
||||||
match self.method.types.response() {
|
let (response_type, response_parse) = match self.method.types.response() {
|
||||||
Some(_) => {
|
Some(_) => (quote! { Response }, quote! { .json::<Response>() }),
|
||||||
quote! {
|
None => (quote! { String }, quote! { .text() }),
|
||||||
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 params = mandatory_params.iter().map(|param| param.to_parameter());
|
|
||||||
|
|
||||||
quote! {
|
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 {
|
fn mandatory_parameters_as_form_builder(&self) -> TokenStream {
|
||||||
let mandatory_params = match self.method.types.mandatory_params() {
|
let builder = self
|
||||||
Some(p) => p,
|
.method
|
||||||
None => return quote! {},
|
.types
|
||||||
};
|
.mandatory_params()
|
||||||
|
.into_iter()
|
||||||
let builder = mandatory_params
|
|
||||||
.iter()
|
|
||||||
.map(|param| param.generate_form_builder(quote! { form }));
|
.map(|param| param.generate_form_builder(quote! { form }));
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#(let #builder)*
|
#(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 {
|
impl types::Type {
|
||||||
|
|
|
@ -13,6 +13,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "id",
|
name: "id",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"ID of the search job",
|
"ID of the search job",
|
||||||
),
|
),
|
||||||
|
@ -22,6 +23,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "limit",
|
name: "limit",
|
||||||
is_optional: true,
|
is_optional: true,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"max number of results to return. 0 or negative means no limit",
|
"max number of results to return. 0 or negative means no limit",
|
||||||
),
|
),
|
||||||
|
@ -31,6 +33,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "offset",
|
name: "offset",
|
||||||
is_optional: true,
|
is_optional: true,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"result to start at. A negative number means count backwards (e.g. -2 returns the 2 most recent results)",
|
"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 {
|
TypeInfo {
|
||||||
name: "descrLink",
|
name: "descrLink",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"URL of the torrent's description page",
|
"URL of the torrent's description page",
|
||||||
),
|
),
|
||||||
|
@ -56,6 +60,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "fileName",
|
name: "fileName",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"Name of the file",
|
"Name of the file",
|
||||||
),
|
),
|
||||||
|
@ -65,6 +70,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "fileSize",
|
name: "fileSize",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"Size of the file in Bytes",
|
"Size of the file in Bytes",
|
||||||
),
|
),
|
||||||
|
@ -74,6 +80,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "fileUrl",
|
name: "fileUrl",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"Torrent download link (usually either .torrent file or magnet link)",
|
"Torrent download link (usually either .torrent file or magnet link)",
|
||||||
),
|
),
|
||||||
|
@ -83,6 +90,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "nbLeechers",
|
name: "nbLeechers",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"Number of leechers",
|
"Number of leechers",
|
||||||
),
|
),
|
||||||
|
@ -92,6 +100,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "nbSeeders",
|
name: "nbSeeders",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"Number of seeders",
|
"Number of seeders",
|
||||||
),
|
),
|
||||||
|
@ -101,6 +110,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "siteUrl",
|
name: "siteUrl",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"URL of the torrent site",
|
"URL of the torrent site",
|
||||||
),
|
),
|
||||||
|
@ -117,6 +127,7 @@ ApiMethod {
|
||||||
type_info: TypeInfo {
|
type_info: TypeInfo {
|
||||||
name: "results",
|
name: "results",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"Array of result objects- see table below",
|
"Array of result objects- see table below",
|
||||||
),
|
),
|
||||||
|
@ -128,6 +139,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "status",
|
name: "status",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"Current status of the search job (either Running or Stopped)",
|
"Current status of the search job (either Running or Stopped)",
|
||||||
),
|
),
|
||||||
|
@ -137,6 +149,7 @@ ApiMethod {
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "total",
|
name: "total",
|
||||||
is_optional: false,
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
description: Some(
|
description: Some(
|
||||||
"Total number of results. If the status is Running this number may continue to increase",
|
"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>> {
|
pub fn parameters(&self) -> Vec<&types::Type> {
|
||||||
self.composite_types.iter().find_map(|type_| match type_ {
|
self.composite_types
|
||||||
CompositeType::Parameters(p) => Some(&p.types),
|
.iter()
|
||||||
_ => None,
|
.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()
|
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()
|
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>> {
|
pub fn response(&self) -> Option<&Vec<types::Type>> {
|
||||||
|
@ -386,11 +395,6 @@ mod tests {
|
||||||
".check"
|
".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(file, api_method_as_str).unwrap();
|
||||||
fs::write(tree_file, tree_as_str).unwrap();
|
fs::write(tree_file, tree_as_str).unwrap();
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,16 +16,16 @@ pub struct TypeDescription {
|
||||||
pub struct TypeInfo {
|
pub struct TypeInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub is_optional: bool,
|
pub is_optional: bool,
|
||||||
// is_list: bool,
|
pub is_list: bool,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeInfo {
|
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 {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
is_optional,
|
is_optional,
|
||||||
// is_list,
|
is_list,
|
||||||
description,
|
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 {
|
pub fn to_borrowed_type(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Type::Number(_) => "i32".into(),
|
Type::Number(_) => "i32".into(),
|
||||||
|
@ -116,7 +112,12 @@ impl Type {
|
||||||
.trim();
|
.trim();
|
||||||
|
|
||||||
let is_optional = name.contains(OPTIONAL);
|
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| {
|
let create_object_type = |name: &str| {
|
||||||
Some(Type::Object(Object {
|
Some(Type::Object(Object {
|
||||||
|
@ -126,6 +127,7 @@ impl Type {
|
||||||
};
|
};
|
||||||
|
|
||||||
match type_as_str {
|
match type_as_str {
|
||||||
|
"raw" => None,
|
||||||
"bool" => Some(Type::Bool(create_type_info())),
|
"bool" => Some(Type::Bool(create_type_info())),
|
||||||
"integer" | "number" | "int" => Some(Type::Number(create_type_info())),
|
"integer" | "number" | "int" => Some(Type::Number(create_type_info())),
|
||||||
"string" => Some(Type::String(create_type_info())),
|
"string" => Some(Type::String(create_type_info())),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user