Support for list return
This commit is contained in:
parent
4a1db65877
commit
ab816e14b1
File diff suppressed because it is too large
Load Diff
|
@ -150,13 +150,18 @@ impl types::Type {
|
|||
fn generate_struct_field(&self) -> TokenStream {
|
||||
let name_snake = self.name_snake();
|
||||
let type_name = util::to_ident(&self.to_owned_type());
|
||||
let type_ = if self.is_list() {
|
||||
quote! { std::vec::Vec<#type_name> }
|
||||
} else {
|
||||
quote! { #type_name }
|
||||
};
|
||||
let orig_name = self.name();
|
||||
|
||||
util::add_docs(
|
||||
&self.get_type_info().description,
|
||||
quote! {
|
||||
#[serde(rename = #orig_name)]
|
||||
pub #name_snake: #type_name
|
||||
pub #name_snake: #type_
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -292,7 +297,10 @@ impl<'a> GroupMethod<'a> {
|
|||
None => return quote! {},
|
||||
};
|
||||
|
||||
let struct_fields = response.iter().map(|field| field.generate_struct_field());
|
||||
let struct_fields = response
|
||||
.types
|
||||
.iter()
|
||||
.map(|field| field.generate_struct_field());
|
||||
|
||||
quote! {
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
|
@ -347,7 +355,16 @@ impl<'a> GroupMethod<'a> {
|
|||
let method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url);
|
||||
|
||||
let (response_type, response_parse) = match self.method.types.response() {
|
||||
Some(_) => (quote! { Response }, quote! { .json::<Response>() }),
|
||||
Some(resp) => {
|
||||
if resp.is_list {
|
||||
(
|
||||
quote! { std::vec::Vec<Response> },
|
||||
quote! { .json::<std::vec::Vec<Response>>() },
|
||||
)
|
||||
} else {
|
||||
(quote! { Response }, quote! { .json::<Response>() })
|
||||
}
|
||||
}
|
||||
None => (quote! { String }, quote! { .text() }),
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
ApiMethod {
|
||||
name: "foo",
|
||||
description: None,
|
||||
url: "foo",
|
||||
types: CompositeTypes {
|
||||
composite_types: [
|
||||
Response(
|
||||
TypeWithoutName {
|
||||
types: [
|
||||
Number(
|
||||
TypeInfo {
|
||||
name: "amount_left",
|
||||
description: Some(
|
||||
"Amount of data left to download (bytes)",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: true,
|
||||
},
|
||||
),
|
||||
],
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
## Testing
|
||||
|
||||
Name: `foo`
|
||||
|
||||
The response is a JSON object with the following fields
|
||||
|
||||
Property | Type | Description
|
||||
---------------------|---------|------------
|
||||
`amount_left` | integer array | Amount of data left to download (bytes)
|
|
@ -0,0 +1,52 @@
|
|||
TokenTree {
|
||||
title: None,
|
||||
content: [],
|
||||
children: [
|
||||
TokenTree {
|
||||
title: Some(
|
||||
"Testing",
|
||||
),
|
||||
content: [
|
||||
Text(
|
||||
"",
|
||||
),
|
||||
Text(
|
||||
"Name: `foo`",
|
||||
),
|
||||
Text(
|
||||
"",
|
||||
),
|
||||
Text(
|
||||
"The response is a JSON object with the following fields",
|
||||
),
|
||||
Text(
|
||||
"",
|
||||
),
|
||||
Table(
|
||||
Table {
|
||||
header: TableRow {
|
||||
raw: "Property | Type | Description",
|
||||
columns: [
|
||||
"Property",
|
||||
"Type",
|
||||
"Description",
|
||||
],
|
||||
},
|
||||
split: "---------------------|---------|------------",
|
||||
rows: [
|
||||
TableRow {
|
||||
raw: "`amount_left` | integer array | Amount of data left to download (bytes)",
|
||||
columns: [
|
||||
"amount_left",
|
||||
"integer array",
|
||||
"Amount of data left to download (bytes)",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
],
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
ApiMethod {
|
||||
name: "foo",
|
||||
description: None,
|
||||
url: "foo",
|
||||
types: CompositeTypes {
|
||||
composite_types: [
|
||||
Response(
|
||||
TypeWithoutName {
|
||||
types: [
|
||||
Number(
|
||||
TypeInfo {
|
||||
name: "added_on",
|
||||
description: Some(
|
||||
"Time (Unix Epoch) when the torrent was added to the client",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
is_list: true,
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
## Testing
|
||||
|
||||
Name: `foo`
|
||||
|
||||
The response is a JSON array with the following fields
|
||||
|
||||
Property | Type | Description
|
||||
---------------------|---------|------------
|
||||
`added_on` | integer | Time (Unix Epoch) when the torrent was added to the client
|
|
@ -0,0 +1,52 @@
|
|||
TokenTree {
|
||||
title: None,
|
||||
content: [],
|
||||
children: [
|
||||
TokenTree {
|
||||
title: Some(
|
||||
"Testing",
|
||||
),
|
||||
content: [
|
||||
Text(
|
||||
"",
|
||||
),
|
||||
Text(
|
||||
"Name: `foo`",
|
||||
),
|
||||
Text(
|
||||
"",
|
||||
),
|
||||
Text(
|
||||
"The response is a JSON array with the following fields",
|
||||
),
|
||||
Text(
|
||||
"",
|
||||
),
|
||||
Table(
|
||||
Table {
|
||||
header: TableRow {
|
||||
raw: "Property | Type | Description",
|
||||
columns: [
|
||||
"Property",
|
||||
"Type",
|
||||
"Description",
|
||||
],
|
||||
},
|
||||
split: "---------------------|---------|------------",
|
||||
rows: [
|
||||
TableRow {
|
||||
raw: "`added_on` | integer | Time (Unix Epoch) when the torrent was added to the client",
|
||||
columns: [
|
||||
"added_on",
|
||||
"integer",
|
||||
"Time (Unix Epoch) when the torrent was added to the client",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
],
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
}
|
|
@ -12,34 +12,35 @@ ApiMethod {
|
|||
Number(
|
||||
TypeInfo {
|
||||
name: "id",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"ID of the search job",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
Number(
|
||||
TypeInfo {
|
||||
name: "limit",
|
||||
is_optional: true,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"max number of results to return. 0 or negative means no limit",
|
||||
),
|
||||
is_optional: true,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
Number(
|
||||
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)",
|
||||
),
|
||||
is_optional: true,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
Object(
|
||||
|
@ -49,71 +50,71 @@ ApiMethod {
|
|||
String(
|
||||
TypeInfo {
|
||||
name: "descrLink",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"URL of the torrent's description page",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
String(
|
||||
TypeInfo {
|
||||
name: "fileName",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Name of the file",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
Number(
|
||||
TypeInfo {
|
||||
name: "fileSize",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Size of the file in Bytes",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
String(
|
||||
TypeInfo {
|
||||
name: "fileUrl",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Torrent download link (usually either .torrent file or magnet link)",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
Number(
|
||||
TypeInfo {
|
||||
name: "nbLeechers",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Number of leechers",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
Number(
|
||||
TypeInfo {
|
||||
name: "nbSeeders",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Number of seeders",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
String(
|
||||
TypeInfo {
|
||||
name: "siteUrl",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"URL of the torrent site",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -126,36 +127,37 @@ ApiMethod {
|
|||
Object {
|
||||
type_info: TypeInfo {
|
||||
name: "results",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Array of result objects- see table below",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: true,
|
||||
},
|
||||
ref_type: "Result",
|
||||
ref_type: "",
|
||||
},
|
||||
),
|
||||
String(
|
||||
TypeInfo {
|
||||
name: "status",
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
description: Some(
|
||||
"Current status of the search job (either Running or Stopped)",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
Number(
|
||||
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",
|
||||
),
|
||||
is_optional: false,
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
is_list: false,
|
||||
},
|
||||
),
|
||||
],
|
||||
|
|
|
@ -53,9 +53,9 @@ impl CompositeTypes {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn response(&self) -> Option<&Vec<types::Type>> {
|
||||
pub fn response(&self) -> Option<&TypeWithoutName> {
|
||||
self.composite_types.iter().find_map(|type_| match type_ {
|
||||
CompositeType::Response(p) => Some(&p.types),
|
||||
CompositeType::Response(p) => Some(p),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
@ -104,11 +104,12 @@ pub struct TypeWithName {
|
|||
#[derive(Debug)]
|
||||
pub struct TypeWithoutName {
|
||||
pub types: Vec<types::Type>,
|
||||
pub is_list: bool,
|
||||
}
|
||||
|
||||
impl TypeWithoutName {
|
||||
pub fn new(types: Vec<types::Type>) -> Self {
|
||||
Self { types }
|
||||
pub fn new(types: Vec<types::Type>, is_list: bool) -> Self {
|
||||
Self { types, is_list }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,6 +271,7 @@ impl md_parser::Table {
|
|||
|
||||
Some(CompositeType::Response(TypeWithoutName::new(
|
||||
self.to_types(),
|
||||
input_name.to_lowercase().contains("array"),
|
||||
)))
|
||||
}
|
||||
|
||||
|
@ -280,6 +282,7 @@ impl md_parser::Table {
|
|||
|
||||
Some(CompositeType::Parameters(TypeWithoutName::new(
|
||||
self.to_types(),
|
||||
input_name.to_lowercase().contains("array"),
|
||||
)))
|
||||
}
|
||||
|
||||
|
@ -409,4 +412,14 @@ mod tests {
|
|||
fn enum_test() {
|
||||
run_test!("enum");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_result() {
|
||||
run_test!("array_result");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_field() {
|
||||
run_test!("array_field");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,18 +15,18 @@ pub struct TypeDescription {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct TypeInfo {
|
||||
pub name: String,
|
||||
pub is_optional: bool,
|
||||
pub is_list: bool,
|
||||
pub description: Option<String>,
|
||||
is_optional: bool,
|
||||
is_list: bool,
|
||||
}
|
||||
|
||||
impl TypeInfo {
|
||||
pub fn new(name: &str, is_optional: bool, is_list: bool, description: Option<String>) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
description,
|
||||
is_optional,
|
||||
is_list,
|
||||
description,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,10 @@ impl Type {
|
|||
self.get_type_info().is_optional
|
||||
}
|
||||
|
||||
pub fn is_list(&self) -> bool {
|
||||
self.get_type_info().is_list
|
||||
}
|
||||
|
||||
pub fn get_type_info(&self) -> &TypeInfo {
|
||||
match self {
|
||||
Type::Number(t) => t,
|
||||
|
@ -116,8 +120,21 @@ impl Type {
|
|||
.clone()
|
||||
.map(|desc| desc.contains("array"))
|
||||
.unwrap_or(false);
|
||||
let create_type_info =
|
||||
|| TypeInfo::new(type_name, is_optional, is_list, description.clone());
|
||||
|
||||
let (type_without_array, type_contains_array) = if type_as_str.contains("array") {
|
||||
(type_as_str.replace("array", ""), true)
|
||||
} else {
|
||||
(type_as_str.to_owned(), false)
|
||||
};
|
||||
|
||||
let create_type_info = || {
|
||||
TypeInfo::new(
|
||||
type_name,
|
||||
is_optional,
|
||||
is_list || type_contains_array,
|
||||
description.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
let create_object_type = |name: &str| {
|
||||
Some(Type::Object(Object {
|
||||
|
@ -126,7 +143,7 @@ impl Type {
|
|||
}))
|
||||
};
|
||||
|
||||
match type_as_str {
|
||||
match type_without_array.trim() {
|
||||
"raw" => None,
|
||||
"bool" => Some(Type::Bool(create_type_info())),
|
||||
"integer" | "number" | "int" => Some(Type::Number(create_type_info())),
|
||||
|
|
|
@ -10,7 +10,7 @@ mod foo {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let _ = foo::api_impl::ApplicationPreferencesBittorrentProtocol::TCP;
|
||||
let _ = foo::api_impl::application::preferences::BittorrentProtocol::TCP;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user