xo_api_client/api/
xo.rs

1use std::{collections::BTreeMap, sync::Arc};
2
3use crate::{
4    procedure_object,
5    types::{XoObject, XoObjectMap},
6    RpcError,
7};
8
9use jsonrpsee_types::{traits::Client, v2::params::ParamsSer, JsonValue};
10use jsonrpsee_ws_client::WsClient;
11
12use crate::procedure_args;
13
14pub struct XoProcedures {
15    pub(crate) inner: Arc<WsClient>,
16}
17
18impl XoProcedures {
19    /// Get all objects from server
20    /// * `R` is a type that can hold that entire result set with all different types
21    /// * `filter` is an optional filter
22    /// * `limit` is an optional max limit on number of results
23    /// xo-cli: xo.getAllObjects [filter=<object>] [limit=<number>] [ndjson=<boolean>]
24    pub async fn get_all_objects<R: serde::de::DeserializeOwned>(
25        &self,
26        filter: impl Into<Option<serde_json::Map<String, JsonValue>>>,
27        limit: impl Into<Option<usize>>,
28    ) -> Result<R, RpcError> {
29        let args = match (filter.into(), limit.into()) {
30            (Some(filter), Some(limit)) => {
31                procedure_args! { "filter" => filter, "limit" => limit }
32            }
33            (Some(filter), None) => procedure_args! { "filter" => filter },
34            (None, Some(limit)) => procedure_args! { "limit" => limit },
35            (None, None) => procedure_args! {},
36        };
37
38        self.inner
39            .request("xo.getAllObjects", Some(ParamsSer::Map(args)))
40            .await
41    }
42
43    /// Get all objects of specified type from server
44    /// * `R` is a type that can represent that collection of objects
45    /// * `filter` is an optional filter
46    /// * `limit` is an optional max limit on number of results
47    pub async fn get_objects<R: XoObjectMap>(
48        &self,
49        filter: impl Into<Option<serde_json::Map<String, JsonValue>>>,
50        limit: impl Into<Option<usize>>,
51    ) -> Result<R, RpcError> {
52        let mut filter = filter.into().unwrap_or_default();
53        filter.insert("type".to_string(), R::Object::OBJECT_TYPE.into());
54
55        self.get_all_objects(filter, limit).await
56    }
57
58    /// Get single object of specified type from server
59    /// * `R` is a type that can represent that type of object
60    /// * `id` is the id of the object
61    pub async fn get_object<R: XoObject>(
62        &self,
63        id: R::IdType,
64    ) -> Result<Option<R>, GetSingleObjectError>
65    where
66        R::IdType: Ord,
67    {
68        let filter = procedure_object!(
69            "id" => id.clone(),
70            "type" => R::OBJECT_TYPE.to_string()
71        );
72
73        // TODO: Can we get rid of the BTreeMap here?
74        let mut result: BTreeMap<R::IdType, R> = self
75            .get_all_objects(filter, Some(2))
76            .await
77            .map_err(GetSingleObjectError::Rpc)?;
78
79        match result.remove(&id) {
80            None => Ok(None),
81            Some(vm) if result.is_empty() => Ok(Some(vm)),
82            _ => Err(GetSingleObjectError::MultipleMatches),
83        }
84    }
85}
86
87#[derive(Debug)]
88pub enum GetSingleObjectError {
89    MultipleMatches,
90    Rpc(RpcError),
91}