1use bon::Builder;
2use bytes::Bytes;
3use http::StatusCode;
4
5use crate::{
6 executor::Executor,
7 models::{FactionChainsResponse, FactionId},
8};
9
10pub mod models;
11
12#[derive(Default)]
13pub struct ApiRequest<D = ()> {
14 pub disriminant: D,
15 pub path: String,
16 pub parameters: Vec<(&'static str, String)>,
17}
18
19impl<D> ApiRequest<D> {
20 pub fn url(&self) -> String {
21 let mut url = format!("https://api.torn.com/v2{}?", self.path);
22
23 for (name, value) in &self.parameters {
24 url.push_str(&format!("{name}={value}"));
25 }
26
27 url
28 }
29}
30
31pub struct ApiResponse<D = ()> {
32 pub discriminant: D,
33 pub body: Option<Bytes>,
34 pub status: StatusCode,
35}
36
37pub trait IntoRequest: Send {
38 type Discriminant: Send;
39 type Response: for<'de> serde::Deserialize<'de> + Send;
40 fn into_request(self) -> ApiRequest<Self::Discriminant>;
41}
42
43pub struct FactionScope<'e, E>(&'e E)
44where
45 E: Executor;
46
47impl<E> FactionScope<'_, E>
48where
49 E: Executor,
50{
51 pub async fn chains_for_id<S>(
52 &self,
53 id: FactionId,
54 builder: impl FnOnce(
55 FactionChainsRequestBuilder<faction_chains_request_builder::Empty>,
56 ) -> FactionChainsRequestBuilder<S>,
57 ) -> Result<FactionChainsResponse, E::Error>
58 where
59 S: faction_chains_request_builder::IsComplete,
60 {
61 let r = builder(FactionChainsRequest::with_id(id)).build();
62
63 self.0.fetch(r).await
64 }
65}
66
67#[derive(Builder)]
68#[builder(start_fn = with_id)]
69pub struct FactionChainsRequest {
70 #[builder(start_fn)]
71 pub id: FactionId,
72 pub limit: Option<usize>,
73}
74
75impl IntoRequest for FactionChainsRequest {
76 type Discriminant = FactionId;
77 type Response = FactionChainsResponse;
78 fn into_request(self) -> ApiRequest<Self::Discriminant> {
79 ApiRequest {
80 disriminant: self.id,
81 path: format!("/faction/{}/chains", self.id),
82 parameters: self
83 .limit
84 .into_iter()
85 .map(|l| ("limit", l.to_string()))
86 .collect(),
87 }
88 }
89}
90
91#[cfg(test)]
92mod test {
93 use crate::executor::ReqwestClient;
94
95 use super::*;
96
97 #[tokio::test]
98 async fn test_request() {
99 let client = ReqwestClient::new("nAYRXaoqzBAGalWt");
100
101 let r = models::TornItemsForIdsRequest::builder("1".to_owned()).build();
102 client.fetch(r).await.unwrap();
103 }
104}