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 {
|
fn generate_struct_field(&self) -> TokenStream {
|
||||||
let name_snake = self.name_snake();
|
let name_snake = self.name_snake();
|
||||||
let type_name = util::to_ident(&self.to_owned_type());
|
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();
|
let orig_name = self.name();
|
||||||
|
|
||||||
util::add_docs(
|
util::add_docs(
|
||||||
&self.get_type_info().description,
|
&self.get_type_info().description,
|
||||||
quote! {
|
quote! {
|
||||||
#[serde(rename = #orig_name)]
|
#[serde(rename = #orig_name)]
|
||||||
pub #name_snake: #type_name
|
pub #name_snake: #type_
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -292,7 +297,10 @@ impl<'a> GroupMethod<'a> {
|
||||||
None => return quote! {},
|
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! {
|
quote! {
|
||||||
#[derive(Debug, serde::Deserialize)]
|
#[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 method_url = format!("/api/v2/{}/{}", self.group.url, self.method.url);
|
||||||
|
|
||||||
let (response_type, response_parse) = match self.method.types.response() {
|
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() }),
|
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(
|
Number(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "id",
|
name: "id",
|
||||||
is_optional: false,
|
|
||||||
is_list: false,
|
|
||||||
description: Some(
|
description: Some(
|
||||||
"ID of the search job",
|
"ID of the search job",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Number(
|
Number(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "limit",
|
name: "limit",
|
||||||
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",
|
||||||
),
|
),
|
||||||
|
is_optional: true,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Number(
|
Number(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "offset",
|
name: "offset",
|
||||||
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)",
|
||||||
),
|
),
|
||||||
|
is_optional: true,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Object(
|
Object(
|
||||||
|
@ -49,71 +50,71 @@ ApiMethod {
|
||||||
String(
|
String(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "descrLink",
|
name: "descrLink",
|
||||||
is_optional: false,
|
|
||||||
is_list: false,
|
|
||||||
description: Some(
|
description: Some(
|
||||||
"URL of the torrent's description page",
|
"URL of the torrent's description page",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
String(
|
String(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "fileName",
|
name: "fileName",
|
||||||
is_optional: false,
|
|
||||||
is_list: false,
|
|
||||||
description: Some(
|
description: Some(
|
||||||
"Name of the file",
|
"Name of the file",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Number(
|
Number(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "fileSize",
|
name: "fileSize",
|
||||||
is_optional: false,
|
|
||||||
is_list: false,
|
|
||||||
description: Some(
|
description: Some(
|
||||||
"Size of the file in Bytes",
|
"Size of the file in Bytes",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
String(
|
String(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "fileUrl",
|
name: "fileUrl",
|
||||||
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)",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Number(
|
Number(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "nbLeechers",
|
name: "nbLeechers",
|
||||||
is_optional: false,
|
|
||||||
is_list: false,
|
|
||||||
description: Some(
|
description: Some(
|
||||||
"Number of leechers",
|
"Number of leechers",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Number(
|
Number(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "nbSeeders",
|
name: "nbSeeders",
|
||||||
is_optional: false,
|
|
||||||
is_list: false,
|
|
||||||
description: Some(
|
description: Some(
|
||||||
"Number of seeders",
|
"Number of seeders",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
String(
|
String(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "siteUrl",
|
name: "siteUrl",
|
||||||
is_optional: false,
|
|
||||||
is_list: false,
|
|
||||||
description: Some(
|
description: Some(
|
||||||
"URL of the torrent site",
|
"URL of the torrent site",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -126,36 +127,37 @@ ApiMethod {
|
||||||
Object {
|
Object {
|
||||||
type_info: TypeInfo {
|
type_info: TypeInfo {
|
||||||
name: "results",
|
name: "results",
|
||||||
is_optional: false,
|
|
||||||
is_list: false,
|
|
||||||
description: Some(
|
description: Some(
|
||||||
"Array of result objects- see table below",
|
"Array of result objects- see table below",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: true,
|
||||||
},
|
},
|
||||||
ref_type: "Result",
|
ref_type: "",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
String(
|
String(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "status",
|
name: "status",
|
||||||
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)",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Number(
|
Number(
|
||||||
TypeInfo {
|
TypeInfo {
|
||||||
name: "total",
|
name: "total",
|
||||||
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",
|
||||||
),
|
),
|
||||||
|
is_optional: false,
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
is_list: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -53,9 +53,9 @@ impl CompositeTypes {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn response(&self) -> Option<&Vec<types::Type>> {
|
pub fn response(&self) -> Option<&TypeWithoutName> {
|
||||||
self.composite_types.iter().find_map(|type_| match type_ {
|
self.composite_types.iter().find_map(|type_| match type_ {
|
||||||
CompositeType::Response(p) => Some(&p.types),
|
CompositeType::Response(p) => Some(p),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -104,11 +104,12 @@ pub struct TypeWithName {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TypeWithoutName {
|
pub struct TypeWithoutName {
|
||||||
pub types: Vec<types::Type>,
|
pub types: Vec<types::Type>,
|
||||||
|
pub is_list: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeWithoutName {
|
impl TypeWithoutName {
|
||||||
pub fn new(types: Vec<types::Type>) -> Self {
|
pub fn new(types: Vec<types::Type>, is_list: bool) -> Self {
|
||||||
Self { types }
|
Self { types, is_list }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,6 +271,7 @@ impl md_parser::Table {
|
||||||
|
|
||||||
Some(CompositeType::Response(TypeWithoutName::new(
|
Some(CompositeType::Response(TypeWithoutName::new(
|
||||||
self.to_types(),
|
self.to_types(),
|
||||||
|
input_name.to_lowercase().contains("array"),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +282,7 @@ impl md_parser::Table {
|
||||||
|
|
||||||
Some(CompositeType::Parameters(TypeWithoutName::new(
|
Some(CompositeType::Parameters(TypeWithoutName::new(
|
||||||
self.to_types(),
|
self.to_types(),
|
||||||
|
input_name.to_lowercase().contains("array"),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,4 +412,14 @@ mod tests {
|
||||||
fn enum_test() {
|
fn enum_test() {
|
||||||
run_test!("enum");
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TypeInfo {
|
pub struct TypeInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub is_optional: bool,
|
|
||||||
pub is_list: bool,
|
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
is_optional: bool,
|
||||||
|
is_list: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeInfo {
|
impl TypeInfo {
|
||||||
pub fn new(name: &str, is_optional: bool, is_list: 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(),
|
||||||
|
description,
|
||||||
is_optional,
|
is_optional,
|
||||||
is_list,
|
is_list,
|
||||||
description,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,10 @@ impl Type {
|
||||||
self.get_type_info().is_optional
|
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 {
|
pub fn get_type_info(&self) -> &TypeInfo {
|
||||||
match self {
|
match self {
|
||||||
Type::Number(t) => t,
|
Type::Number(t) => t,
|
||||||
|
@ -116,8 +120,21 @@ impl Type {
|
||||||
.clone()
|
.clone()
|
||||||
.map(|desc| desc.contains("array"))
|
.map(|desc| desc.contains("array"))
|
||||||
.unwrap_or(false);
|
.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| {
|
let create_object_type = |name: &str| {
|
||||||
Some(Type::Object(Object {
|
Some(Type::Object(Object {
|
||||||
|
@ -126,7 +143,7 @@ impl Type {
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
match type_as_str {
|
match type_without_array.trim() {
|
||||||
"raw" => None,
|
"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())),
|
||||||
|
|
|
@ -10,7 +10,7 @@ mod foo {
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let _ = foo::api_impl::ApplicationPreferencesBittorrentProtocol::TCP;
|
let _ = foo::api_impl::application::preferences::BittorrentProtocol::TCP;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user