1use derive_builder::Builder;
16use serde::{Deserialize, Serialize};
17
18use crate::mochow::{client::IntoRequest, config::ClientConfiguration};
19
20use super::ReadConsistency;
21
22#[derive(Debug, Clone, Builder, Serialize)]
28pub struct InsertRowArgs<T> {
29 #[builder(setter(into))]
30 pub database: String,
31 #[builder(setter(into))]
32 pub table: String,
33 #[builder(setter(into))]
35 pub rows: Vec<T>,
36}
37
38#[derive(Debug, Clone, Deserialize)]
39pub struct InsertRowsResponse {
40 pub code: i32,
41 pub msg: String,
42 #[serde(rename = "affectedCount")]
44 pub affected_count: i32,
45}
46
47#[derive(Debug, Clone, Builder, Serialize)]
53pub struct UpsertRowArgs<T> {
54 #[builder(setter(into))]
55 pub database: String,
56 #[builder(setter(into))]
57 pub table: String,
58 #[builder(setter(into))]
60 pub rows: Vec<T>,
61}
62
63#[derive(Debug, Clone, Deserialize)]
64pub struct UpsertRowsResponse {
65 pub code: i32,
66 pub msg: String,
67 #[serde(rename = "affectedCount")]
69 pub affected_count: i32,
70}
71
72#[derive(Debug, Clone, Builder, Serialize)]
77pub struct UpdateRowArgs {
78 #[builder(setter(into))]
79 pub database: String,
80 #[builder(setter(into))]
81 pub table: String,
82
83 #[builder(setter(into))]
85 #[serde(rename = "primaryKey")]
86 pub primary_key: serde_json::Value,
87
88 #[builder(default, setter(strip_option))]
90 #[serde(rename = "partitionKey", skip_serializing_if = "Option::is_none")]
91 pub partition_ey: Option<serde_json::Value>,
92
93 #[builder(setter(into))]
95 pub update: serde_json::Value,
96}
97
98#[derive(Debug, Clone, Builder, Serialize)]
103pub struct DeleteRowArgs {
104 #[builder(setter(into))]
105 pub database: String,
106 #[builder(setter(into))]
107 pub table: String,
108
109 #[builder(default, setter(strip_option))]
110 #[serde(rename = "primaryKey", skip_serializing_if = "Option::is_none")]
111 pub primary_key: Option<serde_json::Value>,
112
113 #[builder(default, setter(strip_option))]
114 #[serde(rename = "partitionKey", skip_serializing_if = "Option::is_none")]
115 pub partition_ey: Option<serde_json::Value>,
116
117 #[builder(default, setter(into, strip_option))]
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub filter: Option<String>,
122}
123
124#[derive(Debug, Clone, Builder, Serialize)]
129pub struct QueryRowArgs {
130 #[builder(setter(into))]
131 pub database: String,
132 #[builder(setter(into))]
133 pub table: String,
134
135 #[builder(setter(into))]
136 #[serde(rename = "primaryKey")]
137 pub primary_key: serde_json::Value,
138
139 #[builder(default, setter(strip_option))]
140 #[serde(rename = "partitionKey", skip_serializing_if = "Option::is_none")]
141 pub partition_key: Option<serde_json::Value>,
142
143 #[builder(default, setter(into, strip_option))]
145 #[serde(rename = "projections", skip_serializing_if = "Option::is_none")]
146 pub projections: Option<Vec<String>>,
147
148 #[builder(default, setter(strip_option))]
150 #[serde(rename = "retrieveVector", skip_serializing_if = "Option::is_none")]
151 pub retrieve_vector: Option<bool>,
152
153 #[builder(default, setter(into, strip_option))]
157 #[serde(rename = "readConsistency", skip_serializing_if = "Option::is_none")]
158 pub read_consistency: Option<ReadConsistency>,
159}
160
161#[derive(Debug, Clone, Deserialize)]
163pub struct QueryRowsResponse<T> {
164 pub code: i32,
165 pub msg: String,
166 pub row: T,
167}
168
169#[derive(Debug, Clone, Builder, Serialize)]
174pub struct SearchRowsArgs {
175 #[builder(setter(into))]
176 pub database: String,
177 #[builder(setter(into))]
178 pub table: String,
179
180 #[builder(setter(into))]
182 pub anns: AnnsSearchParams,
183
184 #[builder(default, setter(strip_option))]
185 #[serde(rename = "partitionKey", skip_serializing_if = "Option::is_none")]
186 pub partition_ey: Option<serde_json::Value>,
187
188 #[builder(default, setter(into, strip_option))]
189 #[serde(rename = "projections", skip_serializing_if = "Option::is_none")]
190 pub projections: Option<Vec<String>>,
191
192 #[builder(default, setter(strip_option))]
193 #[serde(rename = "retrieveVector", skip_serializing_if = "Option::is_none")]
194 pub retrieve_vector: Option<bool>,
195
196 #[builder(default, setter(into, strip_option))]
197 #[serde(rename = "readConsistency", skip_serializing_if = "Option::is_none")]
198 pub read_consistency: Option<String>,
199}
200
201#[derive(Debug, Clone, Builder, Serialize)]
202pub struct AnnsSearchParams {
203 #[builder(setter(into))]
204 #[serde(rename = "vectorField")]
205 pub vector_field: String,
206
207 #[builder(setter(into))]
209 #[serde(rename = "vectorFloats")]
210 pub vector_floats: Vec<f64>,
211
212 #[builder(setter(into))]
213 pub params: VectorSearchParams,
214
215 #[builder(default, setter(into, strip_option))]
217 #[serde(skip_serializing_if = "Option::is_none")]
218 pub filter: Option<String>,
219}
220
221#[derive(Debug, Clone, Serialize)]
222#[serde(untagged)]
223pub enum VectorSearchParams {
224 FLAT(FLATSearchParams),
225 HNSW(HNSWSearchParams),
226 HNSWPQ(HNSWPQSearchParams),
227 PUCK(PUCKSearchParams),
228}
229
230#[derive(Debug, Clone, Builder, Serialize)]
231pub struct HNSWSearchParams {
232 #[builder(setter(into))]
234 pub ef: u32,
235 #[builder(default = "50", setter(into))]
236 pub limit: u32,
237
238 #[builder(default, setter(into, strip_option))]
240 #[serde(rename = "distanceFar", skip_serializing_if = "Option::is_none")]
241 pub distance_far: Option<f64>,
242
243 #[builder(default, setter(into, strip_option))]
245 #[serde(rename = "distanceNear", skip_serializing_if = "Option::is_none")]
246 pub distance_near: Option<f64>,
247
248 #[builder(default, setter(into))]
249 pub pruning: bool,
250}
251
252#[derive(Debug, Clone, Builder, Serialize)]
253pub struct HNSWPQSearchParams {
254 #[builder(setter(into))]
256 pub ef: u32,
257 #[builder(default = "50", setter(into))]
258 pub limit: u32,
259
260 #[builder(default, setter(into, strip_option))]
262 #[serde(rename = "distanceFar", skip_serializing_if = "Option::is_none")]
263 pub distance_far: Option<f64>,
264
265 #[builder(default, setter(into, strip_option))]
267 #[serde(rename = "distanceNear", skip_serializing_if = "Option::is_none")]
268 pub distance_near: Option<f64>,
269}
270
271#[derive(Debug, Clone, Builder, Serialize)]
272pub struct PUCKSearchParams {
273 #[builder(setter(into))]
275 #[serde(rename = "searchCoarseCount")]
276 pub search_coarse_count: u32,
277 #[builder(default = "50", setter(into))]
278 pub limit: u32,
279 #[builder(default, setter(into, strip_option))]
280 #[serde(rename = "distanceFar", skip_serializing_if = "Option::is_none")]
281 pub distance_far: Option<f64>,
282 #[builder(default, setter(into, strip_option))]
283 #[serde(rename = "distanceNear", skip_serializing_if = "Option::is_none")]
284 pub distance_near: Option<f64>,
285}
286
287#[derive(Debug, Clone, Builder, Serialize)]
288pub struct FLATSearchParams {
289 #[builder(default = "50", setter(into))]
290 pub limit: u32,
291
292 #[builder(default, setter(into, strip_option))]
294 #[serde(rename = "distanceFar", skip_serializing_if = "Option::is_none")]
295 pub distance_far: Option<f64>,
296
297 #[builder(default, setter(into, strip_option))]
299 #[serde(rename = "distanceNear", skip_serializing_if = "Option::is_none")]
300 pub distance_near: Option<f64>,
301}
302
303#[derive(Debug, Clone, Deserialize)]
305pub struct SearchRowsResponse<T> {
306 pub code: i32,
307 pub msg: String,
308 pub rows: Vec<RowResult<T>>,
309}
310
311#[derive(Debug, Clone, Deserialize)]
312pub struct RowResult<T> {
313 pub row: T,
315 pub distance: f64,
317 pub score: f64,
319}
320
321#[derive(Debug, Clone, Builder, Serialize)]
326pub struct SelectRowsArgs {
327 #[builder(setter(into))]
328 pub database: String,
329 #[builder(setter(into))]
330 pub table: String,
331
332 #[builder(default, setter(into, strip_option))]
334 #[serde(skip_serializing_if = "Option::is_none")]
335 pub filter: Option<String>,
336
337 #[builder(default, setter(strip_option))]
339 #[serde(skip_serializing_if = "Option::is_none")]
340 pub marker: Option<serde_json::Value>,
341
342 #[builder(default, setter(into, strip_option))]
343 #[serde(skip_serializing_if = "Option::is_none")]
344 pub limit: Option<u32>,
345
346 #[builder(default, setter(into, strip_option))]
347 #[serde(rename = "projections", skip_serializing_if = "Option::is_none")]
348 pub projections: Option<Vec<String>>,
349
350 #[builder(default, setter(into, strip_option))]
351 #[serde(rename = "readConsistency", skip_serializing_if = "Option::is_none")]
352 pub read_consistency: Option<String>,
353}
354
355#[derive(Debug, Clone, Deserialize)]
357pub struct SelectRowsResponse<T> {
358 pub code: i32,
359 pub msg: String,
360 pub rows: Vec<T>,
361
362 #[serde(rename = "isTruncated")]
363 pub is_truncated: bool,
364
365 #[serde(rename = "nextMarker")]
366 pub next_marker: serde_json::Value,
367}
368
369#[derive(Debug, Clone, Builder, Serialize)]
375pub struct BatchSearchRowsArgs {
376 #[builder(setter(into))]
377 pub database: String,
378 #[builder(setter(into))]
379 pub table: String,
380 #[builder(setter(into))]
381 pub anns: BatchAnnsSearchParams,
382
383 #[builder(default, setter(strip_option))]
384 #[serde(rename = "partitionKey", skip_serializing_if = "Option::is_none")]
385 pub partition_ey: Option<serde_json::Value>,
386
387 #[builder(default, setter(into, strip_option))]
388 #[serde(rename = "projections", skip_serializing_if = "Option::is_none")]
389 pub projections: Option<Vec<String>>,
390
391 #[builder(default, setter(strip_option))]
392 #[serde(rename = "retrieveVector", skip_serializing_if = "Option::is_none")]
393 pub retrieve_vector: Option<bool>,
394
395 #[builder(default, setter(into, strip_option))]
396 #[serde(rename = "readConsistency", skip_serializing_if = "Option::is_none")]
397 pub read_consistency: Option<String>,
398}
399
400#[derive(Debug, Clone, Builder, Serialize)]
405pub struct BatchAnnsSearchParams {
406 #[builder(setter(into))]
407 #[serde(rename = "vectorField")]
408 pub vector_field: String,
409
410 #[builder(setter(into))]
412 #[serde(rename = "vectorFloats")]
413 pub vector_floats: Vec<Vec<f64>>,
414
415 #[builder(setter(into))]
416 pub params: VectorSearchParams,
417
418 #[builder(default, setter(into, strip_option))]
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub filter: Option<String>,
421}
422
423#[derive(Debug, Clone, Deserialize)]
424pub struct BatchSearchRowsResponse<T> {
425 pub code: i32,
426 pub msg: String,
427 pub results: Vec<BatchRowResult<T>>,
428}
429
430#[derive(Debug, Clone, Deserialize)]
431pub struct BatchRowResult<T> {
432 #[serde(default, rename = "searchVectorFloats")]
434 pub search_vector_floats: Vec<f64>,
435 pub rows: Vec<RowResult<T>>,
436}
437
438impl<T: Serialize> IntoRequest for InsertRowArgs<T> {
439 fn into_request(
440 self,
441 config: &ClientConfiguration,
442 client: &reqwest_middleware::ClientWithMiddleware,
443 ) -> reqwest_middleware::RequestBuilder {
444 let url = format!("{}/{}/row?insert", config.endpoint, config.version);
445 client.post(url).json(&self)
446 }
447}
448
449impl<T: Serialize> IntoRequest for UpsertRowArgs<T> {
450 fn into_request(
451 self,
452 config: &ClientConfiguration,
453 client: &reqwest_middleware::ClientWithMiddleware,
454 ) -> reqwest_middleware::RequestBuilder {
455 let url = format!("{}/{}/row?upsert", config.endpoint, config.version);
456 client.post(url).json(&self)
457 }
458}
459
460impl IntoRequest for UpdateRowArgs {
461 fn into_request(
462 self,
463 config: &ClientConfiguration,
464 client: &reqwest_middleware::ClientWithMiddleware,
465 ) -> reqwest_middleware::RequestBuilder {
466 let url = format!("{}/{}/row?update", config.endpoint, config.version);
467 client.post(url).json(&self)
468 }
469}
470
471impl IntoRequest for DeleteRowArgs {
472 fn into_request(
473 self,
474 config: &ClientConfiguration,
475 client: &reqwest_middleware::ClientWithMiddleware,
476 ) -> reqwest_middleware::RequestBuilder {
477 let url = format!("{}/{}/row?delete", config.endpoint, config.version);
478 client.post(url).json(&self)
479 }
480}
481
482impl IntoRequest for QueryRowArgs {
483 fn into_request(
484 self,
485 config: &ClientConfiguration,
486 client: &reqwest_middleware::ClientWithMiddleware,
487 ) -> reqwest_middleware::RequestBuilder {
488 let url = format!("{}/{}/row?query", config.endpoint, config.version);
489 client.post(url).json(&self)
490 }
491}
492
493impl IntoRequest for SearchRowsArgs {
494 fn into_request(
495 self,
496 config: &ClientConfiguration,
497 client: &reqwest_middleware::ClientWithMiddleware,
498 ) -> reqwest_middleware::RequestBuilder {
499 let url = format!("{}/{}/row?search", config.endpoint, config.version);
500 client.post(url).json(&self)
501 }
502}
503
504impl IntoRequest for SelectRowsArgs {
505 fn into_request(
506 self,
507 config: &ClientConfiguration,
508 client: &reqwest_middleware::ClientWithMiddleware,
509 ) -> reqwest_middleware::RequestBuilder {
510 let url = format!("{}/{}/row?select", config.endpoint, config.version);
511 client.post(url).json(&self)
512 }
513}
514
515impl IntoRequest for BatchSearchRowsArgs {
516 fn into_request(
517 self,
518 config: &ClientConfiguration,
519 client: &reqwest_middleware::ClientWithMiddleware,
520 ) -> reqwest_middleware::RequestBuilder {
521 let url = format!("{}/{}/row?batchSearch", config.endpoint, config.version);
522 client.post(url).json(&self)
523 }
524}
525
526#[cfg(test)]
527mod tests {
528 use super::*;
529 use crate::mochow::{TESTDATABSE, TESTTABLE, UTCLIENT};
530 use anyhow::Result;
531
532 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
533 struct MyRecord {
534 #[serde(default)]
535 id: String,
536 #[serde(default, rename = "bookName")]
537 book_name: String,
538 #[serde(default)]
539 author: String,
540 #[serde(default)]
541 page: i32,
542 #[serde(default)]
543 vector: Vec<f64>,
544 }
545
546 #[test]
547 fn test_insert_row_serialize() -> Result<()> {
548 let args = InsertRowArgsBuilder::default()
549 .database("test_db")
550 .table("test_table")
551 .rows(vec![serde_json::json!(
552 {
553 "id": "00001",
554 "username": "alice",
555 "vector_field": [
556 0.2323234,
557 0.34534545,
558 0.9837234
559 ]
560 }
561 )])
562 .build()?;
563 let json = serde_json::to_string(&args)?;
564 println!("{}", json);
565 Ok(())
566 }
567
568 #[tokio::test]
569 async fn test_insert_row() -> Result<()> {
570 let args1 = InsertRowArgsBuilder::default()
572 .database(&TESTDATABSE.to_string())
573 .table(&TESTTABLE.to_string())
574 .rows(vec![MyRecord {
575 id: "0001".to_string(),
576 book_name: "西游记".to_string(),
577 author: "吴承恩".to_string(),
578 page: 21,
579 vector: vec![0.2123, 0.24, 0.213],
580 }])
581 .build()?;
582 let _ret = UTCLIENT.insert_row(&args1).await?;
583 println!("insert_row ret: {:?}", _ret);
584
585 let args2 = InsertRowArgsBuilder::default()
587 .database(&TESTDATABSE.to_string())
588 .table(&TESTTABLE.to_string())
589 .rows(vec![serde_json::json!({
590 "id": "0002",
591 "bookName": "西游记",
592 "author": "吴承恩",
593 "page": 22,
594 "vector": [0.2123, 0.24, 0.213],
595 })])
596 .build()?;
597 let _ret = UTCLIENT.insert_row(&args2).await?;
598 println!("insert_row ret: {:?}", _ret);
599 Ok(())
600 }
601
602 #[tokio::test]
603 async fn test_upsert_row() -> Result<()> {
604 let args = UpsertRowArgsBuilder::default()
605 .database(&TESTDATABSE.to_string())
606 .table(&TESTTABLE.to_string())
607 .rows(vec![
608 serde_json::json!({
609 "id": "0001",
610 "bookName": "西游记",
611 "author": "吴承恩",
612 "page": 21,
613 "vector": [0.2123, 0.21, 0.213],
614 }),
615 serde_json::json!({
616 "id": "0002",
617 "bookName": "西游记",
618 "author": "吴承恩",
619 "page": 22,
620 "vector": [0.2123, 0.22, 0.213],
621 }),
622 serde_json::json!({
623 "id": "0003",
624 "bookName": "三国演义",
625 "author": "罗贯中",
626 "page": 23,
627 "vector": [0.2123, 0.23, 0.213],
628 }),
629 serde_json::json!({
630 "id": "0004",
631 "bookName": "三国演义",
632 "author": "罗贯中",
633 "page": 24,
634 "vector": [0.2123, 0.24, 0.213],
635 }),
636 ])
637 .build()?;
638 let _ret = UTCLIENT.upsert_row(&args).await?;
639 println!("upsert_row ret: {:?}", _ret);
640 Ok(())
641 }
642
643 #[tokio::test]
644 async fn test_update_row() -> Result<()> {
645 let args = UpdateRowArgsBuilder::default()
646 .database(&TESTDATABSE.to_string())
647 .table(&TESTTABLE.to_string())
648 .primary_key(serde_json::json!({
649 "id": "0001",
650 }))
651 .update(serde_json::json!({
652 "bookName": "红楼梦",
653 "author": "曹雪芹",
654 "page": 100,
655 }))
656 .build()?;
657 let _ret = UTCLIENT.update_row(&args).await?;
658 println!("update_row ret: {:?}", _ret);
659 Ok(())
660 }
661
662 #[tokio::test]
663 async fn test_delete_row() -> Result<()> {
664 let args = DeleteRowArgsBuilder::default()
665 .database(&TESTDATABSE.to_string())
666 .table(&TESTTABLE.to_string())
667 .filter("page >= 22")
671 .build()?;
672 let _ret = UTCLIENT.delete_rows(&args).await?;
673 println!("delete_row ret: {:?}", _ret);
674 Ok(())
675 }
676
677 #[tokio::test]
678 async fn test_query_row() -> Result<()> {
679 let args = QueryRowArgsBuilder::default()
680 .database(&TESTDATABSE.to_string())
681 .table(&TESTTABLE.to_string())
682 .primary_key(serde_json::json!({
683 "id": "0001",
684 }))
685 .projections(vec!["id".to_string(), "bookName".to_string()])
686 .retrieve_vector(false)
687 .build()?;
688 let query_ret: QueryRowsResponse<MyRecord> = UTCLIENT.query_row(&args).await?;
689 println!("query_row ret: {:?}", query_ret.row);
690 let row1 = query_ret.row;
691 let query_ret: QueryRowsResponse<serde_json::Value> = UTCLIENT.query_row(&args).await?;
692 println!("query_row ret: {:?}", query_ret.row);
693 let row2 = serde_json::from_value(query_ret.row)?;
695 assert_eq!(row1, row2);
696 Ok(())
697 }
698
699 #[tokio::test]
700 async fn test_select_row() -> Result<()> {
701 let mut args = SelectRowsArgsBuilder::default()
702 .database(&TESTDATABSE.to_string())
703 .table(&TESTTABLE.to_string())
704 .projections(vec![
705 "id".to_string(),
706 "bookName".to_string(),
707 "page".to_string(),
708 ])
709 .filter("page > 21")
710 .limit(1 as u32)
711 .build()?;
712 loop {
713 let ret: SelectRowsResponse<serde_json::Value> = UTCLIENT.select_rows(&args).await?;
714 println!("select_rows ret: {:?}", ret);
715 if !ret.is_truncated {
716 break;
717 } else {
718 args.marker = Some(ret.next_marker);
719 }
720 }
721
722 Ok(())
723 }
724
725 #[tokio::test]
726 async fn test_search() -> Result<()> {
727 let search_args = SearchRowsArgsBuilder::default()
728 .database(&TESTDATABSE.to_string())
729 .table(&TESTTABLE.to_string())
730 .anns(
731 AnnsSearchParamsBuilder::default()
732 .vector_field("vector")
733 .vector_floats(vec![0.3123, 0.43, 0.213])
734 .params(VectorSearchParams::HNSW(HNSWSearchParams {
735 ef: 200,
736 limit: 10,
737 distance_far: None,
738 distance_near: None,
739 pruning: false,
740 }))
741 .filter("bookName = '三国演义'")
742 .build()?,
743 )
744 .retrieve_vector(true)
745 .build()?;
746 let ret: SearchRowsResponse<serde_json::Value> = UTCLIENT.search_rows(&search_args).await?;
747 println!("search_rows ret: {:?}", ret.rows);
748 Ok(())
749 }
750
751 #[tokio::test]
752 async fn test_batch_search() -> Result<()> {
753 let batch_ann_params = BatchAnnsSearchParamsBuilder::default()
754 .vector_field("vector")
755 .vector_floats(vec![vec![0.3123, 0.43, 0.213], vec![0.5512, 0.33, 0.43]])
756 .params(VectorSearchParams::HNSW(HNSWSearchParams {
757 ef: 200,
758 limit: 10,
759 distance_far: None,
760 distance_near: None,
761 pruning: false,
762 }))
763 .filter("bookName = '三国演义'")
764 .build()?;
765 let batch_search_args = BatchSearchRowsArgsBuilder::default()
766 .database(&TESTDATABSE.to_string())
767 .table(&TESTTABLE.to_string())
768 .anns(batch_ann_params)
769 .retrieve_vector(true)
770 .build()?;
771 let batch_rets: BatchSearchRowsResponse<serde_json::Value> =
772 UTCLIENT.batch_search_rows(&batch_search_args).await?;
773 for (i, bs) in batch_rets.results.iter().enumerate() {
774 println!("batch: {}, {:?}", i, bs.search_vector_floats);
775 for (j, ss) in bs.rows.iter().enumerate() {
776 println!("{}, {:?}", j, ss);
777 }
778 }
779 Ok(())
780 }
781}