1use crate::auth::AuthManager;
4use crate::error::{Error, Result};
5use crate::http::HttpClient;
6use crate::schema::{CollectionMetadata, Schema};
7use crate::search::{DistinctValuesQuery, DistinctValuesResponse, SearchQuery, SearchResponse};
8use crate::types::{FieldType, Query, Record};
9use std::sync::Arc;
10use std::time::Duration;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct RateLimitInfo {
15 pub limit: usize,
17 pub remaining: usize,
19 pub reset: i64,
21}
22
23impl RateLimitInfo {
24 pub fn is_near_limit(&self) -> bool {
28 let threshold = (self.limit as f64 * 0.1) as usize;
29 self.remaining <= threshold
30 }
31
32 pub fn is_exceeded(&self) -> bool {
34 self.remaining == 0
35 }
36
37 pub fn remaining_percentage(&self) -> f64 {
39 (self.remaining as f64 / self.limit as f64) * 100.0
40 }
41}
42
43#[derive(Clone)]
45pub struct Client {
46 http: Arc<HttpClient>,
47 auth: Arc<AuthManager>,
48 schema_cache: Arc<crate::schema_cache::SchemaCache>,
50 base_url: String,
52}
53
54impl Client {
55 pub fn builder() -> ClientBuilder {
57 ClientBuilder::default()
58 }
59
60 pub async fn health_check(&self) -> Result<()> {
62 self.http.health_check().await
63 }
64
65 async fn execute_with_token_refresh<F, Fut, T>(&self, mut operation: F) -> Result<T>
67 where
68 F: FnMut(String) -> Fut,
69 Fut: std::future::Future<Output = Result<T>>,
70 {
71 let token = self.auth.get_token().await?;
73 match operation(token).await {
74 Ok(result) => Ok(result),
75 Err(Error::TokenExpired) => {
76 log::debug!("Token expired, refreshing and retrying...");
78 let new_token = self.auth.refresh_token().await?;
79 operation(new_token).await
80 }
81 Err(e) => Err(e),
82 }
83 }
84
85 pub async fn insert(
122 &self,
123 collection: &str,
124 record: Record,
125 options: Option<crate::options::InsertOptions>,
126 ) -> Result<Record> {
127 let collection = collection.to_string();
128 let http = self.http.clone();
129 self.execute_with_token_refresh(move |token| {
130 let collection = collection.clone();
131 let record = record.clone();
132 let http = http.clone();
133 let options = options.clone();
134 async move { http.insert(&collection, record, options, &token).await }
135 })
136 .await
137 }
138
139 pub async fn find(
175 &self,
176 collection: &str,
177 query: Query,
178 bypass_ripple: Option<bool>,
179 ) -> Result<Vec<Record>> {
180 let collection = collection.to_string();
181 let http = self.http.clone();
182 self.execute_with_token_refresh(move |token| {
183 let collection = collection.clone();
184 let query = query.clone();
185 let http = http.clone();
186 async move { http.find(&collection, query, &token, bypass_ripple).await }
187 })
188 .await
189 }
190
191 pub async fn find_by_id(
202 &self,
203 collection: &str,
204 id: &str,
205 bypass_ripple: Option<bool>,
206 ) -> Result<Record> {
207 let collection = collection.to_string();
208 let id = id.to_string();
209 let http = self.http.clone();
210 self.execute_with_token_refresh(move |token| {
211 let collection = collection.clone();
212 let id = id.clone();
213 let http = http.clone();
214 async move {
215 http.find_by_id(&collection, &id, &token, bypass_ripple)
216 .await
217 }
218 })
219 .await
220 }
221
222 pub async fn find_by_id_with_projection(
227 &self,
228 collection: &str,
229 id: &str,
230 select_fields: Option<Vec<String>>,
231 exclude_fields: Option<Vec<String>>,
232 ) -> Result<Record> {
233 let collection = collection.to_string();
234 let id = id.to_string();
235 let http = self.http.clone();
236 self.execute_with_token_refresh(move |token| {
237 let collection = collection.clone();
238 let id = id.clone();
239 let select_fields = select_fields.clone();
240 let exclude_fields = exclude_fields.clone();
241 let http = http.clone();
242 async move {
243 http.find_by_id_with_projection(
244 &collection,
245 &id,
246 select_fields.as_deref(),
247 exclude_fields.as_deref(),
248 &token,
249 )
250 .await
251 }
252 })
253 .await
254 }
255
256 pub async fn update(
269 &self,
270 collection: &str,
271 id: &str,
272 record: Record,
273 options: Option<crate::options::UpdateOptions>,
274 ) -> Result<Record> {
275 let collection = collection.to_string();
276 let id = id.to_string();
277 let http = self.http.clone();
278 self.execute_with_token_refresh(move |token| {
279 let collection = collection.clone();
280 let id = id.clone();
281 let record = record.clone();
282 let options = options.clone();
283 let http = http.clone();
284 async move { http.update(&collection, &id, record, options, &token).await }
285 })
286 .await
287 }
288
289 pub async fn update_with_action(
312 &self,
313 collection: &str,
314 id: &str,
315 action: &str,
316 field: &str,
317 value: FieldType,
318 ) -> Result<Record> {
319 let collection = collection.to_string();
320 let id = id.to_string();
321 let action = action.to_string();
322 let field = field.to_string();
323 let http = self.http.clone();
324 self.execute_with_token_refresh(move |token| {
325 let collection = collection.clone();
326 let id = id.clone();
327 let action = action.clone();
328 let field = field.clone();
329 let value = value.clone();
330 let http = http.clone();
331 async move {
332 http.update_with_action(&collection, &id, &action, &field, value, &token)
333 .await
334 }
335 })
336 .await
337 }
338
339 pub async fn update_with_action_sequence(
350 &self,
351 collection: &str,
352 id: &str,
353 actions: Vec<(String, String, FieldType)>,
354 ) -> Result<Record> {
355 let collection = collection.to_string();
356 let id = id.to_string();
357 let http = self.http.clone();
358 self.execute_with_token_refresh(move |token| {
359 let collection = collection.clone();
360 let id = id.clone();
361 let actions = actions.clone();
362 let http = http.clone();
363 async move {
364 http.update_with_action_sequence(&collection, &id, actions, &token)
365 .await
366 }
367 })
368 .await
369 }
370
371 pub async fn delete(
382 &self,
383 collection: &str,
384 id: &str,
385 bypass_ripple: Option<bool>,
386 ) -> Result<()> {
387 let collection = collection.to_string();
388 let id = id.to_string();
389 let http = self.http.clone();
390 self.execute_with_token_refresh(move |token| {
391 let collection = collection.clone();
392 let id = id.clone();
393 let http = http.clone();
394 async move { http.delete(&collection, &id, &token, bypass_ripple).await }
395 })
396 .await
397 }
398
399 pub async fn delete_with_options(
402 &self,
403 collection: &str,
404 id: &str,
405 options: crate::options::DeleteOptions,
406 ) -> Result<()> {
407 let collection = collection.to_string();
408 let id = id.to_string();
409 let http = self.http.clone();
410 self.execute_with_token_refresh(move |token| {
411 let collection = collection.clone();
412 let id = id.clone();
413 let options = options.clone();
414 let http = http.clone();
415 async move {
416 http.delete_with_options(&collection, &id, &token, &options)
417 .await
418 }
419 })
420 .await
421 }
422
423 pub async fn restore_deleted(&self, collection: &str, id: &str) -> Result<bool> {
456 let collection = collection.to_string();
457 let id = id.to_string();
458 let http = self.http.clone();
459 self.execute_with_token_refresh(move |token| {
460 let collection = collection.clone();
461 let id = id.clone();
462 let http = http.clone();
463 async move { http.restore_deleted(&collection, &id, &token).await }
464 })
465 .await
466 }
467
468 pub async fn restore_collection(&self, collection: &str) -> Result<usize> {
489 let collection = collection.to_string();
490 let http = self.http.clone();
491 self.execute_with_token_refresh(move |token| {
492 let collection = collection.clone();
493 let http = http.clone();
494 async move { http.restore_collection(&collection, &token).await }
495 })
496 .await
497 }
498
499 pub async fn batch_insert(
510 &self,
511 collection: &str,
512 records: Vec<Record>,
513 bypass_ripple: Option<bool>,
514 ) -> Result<Vec<Record>> {
515 let collection = collection.to_string();
516 let http = self.http.clone();
517 self.execute_with_token_refresh(move |token| {
518 let collection = collection.clone();
519 let records = records.clone();
520 let http = http.clone();
521 async move {
522 http.batch_insert(&collection, records, &token, bypass_ripple, None)
523 .await
524 }
525 })
526 .await
527 }
528
529 pub async fn batch_insert_with_options(
539 &self,
540 collection: &str,
541 records: Vec<Record>,
542 options: crate::options::BatchInsertOptions,
543 ) -> Result<Vec<Record>> {
544 let collection = collection.to_string();
545 let http = self.http.clone();
546 self.execute_with_token_refresh(move |token| {
547 let collection = collection.clone();
548 let records = records.clone();
549 let http = http.clone();
550 let options = options.clone();
551 async move {
552 http.batch_insert(
553 &collection,
554 records,
555 &token,
556 options.bypass_ripple,
557 options.transaction_id.as_deref(),
558 )
559 .await
560 }
561 })
562 .await
563 }
564
565 pub async fn batch_update(
576 &self,
577 collection: &str,
578 updates: Vec<(String, Record)>,
579 bypass_ripple: Option<bool>,
580 ) -> Result<Vec<Record>> {
581 let collection = collection.to_string();
582 let http = self.http.clone();
583 self.execute_with_token_refresh(move |token| {
584 let collection = collection.clone();
585 let updates = updates.clone();
586 let http = http.clone();
587 async move {
588 http.batch_update(&collection, updates, &token, bypass_ripple, None)
589 .await
590 }
591 })
592 .await
593 }
594
595 pub async fn batch_update_with_options(
605 &self,
606 collection: &str,
607 updates: Vec<(String, Record)>,
608 options: crate::options::BatchUpdateOptions,
609 ) -> Result<Vec<Record>> {
610 let collection = collection.to_string();
611 let http = self.http.clone();
612 self.execute_with_token_refresh(move |token| {
613 let collection = collection.clone();
614 let updates = updates.clone();
615 let http = http.clone();
616 let options = options.clone();
617 async move {
618 http.batch_update(
619 &collection,
620 updates,
621 &token,
622 options.bypass_ripple,
623 options.transaction_id.as_deref(),
624 )
625 .await
626 }
627 })
628 .await
629 }
630
631 pub async fn batch_delete(
642 &self,
643 collection: &str,
644 ids: Vec<String>,
645 bypass_ripple: Option<bool>,
646 ) -> Result<u64> {
647 let collection = collection.to_string();
648 let http = self.http.clone();
649 self.execute_with_token_refresh(move |token| {
650 let collection = collection.clone();
651 let ids = ids.clone();
652 let http = http.clone();
653 async move {
654 http.batch_delete(&collection, ids, &token, bypass_ripple, None)
655 .await
656 }
657 })
658 .await
659 }
660
661 pub async fn batch_delete_with_options(
671 &self,
672 collection: &str,
673 ids: Vec<String>,
674 options: crate::options::BatchDeleteOptions,
675 ) -> Result<u64> {
676 let collection = collection.to_string();
677 let http = self.http.clone();
678 self.execute_with_token_refresh(move |token| {
679 let collection = collection.clone();
680 let ids = ids.clone();
681 let http = http.clone();
682 let options = options.clone();
683 async move {
684 http.batch_delete(
685 &collection,
686 ids,
687 &token,
688 options.bypass_ripple,
689 options.transaction_id.as_deref(),
690 )
691 .await
692 }
693 })
694 .await
695 }
696
697 pub async fn upsert(
740 &self,
741 collection: &str,
742 id: &str,
743 record: Record,
744 options: Option<crate::options::UpsertOptions>,
745 ) -> Result<Record> {
746 let update_opts = options.as_ref().map(|o| {
748 let mut opts = crate::options::UpdateOptions::new();
749 if let Some(bypass) = o.bypass_ripple {
750 opts = opts.bypass_ripple(bypass);
751 }
752 if let Some(ref tx_id) = o.transaction_id {
753 opts = opts.transaction_id(tx_id.clone());
754 }
755 if let Some(bypass) = o.bypass_cache {
756 opts = opts.bypass_cache(bypass);
757 }
758 opts
759 });
760
761 match self
763 .update(collection, id, record.clone(), update_opts)
764 .await
765 {
766 Ok(updated) => Ok(updated),
767 Err(Error::NotFound) => {
768 let insert_opts = options.map(|o| {
771 let mut opts = crate::options::InsertOptions::new();
772 if let Some(ref ttl) = o.ttl {
773 opts = opts.ttl(ttl.clone());
774 }
775 if let Some(bypass) = o.bypass_ripple {
776 opts = opts.bypass_ripple(bypass);
777 }
778 if let Some(ref tx_id) = o.transaction_id {
779 opts = opts.transaction_id(tx_id.clone());
780 }
781 if let Some(bypass) = o.bypass_cache {
782 opts = opts.bypass_cache(bypass);
783 }
784 opts
785 });
786 self.insert(collection, record, insert_opts).await
787 }
788 Err(e) => Err(e),
789 }
790 }
791
792 pub async fn find_one(
825 &self,
826 collection: &str,
827 field: &str,
828 value: impl Into<serde_json::Value>,
829 ) -> Result<Option<Record>> {
830 use crate::query_builder::QueryBuilder;
831
832 let query = QueryBuilder::new().eq(field, value.into()).limit(1).build();
833
834 let mut results = self.find(collection, query, None).await?;
835 Ok(results.pop())
836 }
837
838 pub async fn exists(&self, collection: &str, id: &str) -> Result<bool> {
870 match self.find_by_id(collection, id, None).await {
871 Ok(_) => Ok(true),
872 Err(Error::NotFound) => Ok(false),
873 Err(e) => Err(e),
874 }
875 }
876
877 pub async fn paginate(
907 &self,
908 collection: &str,
909 page: usize,
910 page_size: usize,
911 ) -> Result<Vec<Record>> {
912 use crate::types::Query;
913
914 let skip = if page > 0 { (page - 1) * page_size } else { 0 };
916
917 let query = Query {
918 filter: None,
919 sort: None,
920 limit: Some(page_size),
921 skip: Some(skip),
922 join: None,
923 bypass_cache: None,
924 bypass_ripple: None,
925 select_fields: None,
926 exclude_fields: None,
927 };
928
929 self.find(collection, query, None).await
930 }
931
932 pub async fn get_token(&self) -> Result<String> {
952 self.auth.get_token().await
953 }
954
955 pub async fn refresh_token(&self) -> Result<String> {
956 self.auth.refresh_token().await
957 }
958
959 pub async fn clear_token_cache(&self) {
974 self.auth.clear_cache().await
975 }
976
977 pub async fn list_collections(&self) -> Result<Vec<String>> {
983 let http = self.http.clone();
984 self.execute_with_token_refresh(move |token| {
985 let http = http.clone();
986 async move { http.list_collections(&token).await }
987 })
988 .await
989 }
990
991 pub async fn list_user_collections(&self) -> Result<Vec<String>> {
993 let http = self.http.clone();
994 self.execute_with_token_refresh(move |token| {
995 let http = http.clone();
996 async move { http.list_collections_filtered(&token, true).await }
997 })
998 .await
999 }
1000
1001 pub async fn delete_collection(&self, collection: &str) -> Result<()> {
1007 let collection = collection.to_string();
1008 let http = self.http.clone();
1009 self.execute_with_token_refresh(move |token| {
1010 let collection = collection.clone();
1011 let http = http.clone();
1012 async move { http.delete_collection(&collection, &token).await }
1013 })
1014 .await
1015 }
1016
1017 pub async fn count_documents(&self, collection: &str) -> Result<usize> {
1027 let query = Query {
1030 select_fields: Some(vec!["_id".to_string()]),
1031 ..Query::default()
1032 };
1033 let records = self.find(collection, query, None).await?;
1034 Ok(records.len())
1035 }
1036
1037 pub async fn collection_exists(&self, collection: &str) -> Result<bool> {
1047 let collections = self.list_collections().await?;
1048 Ok(collections.contains(&collection.to_string()))
1049 }
1050
1051 pub async fn kv_set(
1059 &self,
1060 key: &str,
1061 value: serde_json::Value,
1062 ttl: Option<&str>,
1063 ) -> Result<()> {
1064 let key = key.to_string();
1065 let ttl = ttl.map(|s| s.to_string());
1066 let http = self.http.clone();
1067 self.execute_with_token_refresh(move |token| {
1068 let key = key.clone();
1069 let value = value.clone();
1070 let ttl = ttl.clone();
1071 let http = http.clone();
1072 async move { http.kv_set(&key, value, ttl.as_deref(), &token).await }
1073 })
1074 .await
1075 }
1076
1077 pub async fn kv_get(&self, key: &str) -> Result<Option<serde_json::Value>> {
1087 let key = key.to_string();
1088 let http = self.http.clone();
1089 self.execute_with_token_refresh(move |token| {
1090 let key = key.clone();
1091 let http = http.clone();
1092 async move { http.kv_get(&key, &token).await }
1093 })
1094 .await
1095 }
1096
1097 pub async fn kv_delete(&self, key: &str) -> Result<()> {
1103 let key = key.to_string();
1104 let http = self.http.clone();
1105 self.execute_with_token_refresh(move |token| {
1106 let key = key.clone();
1107 let http = http.clone();
1108 async move { http.kv_delete(&key, &token).await }
1109 })
1110 .await
1111 }
1112
1113 pub async fn kv_clear(&self) -> Result<()> {
1115 let http = self.http.clone();
1116 self.execute_with_token_refresh(move |token| {
1117 let http = http.clone();
1118 async move { http.kv_clear(&token).await }
1119 })
1120 .await
1121 }
1122
1123 pub async fn kv_exists(&self, key: &str) -> Result<bool> {
1133 let key = key.to_string();
1134 let http = self.http.clone();
1135 self.execute_with_token_refresh(move |token| {
1136 let key = key.clone();
1137 let http = http.clone();
1138 async move { http.kv_exists(&key, &token).await }
1139 })
1140 .await
1141 }
1142
1143 pub async fn kv_batch_get(&self, keys: Vec<String>) -> Result<Vec<Record>> {
1153 let http = self.http.clone();
1154 self.execute_with_token_refresh(move |token| {
1155 let keys = keys.clone();
1156 let http = http.clone();
1157 async move { http.kv_batch_get(keys, &token).await }
1158 })
1159 .await
1160 }
1161
1162 pub async fn kv_batch_set(
1174 &self,
1175 keys: Vec<String>,
1176 values: Vec<Record>,
1177 ttl: Option<i64>,
1178 ) -> Result<Vec<(String, bool)>> {
1179 let http = self.http.clone();
1180 self.execute_with_token_refresh(move |token| {
1181 let keys = keys.clone();
1182 let values = values.clone();
1183 let http = http.clone();
1184 async move { http.kv_batch_set(keys, values, ttl, &token).await }
1185 })
1186 .await
1187 }
1188
1189 pub async fn kv_batch_delete(&self, keys: Vec<String>) -> Result<Vec<(String, bool)>> {
1199 let http = self.http.clone();
1200 self.execute_with_token_refresh(move |token| {
1201 let keys = keys.clone();
1202 let http = http.clone();
1203 async move { http.kv_batch_delete(keys, &token).await }
1204 })
1205 .await
1206 }
1207
1208 pub async fn kv_find(
1219 &self,
1220 pattern: Option<&str>,
1221 include_expired: bool,
1222 ) -> Result<Vec<serde_json::Value>> {
1223 let pattern = pattern.map(|s| s.to_string());
1224 let http = self.http.clone();
1225 self.execute_with_token_refresh(move |token| {
1226 let pattern = pattern.clone();
1227 let http = http.clone();
1228 async move {
1229 http.kv_find(pattern.as_deref(), include_expired, &token)
1230 .await
1231 }
1232 })
1233 .await
1234 }
1235
1236 pub async fn kv_query(
1238 &self,
1239 pattern: Option<&str>,
1240 include_expired: bool,
1241 ) -> Result<Vec<serde_json::Value>> {
1242 self.kv_find(pattern, include_expired).await
1243 }
1244
1245 pub async fn begin_transaction(&self, isolation_level: &str) -> Result<String> {
1257 let isolation_level = isolation_level.to_string();
1258 let http = self.http.clone();
1259 self.execute_with_token_refresh(move |token| {
1260 let isolation_level = isolation_level.clone();
1261 let http = http.clone();
1262 async move { http.begin_transaction(&isolation_level, &token).await }
1263 })
1264 .await
1265 }
1266
1267 pub async fn get_transaction_status(&self, transaction_id: &str) -> Result<serde_json::Value> {
1277 let transaction_id = transaction_id.to_string();
1278 let http = self.http.clone();
1279 self.execute_with_token_refresh(move |token| {
1280 let transaction_id = transaction_id.clone();
1281 let http = http.clone();
1282 async move { http.get_transaction_status(&transaction_id, &token).await }
1283 })
1284 .await
1285 }
1286
1287 pub async fn commit_transaction(&self, transaction_id: &str) -> Result<()> {
1293 let transaction_id = transaction_id.to_string();
1294 let http = self.http.clone();
1295 self.execute_with_token_refresh(move |token| {
1296 let transaction_id = transaction_id.clone();
1297 let http = http.clone();
1298 async move { http.commit_transaction(&transaction_id, &token).await }
1299 })
1300 .await
1301 }
1302
1303 pub async fn rollback_transaction(&self, transaction_id: &str) -> Result<()> {
1309 let transaction_id = transaction_id.to_string();
1310 let http = self.http.clone();
1311 self.execute_with_token_refresh(move |token| {
1312 let transaction_id = transaction_id.clone();
1313 let http = http.clone();
1314 async move { http.rollback_transaction(&transaction_id, &token).await }
1315 })
1316 .await
1317 }
1318
1319 pub async fn create_savepoint(&self, transaction_id: &str, name: &str) -> Result<()> {
1323 let transaction_id = transaction_id.to_string();
1324 let name = name.to_string();
1325 let http = self.http.clone();
1326 self.execute_with_token_refresh(move |token| {
1327 let transaction_id = transaction_id.clone();
1328 let name = name.clone();
1329 let http = http.clone();
1330 async move { http.create_savepoint(&transaction_id, &name, &token).await }
1331 })
1332 .await
1333 }
1334
1335 pub async fn rollback_to_savepoint(&self, transaction_id: &str, name: &str) -> Result<()> {
1337 let transaction_id = transaction_id.to_string();
1338 let name = name.to_string();
1339 let http = self.http.clone();
1340 self.execute_with_token_refresh(move |token| {
1341 let transaction_id = transaction_id.clone();
1342 let name = name.clone();
1343 let http = http.clone();
1344 async move {
1345 http.rollback_to_savepoint(&transaction_id, &name, &token)
1346 .await
1347 }
1348 })
1349 .await
1350 }
1351
1352 pub async fn release_savepoint(&self, transaction_id: &str, name: &str) -> Result<()> {
1354 let transaction_id = transaction_id.to_string();
1355 let name = name.to_string();
1356 let http = self.http.clone();
1357 self.execute_with_token_refresh(move |token| {
1358 let transaction_id = transaction_id.clone();
1359 let name = name.clone();
1360 let http = http.clone();
1361 async move { http.release_savepoint(&transaction_id, &name, &token).await }
1362 })
1363 .await
1364 }
1365
1366 pub async fn find_by_id_in_transaction(
1372 &self,
1373 collection: &str,
1374 id: &str,
1375 transaction_id: &str,
1376 bypass_ripple: Option<bool>,
1377 ) -> Result<Record> {
1378 let collection = collection.to_string();
1379 let id = id.to_string();
1380 let transaction_id = transaction_id.to_string();
1381 let http = self.http.clone();
1382 self.execute_with_token_refresh(move |token| {
1383 let collection = collection.clone();
1384 let id = id.clone();
1385 let transaction_id = transaction_id.clone();
1386 let http = http.clone();
1387 async move {
1388 http.find_by_id_in_transaction(
1389 &collection,
1390 &id,
1391 &transaction_id,
1392 &token,
1393 bypass_ripple,
1394 )
1395 .await
1396 }
1397 })
1398 .await
1399 }
1400
1401 pub async fn find_in_transaction(
1403 &self,
1404 collection: &str,
1405 query: Query,
1406 transaction_id: &str,
1407 bypass_ripple: Option<bool>,
1408 ) -> Result<Vec<Record>> {
1409 let collection = collection.to_string();
1410 let transaction_id = transaction_id.to_string();
1411 let http = self.http.clone();
1412 self.execute_with_token_refresh(move |token| {
1413 let collection = collection.clone();
1414 let query = query.clone();
1415 let transaction_id = transaction_id.clone();
1416 let http = http.clone();
1417 async move {
1418 http.find_in_transaction(&collection, query, &transaction_id, &token, bypass_ripple)
1419 .await
1420 }
1421 })
1422 .await
1423 }
1424
1425 pub async fn websocket(&self, ws_url: &str) -> Result<crate::websocket::WebSocketClient> {
1435 let token = self.auth.get_token().await?;
1436 crate::websocket::WebSocketClient::new(ws_url, token)
1437 }
1438
1439 pub async fn search(
1466 &self,
1467 collection: &str,
1468 search_query: SearchQuery,
1469 ) -> Result<SearchResponse> {
1470 let collection = collection.to_string();
1471 let http = self.http.clone();
1472 self.execute_with_token_refresh(move |token| {
1473 let collection = collection.clone();
1474 let search_query = search_query.clone();
1475 let http = http.clone();
1476 async move { http.search(&collection, search_query, &token).await }
1477 })
1478 .await
1479 }
1480
1481 pub async fn distinct_values(
1509 &self,
1510 collection: &str,
1511 field: &str,
1512 query: DistinctValuesQuery,
1513 ) -> Result<DistinctValuesResponse> {
1514 let collection = collection.to_string();
1515 let field = field.to_string();
1516 let http = self.http.clone();
1517 self.execute_with_token_refresh(move |token| {
1518 let collection = collection.clone();
1519 let field = field.clone();
1520 let query = query.clone();
1521 let http = http.clone();
1522 async move {
1523 http.distinct_values(&collection, &field, query, &token)
1524 .await
1525 }
1526 })
1527 .await
1528 }
1529
1530 pub async fn text_search(
1550 &self,
1551 collection: &str,
1552 query_text: &str,
1553 limit: usize,
1554 ) -> Result<Vec<Record>> {
1555 let search_query = SearchQuery::new(query_text).limit(limit);
1556 let response = self.search(collection, search_query).await?;
1557
1558 let records: Vec<Record> = response
1560 .results
1561 .into_iter()
1562 .filter_map(|result| {
1563 let score = result.score;
1564 let mut record: Record = serde_json::from_value(result.record).ok()?;
1565 record.insert("_score", score);
1566 Some(record)
1567 })
1568 .collect();
1569
1570 Ok(records)
1571 }
1572
1573 pub async fn hybrid_search(
1600 &self,
1601 collection: &str,
1602 query_text: &str,
1603 query_vector: Vec<f64>,
1604 limit: usize,
1605 ) -> Result<Vec<Record>> {
1606 let search_query = SearchQuery::new(query_text)
1607 .vector(query_vector)
1608 .text_weight(0.5)
1609 .vector_weight(0.5)
1610 .limit(limit);
1611
1612 let response = self.search(collection, search_query).await?;
1613
1614 let records: Vec<Record> = response
1616 .results
1617 .into_iter()
1618 .filter_map(|result| {
1619 let score = result.score;
1620 let mut record: Record = serde_json::from_value(result.record).ok()?;
1621 record.insert("_score", score);
1622 Some(record)
1623 })
1624 .collect();
1625
1626 Ok(records)
1627 }
1628
1629 pub async fn find_all(&self, collection: &str, limit: usize) -> Result<Vec<Record>> {
1648 use crate::types::Query;
1649
1650 let query = Query {
1651 filter: None,
1652 sort: None,
1653 limit: Some(limit),
1654 skip: None,
1655 join: None,
1656 bypass_cache: None,
1657 bypass_ripple: None,
1658 select_fields: Some(Vec::new()),
1659 exclude_fields: Some(Vec::new()),
1660 };
1661
1662 self.find(collection, query, None).await
1663 }
1664
1665 pub async fn create_collection(&self, collection: &str, schema: Schema) -> Result<()> {
1687 let collection = collection.to_string();
1688 let http = self.http.clone();
1689 self.execute_with_token_refresh(move |token| {
1690 let collection = collection.clone();
1691 let schema = schema.clone();
1692 let http = http.clone();
1693 async move { http.create_collection(&collection, schema, &token).await }
1694 })
1695 .await
1696 }
1697
1698 pub async fn get_collection(&self, collection: &str) -> Result<CollectionMetadata> {
1708 let collection = collection.to_string();
1709 let http = self.http.clone();
1710 self.execute_with_token_refresh(move |token| {
1711 let collection = collection.clone();
1712 let http = http.clone();
1713 async move { http.get_collection(&collection, &token).await }
1714 })
1715 .await
1716 }
1717
1718 pub async fn get_schema(&self, collection: &str) -> Result<Schema> {
1728 let collection = collection.to_string();
1729 let http = self.http.clone();
1730 self.execute_with_token_refresh(move |token| {
1731 let collection = collection.clone();
1732 let http = http.clone();
1733 async move { http.get_schema(&collection, &token).await }
1734 })
1735 .await
1736 }
1737
1738 pub async fn execute_tool(
1753 &self,
1754 tool_name: &str,
1755 params: &serde_json::Value,
1756 chat_id: Option<&str>,
1757 ) -> Option<Result<serde_json::Value>> {
1758 let tool_name = tool_name.to_string();
1759 let params = params.clone();
1760 let chat_id = chat_id.map(|s| s.to_string());
1761 let result = self
1762 .execute_with_token_refresh(|token| {
1763 let tool_name = tool_name.clone();
1764 let params = params.clone();
1765 let chat_id = chat_id.clone();
1766 async move {
1767 self.http
1768 .execute_tool_remote(&tool_name, ¶ms, chat_id.as_deref(), &token)
1769 .await
1770 }
1771 })
1772 .await;
1773 match result {
1774 Ok(result) => {
1775 let success = result["success"].as_bool().unwrap_or(false);
1777 if success {
1778 Some(Ok(result["result"].clone()))
1779 } else {
1780 let error = result["error"]
1781 .as_str()
1782 .unwrap_or("tool execution failed")
1783 .to_string();
1784 Some(Err(crate::Error::ToolExecution(error)))
1785 }
1786 }
1787 Err(crate::Error::NotFound) => None,
1789 Err(crate::Error::Api { code: 405, .. }) => None,
1791 Err(e) => Some(Err(e)),
1792 }
1793 }
1794
1795 pub async fn get_chat_models(&self) -> Result<crate::chat::Models> {
1805 let http = self.http.clone();
1806 self.execute_with_token_refresh(move |token| {
1807 let http = http.clone();
1808 async move { http.get_chat_models(&token).await }
1809 })
1810 .await
1811 }
1812
1813 pub async fn get_chat_tools(&self) -> Result<Vec<serde_json::Value>> {
1817 let http = self.http.clone();
1818 self.execute_with_token_refresh(move |token| {
1819 let http = http.clone();
1820 async move { http.get_chat_tools(&token).await }
1821 })
1822 .await
1823 }
1824
1825 pub async fn get_chat_model(&self, model_name: &str) -> Result<Vec<String>> {
1831 let model_name = model_name.to_string();
1832 let http = self.http.clone();
1833 self.execute_with_token_refresh(move |token| {
1834 let model_name = model_name.clone();
1835 let http = http.clone();
1836 async move { http.get_chat_model(&model_name, &token).await }
1837 })
1838 .await
1839 }
1840
1841 pub async fn raw_completion(
1852 &self,
1853 request: crate::chat::RawCompletionRequest,
1854 ) -> Result<crate::chat::RawCompletionResponse> {
1855 let http = self.http.clone();
1856 self.execute_with_token_refresh(move |token| {
1857 let request = request.clone();
1858 let http = http.clone();
1859 async move { http.raw_completion(request, &token).await }
1860 })
1861 .await
1862 }
1863
1864 pub async fn raw_completion_stream(
1870 &self,
1871 request: crate::chat::RawCompletionRequest,
1872 ) -> Result<crate::chat::RawCompletionResponse> {
1873 let http = self.http.clone();
1874 self.execute_with_token_refresh(move |token| {
1875 let request = request.clone();
1876 let http = http.clone();
1877 async move { http.raw_completion_stream(request, &token).await }
1878 })
1879 .await
1880 }
1881
1882 pub async fn raw_completion_stream_with_progress(
1888 &self,
1889 request: crate::chat::RawCompletionRequest,
1890 progress_tx: tokio::sync::mpsc::Sender<String>,
1891 ) -> Result<crate::chat::RawCompletionResponse> {
1892 let token = self.auth.get_token().await?;
1893 self.http
1894 .raw_completion_stream_with_progress(request, &token, progress_tx)
1895 .await
1896 }
1897
1898 pub async fn create_chat_session(
1908 &self,
1909 request: crate::chat::CreateChatSessionRequest,
1910 ) -> Result<crate::chat::ChatResponse> {
1911 let http = self.http.clone();
1912 self.execute_with_token_refresh(move |token| {
1913 let request = request.clone();
1914 let http = http.clone();
1915 async move { http.create_chat_session(request, &token).await }
1916 })
1917 .await
1918 }
1919
1920 pub async fn get_chat_session(
1926 &self,
1927 chat_id: &str,
1928 ) -> Result<crate::chat::ChatSessionResponse> {
1929 let chat_id = chat_id.to_string();
1930 let http = self.http.clone();
1931 self.execute_with_token_refresh(move |token| {
1932 let chat_id = chat_id.clone();
1933 let http = http.clone();
1934 async move { http.get_chat_session(&chat_id, &token).await }
1935 })
1936 .await
1937 }
1938
1939 pub async fn list_chat_sessions(
1945 &self,
1946 query: crate::chat::ListSessionsQuery,
1947 ) -> Result<crate::chat::ListSessionsResponse> {
1948 let http = self.http.clone();
1949 self.execute_with_token_refresh(move |token| {
1950 let query = query.clone();
1951 let http = http.clone();
1952 async move { http.list_chat_sessions(query, &token).await }
1953 })
1954 .await
1955 }
1956
1957 pub async fn submit_chat_tool_result(
1959 &self,
1960 chat_id: &str,
1961 call_id: &str,
1962 success: bool,
1963 result: Option<serde_json::Value>,
1964 error: Option<String>,
1965 ) -> Result<()> {
1966 let chat_id = chat_id.to_string();
1967 let call_id = call_id.to_string();
1968 let http = self.http.clone();
1969 self.execute_with_token_refresh(move |token| {
1970 let chat_id = chat_id.clone();
1971 let call_id = call_id.clone();
1972 let result = result.clone();
1973 let error = error.clone();
1974 let http = http.clone();
1975 async move {
1976 http.submit_chat_tool_result(&chat_id, &call_id, success, result, error, &token)
1977 .await
1978 }
1979 })
1980 .await
1981 }
1982
1983 pub async fn submit_chat_tool_keepalive(&self, chat_id: &str, call_id: &str) -> Result<()> {
1990 let chat_id = chat_id.to_string();
1991 let call_id = call_id.to_string();
1992 let http = self.http.clone();
1993 self.execute_with_token_refresh(move |token| {
1994 let chat_id = chat_id.clone();
1995 let call_id = call_id.clone();
1996 let http = http.clone();
1997 async move {
1998 http.submit_chat_tool_keepalive(&chat_id, &call_id, &token)
1999 .await
2000 }
2001 })
2002 .await
2003 }
2004
2005 pub async fn update_chat_session(
2012 &self,
2013 chat_id: &str,
2014 request: crate::chat::UpdateSessionRequest,
2015 ) -> Result<crate::chat::ChatSessionResponse> {
2016 let chat_id = chat_id.to_string();
2017 let http = self.http.clone();
2018 self.execute_with_token_refresh(move |token| {
2019 let chat_id = chat_id.clone();
2020 let request = request.clone();
2021 let http = http.clone();
2022 async move { http.update_chat_session(&chat_id, request, &token).await }
2023 })
2024 .await
2025 }
2026
2027 pub async fn delete_chat_session(&self, chat_id: &str) -> Result<()> {
2033 let chat_id = chat_id.to_string();
2034 let http = self.http.clone();
2035 self.execute_with_token_refresh(move |token| {
2036 let chat_id = chat_id.clone();
2037 let http = http.clone();
2038 async move { http.delete_chat_session(&chat_id, &token).await }
2039 })
2040 .await
2041 }
2042
2043 pub async fn branch_chat_session(
2049 &self,
2050 request: crate::chat::CreateChatSessionRequest,
2051 ) -> Result<crate::chat::ChatResponse> {
2052 let http = self.http.clone();
2053 self.execute_with_token_refresh(move |token| {
2054 let request = request.clone();
2055 let http = http.clone();
2056 async move { http.branch_chat_session(request, &token).await }
2057 })
2058 .await
2059 }
2060
2061 pub async fn merge_chat_sessions(
2067 &self,
2068 request: crate::chat::MergeSessionsRequest,
2069 ) -> Result<crate::chat::ChatSessionResponse> {
2070 let http = self.http.clone();
2071 self.execute_with_token_refresh(move |token| {
2072 let request = request.clone();
2073 let http = http.clone();
2074 async move { http.merge_chat_sessions(request, &token).await }
2075 })
2076 .await
2077 }
2078
2079 pub async fn chat_message(
2086 &self,
2087 chat_id: &str,
2088 request: crate::chat::ChatMessageRequest,
2089 ) -> Result<crate::chat::ChatResponse> {
2090 let chat_id = chat_id.to_string();
2091 let http = self.http.clone();
2092 self.execute_with_token_refresh(move |token| {
2093 let chat_id = chat_id.clone();
2094 let request = request.clone();
2095 let http = http.clone();
2096 async move { http.chat_message(&chat_id, request, &token).await }
2097 })
2098 .await
2099 }
2100
2101 pub async fn chat_message_stream(
2105 &self,
2106 chat_id: &str,
2107 request: crate::chat::ChatMessageRequest,
2108 ) -> Result<tokio::sync::mpsc::Receiver<crate::websocket::ChatStreamEvent>> {
2109 let token = self.auth.get_token().await?;
2110 self.http
2111 .chat_message_stream(chat_id, request, &token)
2112 .await
2113 }
2114
2115 pub async fn get_chat_session_messages(
2122 &self,
2123 chat_id: &str,
2124 query: crate::chat::GetMessagesQuery,
2125 ) -> Result<crate::chat::GetMessagesResponse> {
2126 let chat_id = chat_id.to_string();
2127 let http = self.http.clone();
2128 self.execute_with_token_refresh(move |token| {
2129 let chat_id = chat_id.clone();
2130 let query = query.clone();
2131 let http = http.clone();
2132 async move {
2133 http.get_chat_session_messages(&chat_id, query, &token)
2134 .await
2135 }
2136 })
2137 .await
2138 }
2139
2140 pub async fn get_chat_message(&self, chat_id: &str, message_id: &str) -> Result<Record> {
2147 let chat_id = chat_id.to_string();
2148 let message_id = message_id.to_string();
2149 let http = self.http.clone();
2150 self.execute_with_token_refresh(move |token| {
2151 let chat_id = chat_id.clone();
2152 let message_id = message_id.clone();
2153 let http = http.clone();
2154 async move { http.get_chat_message(&chat_id, &message_id, &token).await }
2155 })
2156 .await
2157 }
2158
2159 pub async fn compact_chat(
2172 &self,
2173 chat_id: &str,
2174 keep_recent: Option<usize>,
2175 ) -> Result<crate::chat::CompactChatResponse> {
2176 let chat_id = chat_id.to_string();
2177 let http = self.http.clone();
2178 self.execute_with_token_refresh(move |token| {
2179 let chat_id = chat_id.clone();
2180 let http = http.clone();
2181 async move {
2182 let request = crate::chat::CompactChatRequest { keep_recent };
2183 http.compact_chat_session(&chat_id, request, &token).await
2184 }
2185 })
2186 .await
2187 }
2188
2189 pub async fn embed(&self, text: &str, model: &str) -> Result<Vec<f64>> {
2214 let text = text.to_string();
2215 let model = model.to_string();
2216 let http = self.http.clone();
2217 let response = self
2218 .execute_with_token_refresh(move |token| {
2219 let text = text.clone();
2220 let model = model.clone();
2221 let http = http.clone();
2222 async move {
2223 let request = crate::chat::EmbedRequest {
2224 text: Some(text),
2225 texts: None,
2226 model: Some(model),
2227 };
2228 http.embed(request, &token).await
2229 }
2230 })
2231 .await?;
2232 response
2233 .embeddings
2234 .into_iter()
2235 .next()
2236 .ok_or(crate::Error::Api {
2237 code: 500,
2238 message: "No embedding returned".to_string(),
2239 })
2240 }
2241
2242 pub async fn embed_batch(&self, texts: Vec<String>, model: &str) -> Result<Vec<Vec<f64>>> {
2253 let model = model.to_string();
2254 let http = self.http.clone();
2255 let response = self
2256 .execute_with_token_refresh(move |token| {
2257 let texts = texts.clone();
2258 let model = model.clone();
2259 let http = http.clone();
2260 async move {
2261 let request = crate::chat::EmbedRequest {
2262 text: None,
2263 texts: Some(texts),
2264 model: Some(model),
2265 };
2266 http.embed(request, &token).await
2267 }
2268 })
2269 .await?;
2270 Ok(response.embeddings)
2271 }
2272
2273 pub async fn update_chat_message(
2281 &self,
2282 chat_id: &str,
2283 message_id: &str,
2284 request: crate::chat::UpdateMessageRequest,
2285 ) -> Result<Record> {
2286 let chat_id = chat_id.to_string();
2287 let message_id = message_id.to_string();
2288 let http = self.http.clone();
2289 self.execute_with_token_refresh(move |token| {
2290 let chat_id = chat_id.clone();
2291 let message_id = message_id.clone();
2292 let request = request.clone();
2293 let http = http.clone();
2294 async move {
2295 http.update_chat_message(&chat_id, &message_id, request, &token)
2296 .await
2297 }
2298 })
2299 .await
2300 }
2301
2302 pub async fn delete_chat_message(&self, chat_id: &str, message_id: &str) -> Result<()> {
2309 let chat_id = chat_id.to_string();
2310 let message_id = message_id.to_string();
2311 let http = self.http.clone();
2312 self.execute_with_token_refresh(move |token| {
2313 let chat_id = chat_id.clone();
2314 let message_id = message_id.clone();
2315 let http = http.clone();
2316 async move {
2317 http.delete_chat_message(&chat_id, &message_id, &token)
2318 .await
2319 }
2320 })
2321 .await
2322 }
2323
2324 pub async fn toggle_forgotten_message(
2332 &self,
2333 chat_id: &str,
2334 message_id: &str,
2335 request: crate::chat::ToggleForgottenRequest,
2336 ) -> Result<Record> {
2337 let chat_id = chat_id.to_string();
2338 let message_id = message_id.to_string();
2339 let http = self.http.clone();
2340 self.execute_with_token_refresh(move |token| {
2341 let chat_id = chat_id.clone();
2342 let message_id = message_id.clone();
2343 let request = request.clone();
2344 let http = http.clone();
2345 async move {
2346 http.toggle_forgotten_message(&chat_id, &message_id, request, &token)
2347 .await
2348 }
2349 })
2350 .await
2351 }
2352
2353 pub async fn regenerate_chat_message(
2360 &self,
2361 chat_id: &str,
2362 message_id: &str,
2363 ) -> Result<crate::chat::ChatResponse> {
2364 let chat_id = chat_id.to_string();
2365 let message_id = message_id.to_string();
2366 let http = self.http.clone();
2367 self.execute_with_token_refresh(move |token| {
2368 let chat_id = chat_id.clone();
2369 let message_id = message_id.clone();
2370 let http = http.clone();
2371 async move {
2372 http.regenerate_chat_message(&chat_id, &message_id, &token)
2373 .await
2374 }
2375 })
2376 .await
2377 }
2378
2379 pub async fn save_function(&self, function: crate::functions::UserFunction) -> Result<String> {
2389 let http = self.http.clone();
2390 self.execute_with_token_refresh(move |token| {
2391 let function = function.clone();
2392 let http = http.clone();
2393 async move { http.save_function(function, &token).await }
2394 })
2395 .await
2396 }
2397
2398 pub async fn get_function(&self, id: &str) -> Result<crate::functions::UserFunction> {
2408 let id = id.to_string();
2409 let http = self.http.clone();
2410 self.execute_with_token_refresh(move |token| {
2411 let id = id.clone();
2412 let http = http.clone();
2413 async move { http.get_function(&id, &token).await }
2414 })
2415 .await
2416 }
2417
2418 pub async fn list_functions(
2428 &self,
2429 tags: Option<Vec<String>>,
2430 ) -> Result<Vec<crate::functions::UserFunction>> {
2431 let http = self.http.clone();
2432 self.execute_with_token_refresh(move |token| {
2433 let tags = tags.clone();
2434 let http = http.clone();
2435 async move { http.list_functions(tags, &token).await }
2436 })
2437 .await
2438 }
2439
2440 pub async fn update_function(
2447 &self,
2448 id: &str,
2449 function: crate::functions::UserFunction,
2450 ) -> Result<()> {
2451 let id = id.to_string();
2452 let http = self.http.clone();
2453 self.execute_with_token_refresh(move |token| {
2454 let id = id.clone();
2455 let function = function.clone();
2456 let http = http.clone();
2457 async move { http.update_function(&id, function, &token).await }
2458 })
2459 .await
2460 }
2461
2462 pub async fn delete_function(&self, id: &str) -> Result<()> {
2468 let id = id.to_string();
2469 let http = self.http.clone();
2470 self.execute_with_token_refresh(move |token| {
2471 let id = id.clone();
2472 let http = http.clone();
2473 async move { http.delete_function(&id, &token).await }
2474 })
2475 .await
2476 }
2477
2478 pub async fn call_function(
2509 &self,
2510 function_id_or_label: &str,
2511 params: Option<std::collections::HashMap<String, crate::types::FieldType>>,
2512 ) -> Result<crate::functions::FunctionResult> {
2513 let function_id_or_label = function_id_or_label.to_string();
2514 let http = self.http.clone();
2515 self.execute_with_token_refresh(move |token| {
2516 let function_id_or_label = function_id_or_label.clone();
2517 let params = params.clone();
2518 let http = http.clone();
2519 async move {
2520 http.call_function(&function_id_or_label, params, &token)
2521 .await
2522 }
2523 })
2524 .await
2525 }
2526
2527 pub async fn save_user_function(
2541 &self,
2542 user_function: crate::functions::UserFunction,
2543 ) -> Result<String> {
2544 let http = self.http.clone();
2545 self.execute_with_token_refresh(move |token| {
2546 let user_function = user_function.clone();
2547 let http = http.clone();
2548 async move { http.save_user_function(user_function, &token).await }
2549 })
2550 .await
2551 }
2552
2553 pub async fn get_user_function(&self, label: &str) -> Result<crate::functions::UserFunction> {
2563 let label = label.to_string();
2564 let http = self.http.clone();
2565 self.execute_with_token_refresh(move |token| {
2566 let label = label.clone();
2567 let http = http.clone();
2568 async move { http.get_user_function(&label, &token).await }
2569 })
2570 .await
2571 }
2572
2573 pub async fn list_user_functions(
2583 &self,
2584 tags: Option<Vec<String>>,
2585 ) -> Result<Vec<crate::functions::UserFunction>> {
2586 let http = self.http.clone();
2587 self.execute_with_token_refresh(move |token| {
2588 let tags = tags.clone();
2589 let http = http.clone();
2590 async move { http.list_user_functions(tags, &token).await }
2591 })
2592 .await
2593 }
2594
2595 pub async fn update_user_function(
2602 &self,
2603 label: &str,
2604 user_function: crate::functions::UserFunction,
2605 ) -> Result<()> {
2606 let label = label.to_string();
2607 let http = self.http.clone();
2608 self.execute_with_token_refresh(move |token| {
2609 let label = label.clone();
2610 let user_function = user_function.clone();
2611 let http = http.clone();
2612 async move {
2613 http.update_user_function(&label, user_function, &token)
2614 .await
2615 }
2616 })
2617 .await
2618 }
2619
2620 pub async fn delete_user_function(&self, label: &str) -> Result<()> {
2626 let label = label.to_string();
2627 let http = self.http.clone();
2628 self.execute_with_token_refresh(move |token| {
2629 let label = label.clone();
2630 let http = http.clone();
2631 async move { http.delete_user_function(&label, &token).await }
2632 })
2633 .await
2634 }
2635
2636 pub async fn goal_create(&self, data: serde_json::Value) -> Result<serde_json::Value> {
2639 let http = self.http.clone();
2640 self.execute_with_token_refresh(move |token| {
2641 let data = data.clone();
2642 let http = http.clone();
2643 async move { http.goal_create(data, &token).await }
2644 })
2645 .await
2646 }
2647
2648 pub async fn goal_list(&self) -> Result<serde_json::Value> {
2649 let http = self.http.clone();
2650 self.execute_with_token_refresh(move |token| {
2651 let http = http.clone();
2652 async move { http.goal_list(&token).await }
2653 })
2654 .await
2655 }
2656
2657 pub async fn goal_get(&self, id: &str) -> Result<serde_json::Value> {
2658 let id = id.to_string();
2659 let http = self.http.clone();
2660 self.execute_with_token_refresh(move |token| {
2661 let id = id.clone();
2662 let http = http.clone();
2663 async move { http.goal_get(&id, &token).await }
2664 })
2665 .await
2666 }
2667
2668 pub async fn goal_update(
2669 &self,
2670 id: &str,
2671 data: serde_json::Value,
2672 ) -> Result<serde_json::Value> {
2673 let id = id.to_string();
2674 let http = self.http.clone();
2675 self.execute_with_token_refresh(move |token| {
2676 let id = id.clone();
2677 let data = data.clone();
2678 let http = http.clone();
2679 async move { http.goal_update(&id, data, &token).await }
2680 })
2681 .await
2682 }
2683
2684 pub async fn goal_delete(&self, id: &str) -> Result<()> {
2685 let id = id.to_string();
2686 let http = self.http.clone();
2687 self.execute_with_token_refresh(move |token| {
2688 let id = id.clone();
2689 let http = http.clone();
2690 async move { http.goal_delete(&id, &token).await }
2691 })
2692 .await
2693 }
2694
2695 pub async fn goal_search(&self, query: &str) -> Result<serde_json::Value> {
2696 let query = query.to_string();
2697 let http = self.http.clone();
2698 self.execute_with_token_refresh(move |token| {
2699 let query = query.clone();
2700 let http = http.clone();
2701 async move { http.goal_search(&query, &token).await }
2702 })
2703 .await
2704 }
2705
2706 pub async fn goal_complete(
2710 &self,
2711 id: &str,
2712 data: serde_json::Value,
2713 ) -> Result<serde_json::Value> {
2714 let id = id.to_string();
2715 let http = self.http.clone();
2716 self.execute_with_token_refresh(move |token| {
2717 let id = id.clone();
2718 let data = data.clone();
2719 let http = http.clone();
2720 async move { http.goal_complete(&id, data, &token).await }
2721 })
2722 .await
2723 }
2724
2725 pub async fn goal_approve(&self, id: &str) -> Result<serde_json::Value> {
2727 let id = id.to_string();
2728 let http = self.http.clone();
2729 self.execute_with_token_refresh(move |token| {
2730 let id = id.clone();
2731 let http = http.clone();
2732 async move { http.goal_approve(&id, &token).await }
2733 })
2734 .await
2735 }
2736
2737 pub async fn goal_reject(
2739 &self,
2740 id: &str,
2741 data: serde_json::Value,
2742 ) -> Result<serde_json::Value> {
2743 let id = id.to_string();
2744 let http = self.http.clone();
2745 self.execute_with_token_refresh(move |token| {
2746 let id = id.clone();
2747 let data = data.clone();
2748 let http = http.clone();
2749 async move { http.goal_reject(&id, data, &token).await }
2750 })
2751 .await
2752 }
2753
2754 pub async fn goal_step_start(&self, id: &str, step_index: usize) -> Result<serde_json::Value> {
2758 let id = id.to_string();
2759 let http = self.http.clone();
2760 self.execute_with_token_refresh(move |token| {
2761 let id = id.clone();
2762 let http = http.clone();
2763 async move { http.goal_step_start(&id, step_index, &token).await }
2764 })
2765 .await
2766 }
2767
2768 pub async fn goal_step_complete(
2770 &self,
2771 id: &str,
2772 step_index: usize,
2773 data: serde_json::Value,
2774 ) -> Result<serde_json::Value> {
2775 let id = id.to_string();
2776 let http = self.http.clone();
2777 self.execute_with_token_refresh(move |token| {
2778 let id = id.clone();
2779 let data = data.clone();
2780 let http = http.clone();
2781 async move { http.goal_step_complete(&id, step_index, data, &token).await }
2782 })
2783 .await
2784 }
2785
2786 pub async fn goal_step_fail(
2788 &self,
2789 id: &str,
2790 step_index: usize,
2791 data: serde_json::Value,
2792 ) -> Result<serde_json::Value> {
2793 let id = id.to_string();
2794 let http = self.http.clone();
2795 self.execute_with_token_refresh(move |token| {
2796 let id = id.clone();
2797 let data = data.clone();
2798 let http = http.clone();
2799 async move { http.goal_step_fail(&id, step_index, data, &token).await }
2800 })
2801 .await
2802 }
2803
2804 pub async fn task_create(&self, data: serde_json::Value) -> Result<serde_json::Value> {
2807 let http = self.http.clone();
2808 self.execute_with_token_refresh(move |token| {
2809 let data = data.clone();
2810 let http = http.clone();
2811 async move { http.task_create(data, &token).await }
2812 })
2813 .await
2814 }
2815
2816 pub async fn task_list(&self) -> Result<serde_json::Value> {
2817 let http = self.http.clone();
2818 self.execute_with_token_refresh(move |token| {
2819 let http = http.clone();
2820 async move { http.task_list(&token).await }
2821 })
2822 .await
2823 }
2824
2825 pub async fn task_get(&self, id: &str) -> Result<serde_json::Value> {
2826 let id = id.to_string();
2827 let http = self.http.clone();
2828 self.execute_with_token_refresh(move |token| {
2829 let id = id.clone();
2830 let http = http.clone();
2831 async move { http.task_get(&id, &token).await }
2832 })
2833 .await
2834 }
2835
2836 pub async fn task_update(
2837 &self,
2838 id: &str,
2839 data: serde_json::Value,
2840 ) -> Result<serde_json::Value> {
2841 let id = id.to_string();
2842 let http = self.http.clone();
2843 self.execute_with_token_refresh(move |token| {
2844 let id = id.clone();
2845 let data = data.clone();
2846 let http = http.clone();
2847 async move { http.task_update(&id, data, &token).await }
2848 })
2849 .await
2850 }
2851
2852 pub async fn task_delete(&self, id: &str) -> Result<()> {
2853 let id = id.to_string();
2854 let http = self.http.clone();
2855 self.execute_with_token_refresh(move |token| {
2856 let id = id.clone();
2857 let http = http.clone();
2858 async move { http.task_delete(&id, &token).await }
2859 })
2860 .await
2861 }
2862
2863 pub async fn task_due(&self, now: &str) -> Result<serde_json::Value> {
2864 let now = now.to_string();
2865 let http = self.http.clone();
2866 self.execute_with_token_refresh(move |token| {
2867 let now = now.clone();
2868 let http = http.clone();
2869 async move { http.task_due(&now, &token).await }
2870 })
2871 .await
2872 }
2873
2874 pub async fn task_start(&self, id: &str) -> Result<serde_json::Value> {
2878 let id = id.to_string();
2879 let http = self.http.clone();
2880 self.execute_with_token_refresh(move |token| {
2881 let id = id.clone();
2882 let http = http.clone();
2883 async move { http.task_start(&id, &token).await }
2884 })
2885 .await
2886 }
2887
2888 pub async fn task_succeed(
2890 &self,
2891 id: &str,
2892 data: serde_json::Value,
2893 ) -> Result<serde_json::Value> {
2894 let id = id.to_string();
2895 let http = self.http.clone();
2896 self.execute_with_token_refresh(move |token| {
2897 let id = id.clone();
2898 let data = data.clone();
2899 let http = http.clone();
2900 async move { http.task_succeed(&id, data, &token).await }
2901 })
2902 .await
2903 }
2904
2905 pub async fn task_fail(&self, id: &str, data: serde_json::Value) -> Result<serde_json::Value> {
2907 let id = id.to_string();
2908 let http = self.http.clone();
2909 self.execute_with_token_refresh(move |token| {
2910 let id = id.clone();
2911 let data = data.clone();
2912 let http = http.clone();
2913 async move { http.task_fail(&id, data, &token).await }
2914 })
2915 .await
2916 }
2917
2918 pub async fn task_pause(&self, id: &str) -> Result<serde_json::Value> {
2920 let id = id.to_string();
2921 let http = self.http.clone();
2922 self.execute_with_token_refresh(move |token| {
2923 let id = id.clone();
2924 let http = http.clone();
2925 async move { http.task_pause(&id, &token).await }
2926 })
2927 .await
2928 }
2929
2930 pub async fn task_resume(
2932 &self,
2933 id: &str,
2934 data: serde_json::Value,
2935 ) -> Result<serde_json::Value> {
2936 let id = id.to_string();
2937 let http = self.http.clone();
2938 self.execute_with_token_refresh(move |token| {
2939 let id = id.clone();
2940 let data = data.clone();
2941 let http = http.clone();
2942 async move { http.task_resume(&id, data, &token).await }
2943 })
2944 .await
2945 }
2946
2947 pub async fn agent_create(&self, data: serde_json::Value) -> Result<serde_json::Value> {
2950 let http = self.http.clone();
2951 self.execute_with_token_refresh(move |token| {
2952 let data = data.clone();
2953 let http = http.clone();
2954 async move { http.agent_create(data, &token).await }
2955 })
2956 .await
2957 }
2958
2959 pub async fn agent_list(&self) -> Result<serde_json::Value> {
2960 let http = self.http.clone();
2961 self.execute_with_token_refresh(move |token| {
2962 let http = http.clone();
2963 async move { http.agent_list(&token).await }
2964 })
2965 .await
2966 }
2967
2968 pub async fn agent_get(&self, id: &str) -> Result<serde_json::Value> {
2969 let id = id.to_string();
2970 let http = self.http.clone();
2971 self.execute_with_token_refresh(move |token| {
2972 let id = id.clone();
2973 let http = http.clone();
2974 async move { http.agent_get(&id, &token).await }
2975 })
2976 .await
2977 }
2978
2979 pub async fn agent_get_by_name(&self, name: &str) -> Result<serde_json::Value> {
2980 let name = name.to_string();
2981 let http = self.http.clone();
2982 self.execute_with_token_refresh(move |token| {
2983 let name = name.clone();
2984 let http = http.clone();
2985 async move { http.agent_get_by_name(&name, &token).await }
2986 })
2987 .await
2988 }
2989
2990 pub async fn agent_update(
2991 &self,
2992 id: &str,
2993 data: serde_json::Value,
2994 ) -> Result<serde_json::Value> {
2995 let id = id.to_string();
2996 let http = self.http.clone();
2997 self.execute_with_token_refresh(move |token| {
2998 let id = id.clone();
2999 let data = data.clone();
3000 let http = http.clone();
3001 async move { http.agent_update(&id, data, &token).await }
3002 })
3003 .await
3004 }
3005
3006 pub async fn agent_delete(&self, id: &str) -> Result<()> {
3007 let id = id.to_string();
3008 let http = self.http.clone();
3009 self.execute_with_token_refresh(move |token| {
3010 let id = id.clone();
3011 let http = http.clone();
3012 async move { http.agent_delete(&id, &token).await }
3013 })
3014 .await
3015 }
3016
3017 pub async fn agents_by_deployment(&self, deployment_id: &str) -> Result<serde_json::Value> {
3018 let deployment_id = deployment_id.to_string();
3019 let http = self.http.clone();
3020 self.execute_with_token_refresh(move |token| {
3021 let deployment_id = deployment_id.clone();
3022 let http = http.clone();
3023 async move { http.agents_by_deployment(&deployment_id, &token).await }
3024 })
3025 .await
3026 }
3027
3028 pub async fn goal_template_create(&self, data: serde_json::Value) -> Result<serde_json::Value> {
3031 let http = self.http.clone();
3032 self.execute_with_token_refresh(move |token| {
3033 let data = data.clone();
3034 let http = http.clone();
3035 async move { http.goal_template_create(data, &token).await }
3036 })
3037 .await
3038 }
3039
3040 pub async fn goal_template_list(&self) -> Result<serde_json::Value> {
3041 let http = self.http.clone();
3042 self.execute_with_token_refresh(move |token| {
3043 let http = http.clone();
3044 async move { http.goal_template_list(&token).await }
3045 })
3046 .await
3047 }
3048
3049 pub async fn goal_template_get(&self, id: &str) -> Result<serde_json::Value> {
3050 let id = id.to_string();
3051 let http = self.http.clone();
3052 self.execute_with_token_refresh(move |token| {
3053 let id = id.clone();
3054 let http = http.clone();
3055 async move { http.goal_template_get(&id, &token).await }
3056 })
3057 .await
3058 }
3059
3060 pub async fn goal_template_update(
3061 &self,
3062 id: &str,
3063 data: serde_json::Value,
3064 ) -> Result<serde_json::Value> {
3065 let id = id.to_string();
3066 let http = self.http.clone();
3067 self.execute_with_token_refresh(move |token| {
3068 let id = id.clone();
3069 let data = data.clone();
3070 let http = http.clone();
3071 async move { http.goal_template_update(&id, data, &token).await }
3072 })
3073 .await
3074 }
3075
3076 pub async fn goal_template_delete(&self, id: &str) -> Result<()> {
3077 let id = id.to_string();
3078 let http = self.http.clone();
3079 self.execute_with_token_refresh(move |token| {
3080 let id = id.clone();
3081 let http = http.clone();
3082 async move { http.goal_template_delete(&id, &token).await }
3083 })
3084 .await
3085 }
3086
3087 pub async fn kv_get_links(&self, key: &str) -> Result<serde_json::Value> {
3091 let key = key.to_string();
3092 let http = self.http.clone();
3093 self.execute_with_token_refresh(move |token| {
3094 let key = key.clone();
3095 let http = http.clone();
3096 async move { http.kv_get_links(&key, &token).await }
3097 })
3098 .await
3099 }
3100
3101 pub async fn kv_link(
3103 &self,
3104 key: &str,
3105 collection: &str,
3106 document_id: &str,
3107 ) -> Result<serde_json::Value> {
3108 let key = key.to_string();
3109 let collection = collection.to_string();
3110 let document_id = document_id.to_string();
3111 let http = self.http.clone();
3112 self.execute_with_token_refresh(move |token| {
3113 let key = key.clone();
3114 let collection = collection.clone();
3115 let document_id = document_id.clone();
3116 let http = http.clone();
3117 async move { http.kv_link(&key, &collection, &document_id, &token).await }
3118 })
3119 .await
3120 }
3121
3122 pub async fn kv_unlink(
3124 &self,
3125 key: &str,
3126 collection: &str,
3127 document_id: &str,
3128 ) -> Result<serde_json::Value> {
3129 let key = key.to_string();
3130 let collection = collection.to_string();
3131 let document_id = document_id.to_string();
3132 let http = self.http.clone();
3133 self.execute_with_token_refresh(move |token| {
3134 let key = key.clone();
3135 let collection = collection.clone();
3136 let document_id = document_id.clone();
3137 let http = http.clone();
3138 async move {
3139 http.kv_unlink(&key, &collection, &document_id, &token)
3140 .await
3141 }
3142 })
3143 .await
3144 }
3145
3146 pub async fn create_schedule(&self, data: serde_json::Value) -> Result<serde_json::Value> {
3150 let http = self.http.clone();
3151 self.execute_with_token_refresh(move |token| {
3152 let data = data.clone();
3153 let http = http.clone();
3154 async move { http.create_schedule(data, &token).await }
3155 })
3156 .await
3157 }
3158
3159 pub async fn list_schedules(&self) -> Result<serde_json::Value> {
3161 let http = self.http.clone();
3162 self.execute_with_token_refresh(move |token| {
3163 let http = http.clone();
3164 async move { http.list_schedules(&token).await }
3165 })
3166 .await
3167 }
3168
3169 pub async fn get_schedule(&self, id: &str) -> Result<serde_json::Value> {
3171 let id = id.to_string();
3172 let http = self.http.clone();
3173 self.execute_with_token_refresh(move |token| {
3174 let id = id.clone();
3175 let http = http.clone();
3176 async move { http.get_schedule(&id, &token).await }
3177 })
3178 .await
3179 }
3180
3181 pub async fn update_schedule(
3183 &self,
3184 id: &str,
3185 data: serde_json::Value,
3186 ) -> Result<serde_json::Value> {
3187 let id = id.to_string();
3188 let http = self.http.clone();
3189 self.execute_with_token_refresh(move |token| {
3190 let id = id.clone();
3191 let data = data.clone();
3192 let http = http.clone();
3193 async move { http.update_schedule(&id, data, &token).await }
3194 })
3195 .await
3196 }
3197
3198 pub async fn delete_schedule(&self, id: &str) -> Result<()> {
3200 let id = id.to_string();
3201 let http = self.http.clone();
3202 self.execute_with_token_refresh(move |token| {
3203 let id = id.clone();
3204 let http = http.clone();
3205 async move { http.delete_schedule(&id, &token).await }
3206 })
3207 .await
3208 }
3209
3210 pub async fn pause_schedule(&self, id: &str) -> Result<serde_json::Value> {
3212 let id = id.to_string();
3213 let http = self.http.clone();
3214 self.execute_with_token_refresh(move |token| {
3215 let id = id.clone();
3216 let http = http.clone();
3217 async move { http.pause_schedule(&id, &token).await }
3218 })
3219 .await
3220 }
3221
3222 pub async fn resume_schedule(&self, id: &str) -> Result<serde_json::Value> {
3224 let id = id.to_string();
3225 let http = self.http.clone();
3226 self.execute_with_token_refresh(move |token| {
3227 let id = id.clone();
3228 let http = http.clone();
3229 async move { http.resume_schedule(&id, &token).await }
3230 })
3231 .await
3232 }
3233
3234 pub fn schema_cache(&self) -> &crate::schema_cache::SchemaCache {
3240 &self.schema_cache
3241 }
3242
3243 pub fn schema_cache_arc(&self) -> Arc<crate::schema_cache::SchemaCache> {
3245 self.schema_cache.clone()
3246 }
3247
3248 pub fn extract_id(&self, collection: &str, record: &serde_json::Value) -> Option<String> {
3253 let alias = self.schema_cache.get_alias(collection);
3254 let extra: Vec<&str> = alias.iter().map(|s| s.as_str()).collect();
3255 crate::utils::extract_record_id(record, &extra)
3256 }
3257
3258 pub async fn subscribe_sse(
3266 &self,
3267 collection: &str,
3268 filter_field: Option<&str>,
3269 filter_value: Option<&str>,
3270 ) -> Result<tokio::sync::mpsc::Receiver<crate::websocket::MutationNotificationPayload>> {
3271 let token = self.auth.get_token().await?;
3272 let mut parsed_url =
3273 url::Url::parse(&format!("{}/api/subscribe/{}", self.base_url, collection)).map_err(
3274 |e| Error::Api {
3275 code: 0,
3276 message: format!("Invalid SSE URL: {}", e),
3277 },
3278 )?;
3279
3280 {
3281 let mut pairs = parsed_url.query_pairs_mut();
3282 if let Some(ff) = filter_field {
3283 pairs.append_pair("filter_field", ff);
3284 }
3285 if let Some(fv) = filter_value {
3286 pairs.append_pair("filter_value", fv);
3287 }
3288 }
3289
3290 let url = parsed_url.to_string();
3291
3292 let client = reqwest::Client::new();
3293 let response = client
3294 .get(&url)
3295 .header("Authorization", format!("Bearer {}", token))
3296 .header("Accept", "text/event-stream")
3297 .send()
3298 .await
3299 .map_err(|e| Error::Api {
3300 code: 0,
3301 message: format!("SSE connection failed: {}", e),
3302 })?;
3303
3304 if !response.status().is_success() {
3305 return Err(Error::Api {
3306 code: response.status().as_u16(),
3307 message: format!("SSE subscribe failed: {}", response.status()),
3308 });
3309 }
3310
3311 let (tx, rx) = tokio::sync::mpsc::channel(256);
3312 let schema_cache = self.schema_cache.clone();
3313
3314 tokio::spawn(async move {
3316 use futures_util::StreamExt;
3317 let mut stream = response.bytes_stream();
3318 let mut buffer = String::new();
3319
3320 while let Some(chunk) = stream.next().await {
3321 let chunk = match chunk {
3322 Ok(c) => c,
3323 Err(_) => break,
3324 };
3325 let text = String::from_utf8_lossy(&chunk);
3326 buffer.push_str(&text.replace("\r\n", "\n"));
3328
3329 while let Some(end) = buffer.find("\n\n") {
3331 let event_block = buffer[..end].to_owned();
3332 buffer.drain(..end + 2);
3333
3334 let mut event_type = String::new();
3335 let mut data_lines: Vec<String> = Vec::new();
3336
3337 for line in event_block.lines() {
3338 if let Some(val) = line.strip_prefix("event: ") {
3339 event_type = val.trim().to_string();
3340 } else if let Some(val) = line.strip_prefix("data: ") {
3341 data_lines.push(val.trim().to_string());
3342 }
3343 }
3344
3345 let event_data = data_lines.join("\n");
3346
3347 match event_type.as_str() {
3348 "mutation" => {
3349 if let Ok(payload) = serde_json::from_str::<
3350 crate::websocket::MutationNotificationPayload,
3351 >(&event_data)
3352 {
3353 if tx.send(payload).await.is_err() {
3354 return; }
3356 }
3357 }
3358 "schema_changed" => {
3359 if let Ok(sc) = serde_json::from_str::<
3360 crate::websocket::SchemaChangedPayload,
3361 >(&event_data)
3362 {
3363 schema_cache.handle_schema_changed(
3364 &sc.collection,
3365 sc.version,
3366 &sc.primary_key_alias,
3367 );
3368 }
3369 }
3370 _ => {} }
3372 }
3373 }
3374 });
3375
3376 Ok(rx)
3377 }
3378
3379 pub async fn connect_ws(&self) -> Result<crate::websocket::WebSocketClient> {
3385 let token = self.auth.get_token().await?;
3386
3387 let ws_url = self
3389 .base_url
3390 .replace("https://", "wss://")
3391 .replace("http://", "ws://");
3392
3393 let ws = crate::websocket::WebSocketClient::new(&ws_url, token)?;
3394
3395 if self.schema_cache.is_enabled() {
3397 ws.set_schema_cache(self.schema_cache.clone()).await;
3398 }
3399
3400 Ok(ws)
3401 }
3402}
3403
3404#[derive(Default)]
3406pub struct ClientBuilder {
3407 base_url: Option<String>,
3408 api_key: Option<String>,
3409 timeout: Option<Duration>,
3410 max_retries: Option<usize>,
3411 should_retry: Option<bool>,
3412 serialization_format: Option<crate::types::SerializationFormat>,
3413 schema_cache_enabled: bool,
3414 schema_cache_ttl: Option<Duration>,
3415 schema_cache_max: Option<usize>,
3416}
3417
3418impl ClientBuilder {
3419 pub fn new() -> Self {
3421 Self::default()
3422 }
3423
3424 pub fn base_url(mut self, url: impl Into<String>) -> Self {
3438 self.base_url = Some(url.into());
3439 self
3440 }
3441
3442 pub fn api_key(mut self, key: impl Into<String>) -> Self {
3458 self.api_key = Some(key.into());
3459 self
3460 }
3461
3462 #[deprecated(since = "0.1.0", note = "Use `api_key` instead")]
3464 pub fn api_token(mut self, token: impl Into<String>) -> Self {
3465 self.api_key = Some(token.into());
3466 self
3467 }
3468
3469 pub fn timeout(mut self, timeout: Duration) -> Self {
3473 self.timeout = Some(timeout);
3474 self
3475 }
3476
3477 pub fn max_retries(mut self, retries: usize) -> Self {
3481 self.max_retries = Some(retries);
3482 self
3483 }
3484
3485 pub fn should_retry(mut self, should_retry: bool) -> Self {
3509 self.should_retry = Some(should_retry);
3510 self
3511 }
3512
3513 pub fn serialization_format(mut self, format: crate::types::SerializationFormat) -> Self {
3534 self.serialization_format = Some(format);
3535 self
3536 }
3537
3538 pub fn schema_cache(mut self, enabled: bool) -> Self {
3544 self.schema_cache_enabled = enabled;
3545 self
3546 }
3547
3548 pub fn schema_cache_ttl(mut self, seconds: u64) -> Self {
3550 self.schema_cache_ttl = Some(Duration::from_secs(seconds));
3551 self
3552 }
3553
3554 pub fn schema_cache_max(mut self, max: usize) -> Self {
3556 self.schema_cache_max = Some(max);
3557 self
3558 }
3559
3560 pub fn build(self) -> Result<Client> {
3566 let base_url_str = self
3567 .base_url
3568 .ok_or_else(|| Error::InvalidConfig("base_url is required".to_string()))?;
3569
3570 let api_key = self
3571 .api_key
3572 .ok_or_else(|| Error::InvalidConfig("api_key is required".to_string()))?;
3573
3574 let timeout = self.timeout.unwrap_or(Duration::from_secs(30));
3575 let max_retries = self.max_retries.unwrap_or(3);
3576 let should_retry = self.should_retry.unwrap_or(true); let format = self
3578 .serialization_format
3579 .unwrap_or(crate::types::SerializationFormat::MessagePack); let base_url = url::Url::parse(&base_url_str)?;
3583
3584 let http = HttpClient::new(
3586 &base_url_str,
3587 timeout,
3588 max_retries as u32,
3589 should_retry,
3590 format,
3591 )?;
3592
3593 let reqwest_client = reqwest::Client::builder().timeout(timeout).build()?;
3595
3596 let auth = AuthManager::new(api_key, base_url, reqwest_client);
3598
3599 let schema_cache =
3600 crate::schema_cache::SchemaCache::new(crate::schema_cache::SchemaCacheConfig {
3601 enabled: self.schema_cache_enabled,
3602 max_entries: self.schema_cache_max.unwrap_or(100),
3603 ttl: self.schema_cache_ttl.unwrap_or(Duration::from_secs(300)),
3604 });
3605
3606 Ok(Client {
3607 http: Arc::new(http),
3608 auth: Arc::new(auth),
3609 schema_cache: Arc::new(schema_cache),
3610 base_url: base_url_str,
3611 })
3612 }
3613}
3614
3615#[cfg(test)]
3616mod tests {
3617 use super::*;
3618
3619 #[test]
3620 fn test_client_builder_new() {
3621 let builder = ClientBuilder::new();
3622 assert!(builder.base_url.is_none());
3623 assert!(builder.api_key.is_none());
3624 }
3625
3626 #[test]
3627 fn test_client_builder_default() {
3628 let builder = ClientBuilder::default();
3629 assert!(builder.base_url.is_none());
3630 assert!(builder.api_key.is_none());
3631 }
3632
3633 #[test]
3634 fn test_client_builder_with_values() {
3635 let builder = ClientBuilder::new()
3636 .base_url("http://localhost:8080")
3637 .api_key("test-key")
3638 .timeout(Duration::from_secs(30))
3639 .max_retries(5);
3640
3641 assert_eq!(builder.base_url, Some("http://localhost:8080".to_string()));
3642 assert_eq!(builder.api_key, Some("test-key".to_string()));
3643 assert_eq!(builder.timeout, Some(Duration::from_secs(30)));
3644 assert_eq!(builder.max_retries, Some(5));
3645 }
3646
3647 #[test]
3648 fn test_client_builder_missing_base_url() {
3649 let result = ClientBuilder::new().api_key("test-key").build();
3650
3651 assert!(result.is_err());
3652 match result {
3653 Err(crate::Error::InvalidConfig(msg)) => {
3654 assert!(msg.contains("base_url"));
3655 }
3656 _ => panic!("Expected InvalidConfig error"),
3657 }
3658 }
3659
3660 #[test]
3661 fn test_client_builder_missing_api_key() {
3662 let result = ClientBuilder::new()
3663 .base_url("http://localhost:8080")
3664 .build();
3665
3666 assert!(result.is_err());
3667 match result {
3668 Err(crate::Error::InvalidConfig(msg)) => {
3669 assert!(msg.contains("api_key"));
3670 }
3671 _ => panic!("Expected InvalidConfig error"),
3672 }
3673 }
3674
3675 #[test]
3676 fn test_client_builder_invalid_url() {
3677 let result = ClientBuilder::new()
3678 .base_url("not-a-valid-url")
3679 .api_key("test-key")
3680 .build();
3681
3682 assert!(result.is_err());
3683 }
3684
3685 #[test]
3686 fn test_client_builder_valid() {
3687 let result = ClientBuilder::new()
3688 .base_url("http://localhost:8080")
3689 .api_key("test-key")
3690 .build();
3691
3692 assert!(result.is_ok());
3693 }
3694
3695 #[test]
3696 fn test_client_builder_with_custom_timeout() {
3697 let result = ClientBuilder::new()
3698 .base_url("http://localhost:8080")
3699 .api_key("test-key")
3700 .timeout(Duration::from_secs(60))
3701 .build();
3702
3703 assert!(result.is_ok());
3704 }
3705
3706 #[test]
3707 fn test_client_builder_with_custom_retries() {
3708 let result = ClientBuilder::new()
3709 .base_url("http://localhost:8080")
3710 .api_key("test-key")
3711 .max_retries(10)
3712 .build();
3713
3714 assert!(result.is_ok());
3715 }
3716
3717 #[test]
3718 fn test_client_builder_with_retry_enabled() {
3719 let result = ClientBuilder::new()
3720 .base_url("http://localhost:8080")
3721 .api_key("test-key")
3722 .should_retry(true)
3723 .build();
3724
3725 assert!(result.is_ok());
3726 }
3727
3728 #[test]
3729 fn test_client_builder_with_retry_disabled() {
3730 let result = ClientBuilder::new()
3731 .base_url("http://localhost:8080")
3732 .api_key("test-key")
3733 .should_retry(false)
3734 .build();
3735
3736 assert!(result.is_ok());
3737 }
3738
3739 #[test]
3740 fn test_client_builder_method() {
3741 let builder = Client::builder();
3742 assert!(builder.base_url.is_none());
3743 }
3744
3745 #[test]
3746 fn test_query_new() {
3747 let query = Query::new();
3748 assert!(query.filter.is_none());
3749 assert!(query.sort.is_none());
3750 assert!(query.limit.is_none());
3751 assert!(query.skip.is_none());
3752 }
3753
3754 #[test]
3755 fn test_query_with_filter() {
3756 let query = Query::new().filter(serde_json::json!({"name": "test"}));
3757 assert!(query.filter.is_some());
3758 }
3759
3760 #[test]
3761 fn test_query_with_sort() {
3762 let query = Query::new().sort(serde_json::json!({"created_at": -1}));
3763 assert!(query.sort.is_some());
3764 }
3765
3766 #[test]
3767 fn test_query_with_limit() {
3768 let query = Query::new().limit(10);
3769 assert_eq!(query.limit, Some(10));
3770 }
3771
3772 #[test]
3773 fn test_query_with_skip() {
3774 let query = Query::new().skip(20);
3775 assert_eq!(query.skip, Some(20));
3776 }
3777
3778 #[test]
3779 fn test_query_with_bypass_cache() {
3780 let query = Query::new().bypass_cache(true);
3781 assert_eq!(query.bypass_cache, Some(true));
3782 }
3783
3784 #[test]
3785 fn test_query_with_bypass_ripple() {
3786 let query = Query::new().bypass_ripple(true);
3787 assert_eq!(query.bypass_ripple, Some(true));
3788 }
3789
3790 #[test]
3791 fn test_query_with_join() {
3792 let join = serde_json::json!({
3793 "collections": ["users"],
3794 "local_field": "user_id",
3795 "foreign_field": "id",
3796 "as_field": "user"
3797 });
3798 let query = Query::new().join(join.clone());
3799 assert_eq!(query.join, Some(join));
3800 }
3801
3802 #[test]
3803 fn test_query_builder_chaining() {
3804 let query = Query::new()
3805 .filter(serde_json::json!({"status": "active"}))
3806 .sort(serde_json::json!({"created_at": -1}))
3807 .limit(10)
3808 .skip(20)
3809 .bypass_cache(true);
3810
3811 assert!(query.filter.is_some());
3812 assert!(query.sort.is_some());
3813 assert_eq!(query.limit, Some(10));
3814 assert_eq!(query.skip, Some(20));
3815 assert_eq!(query.bypass_cache, Some(true));
3816 }
3817
3818 #[test]
3819 fn test_record_new() {
3820 let record = Record::new();
3821 assert!(record.is_empty());
3822 assert_eq!(record.len(), 0);
3823 }
3824
3825 #[test]
3826 fn test_record_insert_and_get() {
3827 let mut record = Record::new();
3828 record.insert("name", "test");
3829
3830 assert!(!record.is_empty());
3831 assert_eq!(record.len(), 1);
3832 assert!(record.get("name").is_some());
3833 }
3834
3835 #[test]
3836 fn test_record_contains_key() {
3837 let mut record = Record::new();
3838 record.insert("name", "test");
3839
3840 assert!(record.contains_key("name"));
3841 assert!(!record.contains_key("age"));
3842 }
3843
3844 #[test]
3845 fn test_rate_limit_info_is_near_limit() {
3846 let info = RateLimitInfo {
3847 limit: 1000,
3848 remaining: 50, reset: 1234567890,
3850 };
3851 assert!(info.is_near_limit());
3852
3853 let info2 = RateLimitInfo {
3854 limit: 1000,
3855 remaining: 500, reset: 1234567890,
3857 };
3858 assert!(!info2.is_near_limit());
3859 }
3860
3861 #[test]
3862 fn test_rate_limit_info_is_exceeded() {
3863 let info = RateLimitInfo {
3864 limit: 1000,
3865 remaining: 0,
3866 reset: 1234567890,
3867 };
3868 assert!(info.is_exceeded());
3869
3870 let info2 = RateLimitInfo {
3871 limit: 1000,
3872 remaining: 1,
3873 reset: 1234567890,
3874 };
3875 assert!(!info2.is_exceeded());
3876 }
3877
3878 #[test]
3879 fn test_rate_limit_info_remaining_percentage() {
3880 let info = RateLimitInfo {
3881 limit: 1000,
3882 remaining: 250,
3883 reset: 1234567890,
3884 };
3885 assert_eq!(info.remaining_percentage(), 25.0);
3886
3887 let info2 = RateLimitInfo {
3888 limit: 1000,
3889 remaining: 0,
3890 reset: 1234567890,
3891 };
3892 assert_eq!(info2.remaining_percentage(), 0.0);
3893 }
3894
3895 #[test]
3896 fn test_record_remove() {
3897 let mut record = Record::new();
3898 record.insert("name", "test");
3899
3900 let removed = record.remove("name");
3901 assert!(removed.is_some());
3902 assert!(!record.contains_key("name"));
3903 }
3904
3905 fn far_future_jwt() -> String {
3908 use base64::Engine;
3909 let exp = std::time::SystemTime::now()
3910 .duration_since(std::time::UNIX_EPOCH)
3911 .unwrap()
3912 .as_secs()
3913 + 3600;
3914 let header = base64::engine::general_purpose::URL_SAFE_NO_PAD
3915 .encode(serde_json::to_vec(&serde_json::json!({"typ":"JWT","alg":"HS256"})).unwrap());
3916 let payload = base64::engine::general_purpose::URL_SAFE_NO_PAD
3917 .encode(serde_json::to_vec(&serde_json::json!({"exp": exp, "sub":"test"})).unwrap());
3918 format!("{header}.{payload}.sig")
3919 }
3920
3921 #[tokio::test]
3925 async fn test_find_by_id_auto_refreshes_on_token_expired() {
3926 let mut server = mockito::Server::new_async().await;
3927 let jwt = far_future_jwt();
3928
3929 let token_mock = server
3932 .mock("POST", "/api/auth/token")
3933 .with_status(200)
3934 .with_header("content-type", "application/json")
3935 .with_body(serde_json::json!({ "token": jwt }).to_string())
3936 .expect(2)
3937 .create_async()
3938 .await;
3939
3940 let unauthorized = server
3942 .mock("GET", "/api/find/users/u1")
3943 .with_status(401)
3944 .with_header("content-type", "application/json")
3945 .with_body(r#"{"code":401,"message":"token expired"}"#)
3946 .expect(1)
3947 .create_async()
3948 .await;
3949
3950 let success = server
3952 .mock("GET", "/api/find/users/u1")
3953 .with_status(200)
3954 .with_header("content-type", "application/json")
3955 .with_body(r#"{"id":"u1","name":"Alice"}"#)
3956 .expect(1)
3957 .create_async()
3958 .await;
3959
3960 let client = Client::builder()
3961 .base_url(server.url())
3962 .api_key("test-key")
3963 .build()
3964 .expect("client builds");
3965
3966 let record = client
3967 .find_by_id("users", "u1", None)
3968 .await
3969 .expect("auto-refresh should make the retried call succeed");
3970
3971 assert_eq!(
3972 record.get("name").and_then(|v| v.as_string()),
3973 Some("Alice")
3974 );
3975
3976 token_mock.assert_async().await;
3979 unauthorized.assert_async().await;
3980 success.assert_async().await;
3981 }
3982}