v2
This commit is contained in:
parent
a03c1891c8
commit
a0ddaf89a9
5 changed files with 197 additions and 168 deletions
|
|
@ -14,5 +14,6 @@ restson = "1.5.0"
|
|||
rpassword = "7.4.0"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.149"
|
||||
spond-macros = { version = "0.1.0", path = "../macros" }
|
||||
tokio = { version = "1.49.0", features = ["macros", "rt-multi-thread"] }
|
||||
url = "2.5.8"
|
||||
|
|
|
|||
|
|
@ -1,32 +1,34 @@
|
|||
//use bon::Builder;
|
||||
//use chrono::{DateTime,Utc};
|
||||
use chrono::{DateTime,Utc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
//use restson::{RestClient, RestPath, Error};
|
||||
//
|
||||
//pub enum Order {
|
||||
// Ascending,
|
||||
// Descending,
|
||||
//}
|
||||
//
|
||||
//impl AsRef<str> for Order {
|
||||
// fn as_ref(&self) -> &str {
|
||||
// match self {
|
||||
// Self::Ascending => "asc",
|
||||
// Self::Descending => "desc",
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//impl From<bool> for Order {
|
||||
// fn from(ascending: bool) -> Self {
|
||||
// if ascending {
|
||||
// Self::Ascending
|
||||
// } else {
|
||||
// Self::Descending
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
#[derive(serde::Deserialize)]
|
||||
#[derive(Serialize)]
|
||||
pub enum Order {
|
||||
Ascending,
|
||||
Descending,
|
||||
}
|
||||
|
||||
impl AsRef<str> for Order {
|
||||
fn as_ref(&self) -> &str {
|
||||
match self {
|
||||
Self::Ascending => "asc",
|
||||
Self::Descending => "desc",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Order {
|
||||
fn from(ascending: bool) -> Self {
|
||||
if ascending {
|
||||
Self::Ascending
|
||||
} else {
|
||||
Self::Descending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Spond {
|
||||
id: String,
|
||||
|
||||
|
|
@ -46,29 +48,42 @@ pub struct Spond {
|
|||
// min_end_timestamp=Option<DateTime<Utc>>,
|
||||
// max_end_timestamp=Option<DateTime<Utc>>,
|
||||
//) -> Get<(), Vec<Spond>> {
|
||||
//
|
||||
//}
|
||||
//
|
||||
//struct Sponds(Query);
|
||||
//
|
||||
//async pub fn sponds(
|
||||
// #[builder(finish_fn)]
|
||||
// client: &restson::RestClient, E
|
||||
//
|
||||
//
|
||||
|
||||
crate::get!(search(
|
||||
//crate::get!(sponds(
|
||||
// comments: bool,
|
||||
// hidden: bool,
|
||||
// add_profile_info: bool,
|
||||
// scheduled,
|
||||
// #[builder(into, default=Order::Ascending)] order: Order,
|
||||
// #[builder(default=20)]max: usize,
|
||||
// min_end_timestamp: Option<DateTime<Utc>>,
|
||||
// max_end_timestamp: Option<DateTime<Utc>>,
|
||||
// ),
|
||||
// () => "sponds" -> Vec<Spond>);
|
||||
|
||||
#[spond_macros::endpoint((id:u128):"/spond/{id:032X}/info", (eid:u128, uid:u128): "/spond/{eid:032X}/response/{uid:032X}")]
|
||||
pub async fn sponds(result: serde_json::Value,
|
||||
#[query] comments: Option<bool>,
|
||||
#[query] hidden: Option<bool>,
|
||||
#[body] min_end_timestamp: Option<DateTime<Utc>>,
|
||||
) -> serde_json::Value {
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
crate::post!(post(
|
||||
comments: bool,
|
||||
hidden: bool,
|
||||
add_profile_info: bool,
|
||||
scheduled: bool,
|
||||
#[builder(into)] order: Order,
|
||||
#[builder(default=20)]max: usize,
|
||||
),
|
||||
)
|
||||
min_end_timestamp: Option<DateTime<Utc>>,
|
||||
max_end_timestamp: Option<DateTime<Utc>>,
|
||||
() => "sponds" -> Vec<Spond>);
|
||||
|
||||
*/
|
||||
//impl Search {
|
||||
// with_comments(
|
||||
//#[bon::builder]
|
||||
|
|
|
|||
|
|
@ -45,17 +45,29 @@ async fn main() -> Result<()> {
|
|||
let client = Cli::parse().client().await?;
|
||||
|
||||
// https://api.spond.com/core/v1/sponds?includeComments=true&includeHidden=false&addProfileInfo=true&scheduled=true&order=asc&max=20&prevId=F94829E35A9B4A48A042646C8B658B01&minStartTimestamp=2026-04-11T09:45:00Z&minEndTimestamp=2026-02-26T23:00:00.001Z
|
||||
let query = [
|
||||
("includeComments", "true"),
|
||||
("includeHidden", "false"),
|
||||
("addProfileInfo", "true"),
|
||||
("scheduled", "true"),
|
||||
("order", "asc"),
|
||||
("max", "20"),
|
||||
];
|
||||
|
||||
for spond in client.get_with::<_, Sponds>((), &query).await?.into_inner().0 {
|
||||
println!("{spond:?}");
|
||||
if false {
|
||||
let query = [
|
||||
("includeComments", "true"),
|
||||
("includeHidden", "false"),
|
||||
("addProfileInfo", "true"),
|
||||
("scheduled", "true"),
|
||||
("order", "asc"),
|
||||
("max", "20"),
|
||||
];
|
||||
|
||||
for spond in client.get_with::<_, Sponds>((), &query).await?.into_inner().0 {
|
||||
println!("{spond:?}");
|
||||
}
|
||||
} else {
|
||||
let request = api::sponds()
|
||||
.comments(true)
|
||||
.hidden(false)
|
||||
.add_profile_info(false)
|
||||
.scheduled(true)
|
||||
;
|
||||
for spond in request.call(&client).await? {
|
||||
println!("{spond:?}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ macro_rules! get {
|
|||
// Case 1: no query
|
||||
(
|
||||
$name:ident,
|
||||
( $( $arg:ident : $arg_ty:ty ),* ) => $path:literal -> $out:ty $(,)?
|
||||
( $( $arg:ident : $arg_ty:ty ),* $(,)? ) => $path:literal -> $out:ty
|
||||
) => {
|
||||
get!($name(), ( $( $arg : $arg_ty ),* ) => $path -> $out);
|
||||
};
|
||||
|
|
@ -11,7 +11,7 @@ macro_rules! get {
|
|||
// Case 2: empty query ()
|
||||
(
|
||||
$name:ident (),
|
||||
( $( $arg:ident : $arg_ty:ty ),* ) => $path:literal -> $out:ty $(,)?
|
||||
( $( $arg:ident : $arg_ty:ty ),* $(,)? ) => $path:literal -> $out:ty
|
||||
) => {
|
||||
#[bon::builder]
|
||||
pub fn $name(
|
||||
|
|
@ -35,42 +35,30 @@ macro_rules! get {
|
|||
}
|
||||
};
|
||||
|
||||
// Case 3: query with flags / mixed types
|
||||
// Case 3: query with optional attributes
|
||||
(
|
||||
$name:ident ( $( $query:tt ),* $(,)? ),
|
||||
( $( $arg:ident : $arg_ty:ty ),* ) => $path:literal -> $out:ty $(,)?
|
||||
$name:ident ( $( $(#[$attr:meta])* $query_ident:ident $(: $query_ty:ty )? ),* $(,)? ),
|
||||
( $( $arg:ident : $arg_ty:ty ),* $(,)? ) => $path:literal -> $out:ty
|
||||
) => {
|
||||
#[bon::builder]
|
||||
pub fn $name(
|
||||
#[builder(finish_fn)] client: &restson::RestClient,
|
||||
$( #[builder(finish_fn)] $arg: $arg_ty, )*
|
||||
$(
|
||||
get!(@query_field $query)
|
||||
$(#[$attr])* $query_ident : $crate::get!( @query_type $( $query_ty )? ) ,
|
||||
)*
|
||||
) -> impl std::future::Future<Output = Result<$out, restson::Error>> + '_ {
|
||||
#[derive(serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct Query<'a> {
|
||||
$(
|
||||
get!(@query_field_struct $query)
|
||||
)*
|
||||
}
|
||||
|
||||
impl Query<'_> {
|
||||
fn as_pairs(&self) -> Vec<(&str, String)> {
|
||||
let mut out = Vec::new();
|
||||
$(
|
||||
get!(@push_pair out, self, $query)
|
||||
)*
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
let query = Query {
|
||||
// Build Vec<(String,String)> dynamically using serde_json::to_string
|
||||
let query_pairs: Vec<(String, String)> = vec![
|
||||
$(
|
||||
get!(@query_field_init $query)
|
||||
)*
|
||||
};
|
||||
{
|
||||
let val = serde_json::to_string(&$query_ident)
|
||||
.expect("failed to serialize query param");
|
||||
(stringify!($query_ident).to_string(), val)
|
||||
}
|
||||
),*
|
||||
];
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct RP($out);
|
||||
|
|
@ -83,28 +71,18 @@ macro_rules! get {
|
|||
}
|
||||
|
||||
async move {
|
||||
let result = client.get_with::<_, RP>(( $( $arg ),* ), &query.as_pairs()).await?;
|
||||
// Convert Vec<(String,String)> to Vec<(&str,&str)>
|
||||
let ref_pairs: Vec<(&str, &str)> = query_pairs
|
||||
.iter()
|
||||
.map(|(k, v)| (k.as_str(), v.as_str()))
|
||||
.collect();
|
||||
|
||||
let result = client.get_with::<_, RP>(( $( $arg ),* ), &ref_pairs).await?;
|
||||
Ok(result.into_inner().0)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Query helpers
|
||||
(@query_field $field:ident) => { $field: Option<bool>, };
|
||||
(@query_field $field:ident = $ty:ty) => { $field: $ty, };
|
||||
|
||||
(@query_field_struct $field:ident) => { $field: Option<bool>, };
|
||||
(@query_field_struct $field:ident = $ty:ty) => { $field: $ty, };
|
||||
|
||||
(@query_field_init $field:ident) => { $field, };
|
||||
(@query_field_init $field:ident = $ty:ty) => { $field, };
|
||||
|
||||
(@push_pair $vec:ident, $self:ident, $field:ident = $ty:ty) => {
|
||||
$vec.push((stringify!($field), $self.$field.to_string()));
|
||||
};
|
||||
(@push_pair $vec:ident, $self:ident, $field:ident) => {
|
||||
if let Some(v) = &$self.$field {
|
||||
$vec.push((stringify!($field), v.to_string()));
|
||||
}
|
||||
};
|
||||
( @query_type ) => { Option<bool> };
|
||||
( @query_type $ty:ty) => { $ty };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue