use async_stream::try_stream;
use futures_core::stream::BoxStream;
use reqwest::Method;
use serde::Serialize;
use serde_json::{Map, Value};
use crate::client::Client;
use crate::error::{Error, Result};
use crate::models::{NewUser, User};
const PATH: &str = "api/v1/users";
#[derive(Debug)]
pub struct UsersApi<'a> {
client: &'a Client,
}
impl<'a> UsersApi<'a> {
pub(crate) fn new(client: &'a Client) -> Self {
Self { client }
}
pub async fn me(&self) -> Result<User> {
let req = self.client.request(Method::GET, &format!("{PATH}/me"));
self.client.send_json(req).await
}
pub async fn get(&self, id: u64) -> Result<User> {
let req = self.client.request(Method::GET, &format!("{PATH}/{id}"));
self.client.send_json(req).await
}
pub fn list(&self) -> ListUsers<'a> {
ListUsers {
client: self.client,
per_page: 100,
}
}
pub fn search(&self, query: impl Into<String>) -> SearchUsers<'a> {
SearchUsers {
client: self.client,
query: query.into(),
per_page: 100,
}
}
pub async fn create(&self, user: &NewUser) -> Result<User> {
let req = self.client.request(Method::POST, PATH).json(user);
self.client.send_json(req).await
}
pub async fn update<P: Serialize + ?Sized>(&self, id: u64, patch: &P) -> Result<User> {
let req = self
.client
.request(Method::PUT, &format!("{PATH}/{id}"))
.json(patch);
self.client.send_json(req).await
}
pub async fn set_field(
&self,
id: u64,
field: &str,
value: impl Into<Value>,
) -> Result<User> {
let value: Value = value.into();
let mut body = Map::new();
body.insert(field.to_string(), value.clone());
let updated = self.update(id, &Value::Object(body)).await?;
let actual = updated.extra.get(field).cloned();
if actual.as_ref() != Some(&value) {
return Err(Error::WriteVerificationFailed {
field: field.into(),
actual,
});
}
Ok(updated)
}
pub async fn delete(&self, id: u64) -> Result<()> {
let req = self.client.request(Method::DELETE, &format!("{PATH}/{id}"));
self.client.send_unit(req).await
}
}
#[derive(Debug)]
pub struct ListUsers<'a> {
client: &'a Client,
per_page: u32,
}
impl<'a> ListUsers<'a> {
pub fn per_page(mut self, n: u32) -> Self {
self.per_page = n;
self
}
pub async fn page(&self, page: u32) -> Result<Vec<User>> {
let req = self.client.request(Method::GET, PATH).query(&[
("page", page.to_string()),
("per_page", self.per_page.to_string()),
]);
self.client.send_json(req).await
}
pub fn stream(self) -> BoxStream<'a, Result<User>> {
let client = self.client;
let per_page = self.per_page;
Box::pin(try_stream! {
let mut page = 1u32;
loop {
let req = client.request(Method::GET, PATH).query(&[
("page", page.to_string()),
("per_page", per_page.to_string()),
]);
let chunk: Vec<User> = client.send_json(req).await?;
let len = chunk.len() as u32;
for u in chunk { yield u; }
if len < per_page { break; }
page += 1;
}
})
}
}
#[derive(Debug)]
pub struct SearchUsers<'a> {
client: &'a Client,
query: String,
per_page: u32,
}
impl<'a> SearchUsers<'a> {
pub fn per_page(mut self, n: u32) -> Self {
self.per_page = n;
self
}
pub async fn page(&self, page: u32) -> Result<Vec<User>> {
let req = self
.client
.request(Method::GET, &format!("{PATH}/search"))
.query(&[
("query", self.query.clone()),
("page", page.to_string()),
("per_page", self.per_page.to_string()),
]);
self.client.send_json(req).await
}
pub fn stream(self) -> BoxStream<'a, Result<User>> {
let client = self.client;
let per_page = self.per_page;
let query = self.query;
Box::pin(try_stream! {
let mut page = 1u32;
loop {
let req = client
.request(Method::GET, &format!("{PATH}/search"))
.query(&[
("query", query.clone()),
("page", page.to_string()),
("per_page", per_page.to_string()),
]);
let chunk: Vec<User> = client.send_json(req).await?;
let len = chunk.len() as u32;
for u in chunk { yield u; }
if len < per_page { break; }
page += 1;
}
})
}
}