1use async_stream::try_stream;
2use futures_core::stream::BoxStream;
3use reqwest::Method;
4use serde::Serialize;
5use serde_json::{Map, Value};
6
7use crate::client::Client;
8use crate::error::{Error, Result};
9use crate::models::{NewUser, User};
10
11const PATH: &str = "api/v1/users";
12
13#[derive(Debug)]
15pub struct UsersApi<'a> {
16 client: &'a Client,
17}
18
19impl<'a> UsersApi<'a> {
20 pub(crate) fn new(client: &'a Client) -> Self {
21 Self { client }
22 }
23
24 pub async fn me(&self) -> Result<User> {
26 let req = self.client.request(Method::GET, &format!("{PATH}/me"));
27 self.client.send_json(req).await
28 }
29
30 pub async fn get(&self, id: u64) -> Result<User> {
32 let req = self.client.request(Method::GET, &format!("{PATH}/{id}"));
33 self.client.send_json(req).await
34 }
35
36 pub fn list(&self) -> ListUsers<'a> {
38 ListUsers {
39 client: self.client,
40 per_page: 100,
41 }
42 }
43
44 pub fn search(&self, query: impl Into<String>) -> SearchUsers<'a> {
46 SearchUsers {
47 client: self.client,
48 query: query.into(),
49 per_page: 100,
50 }
51 }
52
53 pub async fn create(&self, user: &NewUser) -> Result<User> {
55 let req = self.client.request(Method::POST, PATH).json(user);
56 self.client.send_json(req).await
57 }
58
59 pub async fn update<P: Serialize + ?Sized>(&self, id: u64, patch: &P) -> Result<User> {
61 let req = self
62 .client
63 .request(Method::PUT, &format!("{PATH}/{id}"))
64 .json(patch);
65 self.client.send_json(req).await
66 }
67
68 pub async fn set_field(
72 &self,
73 id: u64,
74 field: &str,
75 value: impl Into<Value>,
76 ) -> Result<User> {
77 let value: Value = value.into();
78 let mut body = Map::new();
79 body.insert(field.to_string(), value.clone());
80 let updated = self.update(id, &Value::Object(body)).await?;
81 let actual = updated.extra.get(field).cloned();
82 if actual.as_ref() != Some(&value) {
83 return Err(Error::WriteVerificationFailed {
84 field: field.into(),
85 actual,
86 });
87 }
88 Ok(updated)
89 }
90
91 pub async fn delete(&self, id: u64) -> Result<()> {
93 let req = self.client.request(Method::DELETE, &format!("{PATH}/{id}"));
94 self.client.send_unit(req).await
95 }
96}
97
98#[derive(Debug)]
100pub struct ListUsers<'a> {
101 client: &'a Client,
102 per_page: u32,
103}
104
105impl<'a> ListUsers<'a> {
106 pub fn per_page(mut self, n: u32) -> Self {
108 self.per_page = n;
109 self
110 }
111
112 pub async fn page(&self, page: u32) -> Result<Vec<User>> {
114 let req = self.client.request(Method::GET, PATH).query(&[
115 ("page", page.to_string()),
116 ("per_page", self.per_page.to_string()),
117 ]);
118 self.client.send_json(req).await
119 }
120
121 pub fn stream(self) -> BoxStream<'a, Result<User>> {
123 let client = self.client;
124 let per_page = self.per_page;
125 Box::pin(try_stream! {
126 let mut page = 1u32;
127 loop {
128 let req = client.request(Method::GET, PATH).query(&[
129 ("page", page.to_string()),
130 ("per_page", per_page.to_string()),
131 ]);
132 let chunk: Vec<User> = client.send_json(req).await?;
133 let len = chunk.len() as u32;
134 for u in chunk { yield u; }
135 if len < per_page { break; }
136 page += 1;
137 }
138 })
139 }
140}
141
142#[derive(Debug)]
144pub struct SearchUsers<'a> {
145 client: &'a Client,
146 query: String,
147 per_page: u32,
148}
149
150impl<'a> SearchUsers<'a> {
151 pub fn per_page(mut self, n: u32) -> Self {
153 self.per_page = n;
154 self
155 }
156
157 pub async fn page(&self, page: u32) -> Result<Vec<User>> {
159 let req = self
160 .client
161 .request(Method::GET, &format!("{PATH}/search"))
162 .query(&[
163 ("query", self.query.clone()),
164 ("page", page.to_string()),
165 ("per_page", self.per_page.to_string()),
166 ]);
167 self.client.send_json(req).await
168 }
169
170 pub fn stream(self) -> BoxStream<'a, Result<User>> {
172 let client = self.client;
173 let per_page = self.per_page;
174 let query = self.query;
175 Box::pin(try_stream! {
176 let mut page = 1u32;
177 loop {
178 let req = client
179 .request(Method::GET, &format!("{PATH}/search"))
180 .query(&[
181 ("query", query.clone()),
182 ("page", page.to_string()),
183 ("per_page", per_page.to_string()),
184 ]);
185 let chunk: Vec<User> = client.send_json(req).await?;
186 let len = chunk.len() as u32;
187 for u in chunk { yield u; }
188 if len < per_page { break; }
189 page += 1;
190 }
191 })
192 }
193}