1use crate::Result;
2use serde::{de::DeserializeOwned, Deserialize, Serialize};
3use serde_json::{json, Value};
4
5pub trait ApiTrait {
6 fn url(&self) -> String;
7 fn token(&self) -> String;
8}
9
10#[derive(Deserialize, Debug, PartialEq, Default, Clone)]
11pub struct ApiParam {
12 pub url: String,
13 pub token: String,
14}
15
16#[derive(Debug, PartialEq)]
17pub struct Api {
18 pub(self) params: ApiParam,
19 pub data: DataApi,
20}
21
22impl Api {
23 pub(crate) fn new(api: ApiParam) -> Api {
24 let params: ApiParam = api.clone();
25 Api {
26 params: params.clone(),
27 data: DataApi {
28 params: params.clone(),
29 },
30 }
31 }
32}
33
34impl ApiTrait for Api {
35 fn url(&self) -> String {
36 self.params.url.clone()
37 }
38
39 fn token(&self) -> String {
40 self.params.token.clone()
41 }
42}
43
44pub trait CollectionGetter: ApiTrait + Sized {
45 fn coll(&self, coll: &str) -> Collection {
46 Collection {
47 coll: coll.to_string(),
48 api: ApiParam {
49 url: self.url(),
50 token: self.token(),
51 },
52 }
53 }
54}
55
56pub struct Collection {
57 coll: String,
58 api: ApiParam,
59}
60
61impl Collection {
62 pub fn get_doc<T: Doc>(&self, id: &str) -> Result<T> {
63 log::debug!("get_doc {}[{}]", self.coll, id);
64 let request_url = format!(
65 "{url}/app-api/v1/data/colls/{coll}/docs/{id}",
66 url = self.api.url,
67 id = id,
68 coll = self.coll
69 );
70
71 ureq::get(request_url.as_str())
72 .set(
73 "Authorization",
74 format!("Bearer {}", self.api.token).as_str(),
75 )
76 .call()?
77 .into_json()
78 .map_err(|e| e.into())
79 }
80
81 pub fn create_doc<T: Doc>(&self, doc: T) -> Result<T> {
82 log::debug!("create_doc {}", serde_json::to_string(&doc).unwrap());
83
84 let request_url = format!(
85 "{url}/app-api/v1/data/colls/{coll}/docs",
86 url = self.api.url,
87 coll = self.coll
88 );
89
90 ureq::post(request_url.as_str())
91 .set(
92 "Authorization",
93 format!("Bearer {}", self.api.token).as_str(),
94 )
95 .send_json(doc)?
96 .into_json()
97 .map_err(|e| e.into())
98 }
99
100 pub fn update_doc<T: Doc>(&self, doc: T) -> Result<T> {
101 log::debug!("update_doc {}", serde_json::to_string(&doc).unwrap());
102
103 let request_url = format!(
104 "{url}/app-api/v1/data/colls/{coll}/docs/{id}",
105 url = self.api.url,
106 id = doc.id().unwrap(),
107 coll = self.coll
108 );
109
110 ureq::put(request_url.as_str())
111 .set(
112 "Authorization",
113 format!("Bearer {}", self.api.token).as_str(),
114 )
115 .send_json(doc)?
116 .into_json()
117 .map_err(|e| e.into())
118 }
119
120 pub fn delete_doc<T: Doc>(&self, doc: T) -> Result<()> {
121 let request_url = format!(
122 "{url}/app-api/v1/data/colls/{coll}/docs/{id}",
123 url = self.api.url,
124 id = doc.id().unwrap(),
125 coll = self.coll
126 );
127
128 ureq::delete(request_url.as_str())
129 .set(
130 "Authorization",
131 format!("Bearer {}", self.api.token).as_str(),
132 )
133 .call()?;
134
135 Ok(())
136 }
137
138 pub fn find<T: Doc, Q: Serialize, P: Serialize>(
139 &self,
140 query: Q,
141 projection: Option<P>,
142 ) -> Result<Vec<T>> {
143 log::debug!("find {}", serde_json::to_string(&query).unwrap());
144 let request_url = format!(
145 "{url}/app-api/v1/data/colls/{coll}/find",
146 url = self.api.url,
147 coll = self.coll
148 );
149
150 ureq::post(request_url.as_str())
151 .set(
152 "Authorization",
153 format!("Bearer {}", self.api.token).as_str(),
154 )
155 .send_json(json!({ "query": query, "projection": projection }))?
156 .into_json()
157 .map_err(|e| e.into())
158 }
159
160 pub fn update_many<T: Doc, Q: Serialize, U: Serialize>(
161 &self,
162 filter: Q,
163 update: U,
164 ) -> Result<Vec<T>> {
165 log::debug!(
166 "updateMany {}, {}",
167 serde_json::to_string(&filter).unwrap(),
168 serde_json::to_string(&update).unwrap()
169 );
170 let request_url = format!(
171 "{url}/app-api/v1/data/colls/{coll}/updateMany",
172 url = self.api.url,
173 coll = self.coll
174 );
175
176 ureq::post(request_url.as_str())
177 .set(
178 "Authorization",
179 format!("Bearer {}", self.api.token).as_str(),
180 )
181 .send_json(json!({"filter": filter, "update": update}))?
182 .into_json()
183 .map_err(|e| e.into())
184 }
185}
186
187#[derive(Debug, PartialEq)]
188pub struct DataApi {
189 pub(self) params: ApiParam,
190}
191
192impl DataApi {
193 pub fn start_transaction(self) -> Result<Transaction> {
194 log::debug!("start_transaction");
195
196 let request_url = format!("{url}/app/transaction", url = self.url());
197
198 ureq::post(request_url.as_str())
199 .set("Authorization", format!("Bearer {}", self.token()).as_str())
200 .send_json(json!({}))?
201 .into_string()
202 .map(|token| Transaction {
203 params: self.params.clone(),
204 token,
205 })
206 .map_err(|e| e.into())
207 }
208}
209
210impl ApiTrait for DataApi {
211 fn url(&self) -> String {
212 self.params.url.clone()
213 }
214
215 fn token(&self) -> String {
216 self.params.token.clone()
217 }
218}
219
220impl CollectionGetter for DataApi {}
221
222#[derive(Debug, PartialEq)]
223pub struct Transaction {
224 pub(self) params: ApiParam,
225 token: String,
226}
227
228impl ApiTrait for Transaction {
229 fn url(&self) -> String {
230 self.params.url.clone()
231 }
232
233 fn token(&self) -> String {
234 self.token.clone()
235 }
236}
237
238impl CollectionGetter for Transaction {}
239
240impl Transaction {
241 pub fn commit(&self) -> Result<()> {
242 log::debug!("transaction commit");
243
244 let request_url = format!("{url}/app/transaction/commit", url = self.url());
245
246 ureq::post(request_url.as_str())
247 .set("Authorization", format!("Bearer {}", self.token()).as_str())
248 .send_json(json!({}))?
249 .into_string()
250 .map(|_| ())
251 .map_err(|e| e.into())
252 }
253
254 pub fn abort(&self) -> Result<()> {
255 log::debug!("transaction commit");
256
257 let request_url = format!("{url}/app/transaction/abort", url = self.url());
258
259 ureq::post(request_url.as_str())
260 .set("Authorization", format!("Bearer {}", self.token()).as_str())
261 .send_json(json!({}))?
262 .into_string()
263 .map(|_| ())
264 .map_err(|e| e.into())
265 }
266}
267
268pub trait Doc: Sized + DeserializeOwned + Serialize + 'static + Clone {
269 fn id(&self) -> Option<String>;
270}
271
272impl Doc for Value {
273 fn id(&self) -> Option<String> {
274 None
275 }
276}