1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6use serde_json::{json, Map, Value};
7
8use crate::client::Client;
9use crate::error::{Error, Result};
10use crate::response::Response;
11
12pub type Document = Map<String, Value>;
15
16#[derive(Debug, Clone, PartialEq, Serialize)]
34#[serde(transparent)]
35pub struct DocumentFilter(Value);
36
37fn field_filter(variant: &str, field: &str, value: impl Into<Value>) -> DocumentFilter {
38 DocumentFilter(json!({variant: {"field": field, "value": value.into()}}))
39}
40
41impl DocumentFilter {
42 pub fn all() -> Self {
45 DocumentFilter(Value::String("All".into()))
46 }
47
48 pub fn eq(field: &str, value: impl Into<Value>) -> Self {
50 field_filter("Eq", field, value)
51 }
52
53 pub fn ne(field: &str, value: impl Into<Value>) -> Self {
55 field_filter("Ne", field, value)
56 }
57
58 pub fn gt(field: &str, value: impl Into<Value>) -> Self {
60 field_filter("Gt", field, value)
61 }
62
63 pub fn gte(field: &str, value: impl Into<Value>) -> Self {
65 field_filter("Gte", field, value)
66 }
67
68 pub fn lt(field: &str, value: impl Into<Value>) -> Self {
70 field_filter("Lt", field, value)
71 }
72
73 pub fn lte(field: &str, value: impl Into<Value>) -> Self {
75 field_filter("Lte", field, value)
76 }
77
78 pub fn contains(field: &str, value: impl Into<Value>) -> Self {
81 field_filter("Contains", field, value)
82 }
83
84 pub fn is_in<V: Into<Value>>(field: &str, values: impl IntoIterator<Item = V>) -> Self {
86 let values: Vec<Value> = values.into_iter().map(Into::into).collect();
87 DocumentFilter(json!({"In": {"field": field, "values": values}}))
88 }
89
90 pub fn and(filters: impl IntoIterator<Item = DocumentFilter>) -> Self {
93 let filters: Vec<Value> = filters.into_iter().map(|f| f.0).collect();
94 DocumentFilter(json!({"And": filters}))
95 }
96}
97
98#[derive(Debug, Clone, Default, PartialEq, Serialize)]
105pub struct DocumentUpdate {
106 #[serde(skip_serializing_if = "Map::is_empty")]
108 pub set: Map<String, Value>,
109 #[serde(skip_serializing_if = "Map::is_empty")]
111 pub inc: Map<String, Value>,
112}
113
114impl DocumentUpdate {
115 pub fn new() -> Self {
117 Self::default()
118 }
119
120 pub fn set(mut self, path: &str, value: impl Into<Value>) -> Self {
122 self.set.insert(path.to_string(), value.into());
123 self
124 }
125
126 pub fn inc(mut self, path: &str, delta: impl Into<Value>) -> Self {
128 self.inc.insert(path.to_string(), delta.into());
129 self
130 }
131
132 fn is_empty(&self) -> bool {
133 self.set.is_empty() && self.inc.is_empty()
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Serialize)]
139#[serde(transparent)]
140pub struct GroupKey(Value);
141
142impl GroupKey {
143 pub fn field(path: &str) -> Self {
146 GroupKey(json!({"Field": path}))
147 }
148
149 pub fn constant(value: impl Into<Value>) -> Self {
152 GroupKey(json!({"Constant": value.into()}))
153 }
154}
155
156#[derive(Debug, Clone, PartialEq, Serialize)]
158#[serde(transparent)]
159pub struct AccumulatorOp(Value);
160
161impl AccumulatorOp {
162 pub fn sum(field: &str) -> Self {
165 AccumulatorOp(json!({"Sum": field}))
166 }
167
168 pub fn avg(field: &str) -> Self {
170 AccumulatorOp(json!({"Avg": field}))
171 }
172
173 pub fn min(field: &str) -> Self {
175 AccumulatorOp(json!({"Min": field}))
176 }
177
178 pub fn max(field: &str) -> Self {
180 AccumulatorOp(json!({"Max": field}))
181 }
182
183 pub fn count() -> Self {
186 AccumulatorOp(Value::String("Count".into()))
187 }
188}
189
190#[derive(Debug, Clone, PartialEq, Serialize)]
195pub struct GroupAccumulator {
196 pub output: String,
198 pub op: AccumulatorOp,
200}
201
202impl GroupAccumulator {
203 pub fn new(output: &str, op: AccumulatorOp) -> Self {
205 Self {
206 output: output.to_string(),
207 op,
208 }
209 }
210}
211
212#[derive(Debug, Clone, PartialEq, Serialize)]
215pub struct SortKey {
216 pub field: String,
218 pub descending: bool,
220}
221
222impl SortKey {
223 pub fn ascending(field: &str) -> Self {
225 Self {
226 field: field.to_string(),
227 descending: false,
228 }
229 }
230
231 pub fn descending(field: &str) -> Self {
233 Self {
234 field: field.to_string(),
235 descending: true,
236 }
237 }
238}
239
240#[derive(Debug, Clone, PartialEq, Serialize)]
245#[serde(transparent)]
246pub struct AggregateStage(Value);
247
248impl AggregateStage {
249 pub fn filter(filter: DocumentFilter) -> Self {
251 AggregateStage(json!({"Match": filter}))
252 }
253
254 pub fn group(by: GroupKey, accumulators: impl IntoIterator<Item = GroupAccumulator>) -> Self {
256 let accumulators: Vec<GroupAccumulator> = accumulators.into_iter().collect();
257 AggregateStage(json!({"Group": {"by": by, "accumulators": accumulators}}))
258 }
259
260 pub fn sort(keys: impl IntoIterator<Item = SortKey>) -> Self {
262 let keys: Vec<SortKey> = keys.into_iter().collect();
263 AggregateStage(json!({"Sort": keys}))
264 }
265
266 pub fn skip(n: usize) -> Self {
268 AggregateStage(json!({"Skip": n}))
269 }
270
271 pub fn limit(n: usize) -> Self {
273 AggregateStage(json!({"Limit": n}))
274 }
275
276 pub fn project(fields: impl IntoIterator<Item = impl Into<String>>, include: bool) -> Self {
279 let fields: Vec<String> = fields.into_iter().map(Into::into).collect();
280 AggregateStage(json!({"Project": {"fields": fields, "include": include}}))
281 }
282
283 pub fn count(field: &str) -> Self {
285 AggregateStage(json!({"Count": {"field": field}}))
286 }
287}
288
289#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
291pub struct DocumentIndex {
292 #[serde(rename = "index_name")]
294 pub name: String,
295 #[serde(default)]
297 pub field: String,
298 #[serde(default)]
300 pub unique: bool,
301}
302
303#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
305pub struct DocumentStats {
306 #[serde(rename = "analyzed")]
308 pub collection: String,
309 #[serde(default)]
311 pub document_count: i64,
312 #[serde(default)]
314 pub indexed_fields: i64,
315}
316
317#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize)]
323pub struct UpdateCounts {
324 #[serde(default)]
326 pub matched: i64,
327 #[serde(default)]
329 pub modified: i64,
330}
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize)]
335pub enum ReturnDocument {
336 #[default]
338 None,
339 Before,
342 After,
344}
345
346#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
349pub struct ReplaceOptions {
350 pub upsert: bool,
352 pub return_document: ReturnDocument,
354 pub expected_version: Option<u64>,
357}
358
359#[derive(Debug, Clone, PartialEq, Deserialize)]
361pub struct ReplaceResult {
362 #[serde(default)]
364 pub id: String,
365 #[serde(default)]
367 pub replaced: bool,
368 #[serde(default)]
370 pub inserted: bool,
371 #[serde(default)]
374 pub document: Option<Document>,
375}
376
377#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize)]
379pub struct PurgeCounts {
380 #[serde(default)]
382 pub purged: i64,
383 #[serde(default)]
385 pub more: bool,
386}
387
388#[derive(Debug, Clone, Default, PartialEq)]
391pub struct ExplainOptions {
392 pub limit: Option<usize>,
394 pub sort: Vec<SortKey>,
396 pub skip: Option<usize>,
398}
399
400#[derive(Debug, Clone, PartialEq, Deserialize)]
402pub struct DocumentPlan {
403 #[serde(default)]
405 pub plan: String,
406 #[serde(default)]
408 pub index: Option<String>,
409 #[serde(default)]
411 pub index_used: bool,
412 #[serde(default)]
414 pub scan_reason: Option<String>,
415 #[serde(default)]
417 pub scan_source: Option<String>,
418 #[serde(default)]
420 pub estimated_rows: f64,
421 #[serde(default)]
423 pub estimated_cost: f64,
424 #[serde(default)]
426 pub rows_examined: i64,
427 #[serde(default)]
429 pub rows_returned: i64,
430 #[serde(default)]
432 pub elapsed_us: i64,
433}
434
435#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
437pub struct IndexRebuild {
438 #[serde(rename = "rebuilt")]
440 pub index_name: String,
441 #[serde(default)]
443 pub documents: i64,
444 #[serde(default)]
446 pub entries: i64,
447}
448
449#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize)]
451pub struct DocumentCommit {
452 #[serde(default)]
454 pub committed: bool,
455 #[serde(default)]
457 pub writes: i64,
458}
459
460#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
463#[serde(rename_all = "snake_case")]
464pub enum FieldType {
465 String,
467 Number,
469 Integer,
471 Boolean,
473 Object,
475 Array,
477 Null,
479}
480
481#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
483pub struct FieldRule {
484 #[serde(default, rename = "type", skip_serializing_if = "Option::is_none")]
486 pub field_type: Option<FieldType>,
487 #[serde(default, skip_serializing_if = "Vec::is_empty")]
489 pub one_of: Vec<Value>,
490 #[serde(default, skip_serializing_if = "Option::is_none")]
492 pub minimum: Option<f64>,
493 #[serde(default, skip_serializing_if = "Option::is_none")]
495 pub maximum: Option<f64>,
496 #[serde(default, skip_serializing_if = "Option::is_none")]
498 pub min_length: Option<usize>,
499 #[serde(default, skip_serializing_if = "Option::is_none")]
501 pub max_length: Option<usize>,
502 #[serde(default, skip_serializing_if = "Option::is_none")]
504 pub pattern: Option<String>,
505}
506
507impl FieldRule {
508 pub fn of_type(field_type: FieldType) -> Self {
510 Self {
511 field_type: Some(field_type),
512 ..Self::default()
513 }
514 }
515}
516
517#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
520pub struct DocumentSchema {
521 #[serde(default)]
523 pub required: Vec<String>,
524 #[serde(default)]
526 pub fields: BTreeMap<String, FieldRule>,
527 #[serde(default = "yes")]
530 pub additional_fields: bool,
531}
532
533impl Default for DocumentSchema {
534 fn default() -> Self {
535 Self {
536 required: Vec::new(),
537 fields: BTreeMap::new(),
538 additional_fields: true,
539 }
540 }
541}
542
543fn yes() -> bool {
544 true
545}
546
547#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
549pub struct CollectionOptions {
550 #[serde(default, skip_serializing_if = "Option::is_none")]
553 pub schema: Option<DocumentSchema>,
554 #[serde(default, skip_serializing_if = "Map::is_empty")]
557 pub defaults: Map<String, Value>,
558 #[serde(default)]
561 pub versioned: bool,
562}
563
564#[derive(Debug, Clone, PartialEq, Serialize)]
577pub enum BulkOp {
578 Insert {
580 id: Option<String>,
583 document: Value,
585 },
586 UpdateOne {
588 id: String,
590 update: DocumentUpdate,
592 upsert: bool,
594 expected_version: Option<u64>,
596 },
597 Replace {
599 id: String,
601 document: Value,
603 upsert: bool,
605 expected_version: Option<u64>,
607 },
608 Delete {
610 id: String,
612 expected_version: Option<u64>,
614 },
615}
616
617impl BulkOp {
618 pub fn insert(document: impl Into<Value>) -> Self {
620 BulkOp::Insert {
621 id: None,
622 document: document.into(),
623 }
624 }
625
626 pub fn insert_with_id(id: &str, document: impl Into<Value>) -> Self {
628 BulkOp::Insert {
629 id: Some(id.to_string()),
630 document: document.into(),
631 }
632 }
633
634 pub fn update_one(id: &str, update: DocumentUpdate) -> Self {
636 BulkOp::UpdateOne {
637 id: id.to_string(),
638 update,
639 upsert: false,
640 expected_version: None,
641 }
642 }
643
644 pub fn replace(id: &str, document: impl Into<Value>) -> Self {
646 BulkOp::Replace {
647 id: id.to_string(),
648 document: document.into(),
649 upsert: false,
650 expected_version: None,
651 }
652 }
653
654 pub fn delete(id: &str) -> Self {
656 BulkOp::Delete {
657 id: id.to_string(),
658 expected_version: None,
659 }
660 }
661
662 pub fn upsert(mut self) -> Self {
665 if let BulkOp::UpdateOne { upsert, .. } | BulkOp::Replace { upsert, .. } = &mut self {
666 *upsert = true;
667 }
668 self
669 }
670
671 pub fn expected_version(mut self, version: u64) -> Self {
674 match &mut self {
675 BulkOp::UpdateOne {
676 expected_version, ..
677 }
678 | BulkOp::Replace {
679 expected_version, ..
680 }
681 | BulkOp::Delete {
682 expected_version, ..
683 } => *expected_version = Some(version),
684 BulkOp::Insert { .. } => {}
685 }
686 self
687 }
688}
689
690#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize)]
692pub struct BulkWriteResult {
693 #[serde(default)]
695 pub inserted: i64,
696 #[serde(default)]
698 pub updated: i64,
699 #[serde(default)]
701 pub upserted: i64,
702 #[serde(default)]
704 pub replaced: i64,
705 #[serde(default)]
707 pub deleted: i64,
708 #[serde(default)]
711 pub inserted_ids: Vec<String>,
712}
713
714fn op(body: Value) -> Value {
715 json!({"Document": body})
716}
717
718impl Client {
719 pub fn document_create_collection(&mut self, collection: &str) -> Result<()> {
721 self.send(op(json!({"CreateCollection": {"collection": collection}})))
722 .map(|_| ())
723 }
724
725 pub fn document_drop_collection(&mut self, collection: &str) -> Result<()> {
728 self.send(op(json!({"DropCollection": {"collection": collection}})))
729 .map(|_| ())
730 }
731
732 pub fn document_list_collections(&mut self) -> Result<Vec<String>> {
734 #[derive(Deserialize)]
735 struct Collections {
736 #[serde(default)]
737 collections: Vec<String>,
738 }
739 let response = self.send(op(Value::String("ListCollections".into())))?;
740 let out: Collections = response.decode("ListCollections")?;
741 Ok(out.collections)
742 }
743
744 pub fn document_insert(
746 &mut self,
747 collection: &str,
748 document: &impl Serialize,
749 ) -> Result<String> {
750 self.document_insert_inner(collection, Value::Null, document)
751 }
752
753 pub fn document_insert_with_id(
756 &mut self,
757 collection: &str,
758 id: &str,
759 document: &impl Serialize,
760 ) -> Result<String> {
761 self.document_insert_inner(collection, json!(id), document)
762 }
763
764 fn document_insert_inner(
765 &mut self,
766 collection: &str,
767 id: Value,
768 document: &impl Serialize,
769 ) -> Result<String> {
770 #[derive(Deserialize)]
771 struct Inserted {
772 #[serde(default)]
773 id: String,
774 }
775 let document = serde_json::to_value(document)
776 .map_err(|e| Error::invalid(format!("the document cannot be encoded as JSON: {e}")))?;
777 if !document.is_object() {
778 return Err(Error::invalid(
779 "a document must encode to a JSON object, not a scalar or an array",
780 ));
781 }
782 let response = self.send(op(json!({"Insert": {
783 "collection": collection,
784 "id": id,
785 "document": document,
786 }})))?;
787 let out: Inserted = response.decode("Insert")?;
788 if out.id.is_empty() {
789 return Err(Error::protocol("Insert answered with no document id"));
790 }
791 Ok(out.id)
792 }
793
794 pub fn document_get(&mut self, collection: &str, id: &str) -> Result<Option<Document>> {
797 let response = self.send(op(json!({"Get": {"collection": collection, "id": id}})))?;
798 Ok(documents_of(&response, "Get")?.into_iter().next())
799 }
800
801 pub fn document_find(
803 &mut self,
804 collection: &str,
805 filter: &DocumentFilter,
806 ) -> Result<Vec<Document>> {
807 self.document_find_inner(collection, filter, Value::Null)
808 }
809
810 pub fn document_find_limit(
812 &mut self,
813 collection: &str,
814 filter: &DocumentFilter,
815 limit: usize,
816 ) -> Result<Vec<Document>> {
817 let limit = if limit == 0 {
818 Value::Null
819 } else {
820 json!(limit)
821 };
822 self.document_find_inner(collection, filter, limit)
823 }
824
825 fn document_find_inner(
826 &mut self,
827 collection: &str,
828 filter: &DocumentFilter,
829 limit: Value,
830 ) -> Result<Vec<Document>> {
831 let response = self.send(op(json!({"Find": {
832 "collection": collection,
833 "filter": filter,
834 "limit": limit,
835 }})))?;
836 documents_of(&response, "Find")
837 }
838
839 pub fn document_update(
842 &mut self,
843 collection: &str,
844 id: &str,
845 set: &Map<String, Value>,
846 ) -> Result<()> {
847 self.send(op(json!({"Update": {
848 "collection": collection,
849 "id": id,
850 "set": set,
851 }})))
852 .map(|_| ())
853 }
854
855 pub fn document_update_one(
858 &mut self,
859 collection: &str,
860 id: &str,
861 update: &DocumentUpdate,
862 ) -> Result<()> {
863 self.update_one(collection, id, update, false).map(|_| ())
864 }
865
866 pub fn document_upsert_one(
869 &mut self,
870 collection: &str,
871 id: &str,
872 update: &DocumentUpdate,
873 ) -> Result<bool> {
874 let out = self.update_one(collection, id, update, true)?;
875 Ok(out.inserted)
876 }
877
878 fn update_one(
879 &mut self,
880 collection: &str,
881 id: &str,
882 update: &DocumentUpdate,
883 upsert: bool,
884 ) -> Result<UpdateOne> {
885 if update.is_empty() {
886 return Err(Error::invalid(
887 "an update must set or increment at least one field",
888 ));
889 }
890 let response = self.send(op(json!({"UpdateOne": {
891 "collection": collection,
892 "id": id,
893 "update": update,
894 "upsert": upsert,
895 }})))?;
896 response.decode("UpdateOne")
897 }
898
899 pub fn document_update_many(
902 &mut self,
903 collection: &str,
904 filter: &DocumentFilter,
905 update: &DocumentUpdate,
906 ) -> Result<UpdateCounts> {
907 if update.is_empty() {
908 return Err(Error::invalid(
909 "an update must set or increment at least one field",
910 ));
911 }
912 let response = self.send(op(json!({"UpdateMany": {
913 "collection": collection,
914 "filter": filter,
915 "update": update,
916 }})))?;
917 response.decode("UpdateMany")
918 }
919
920 pub fn document_delete(&mut self, collection: &str, id: &str) -> Result<()> {
922 self.send(op(json!({"Delete": {"collection": collection, "id": id}})))
923 .map(|_| ())
924 }
925
926 pub fn document_create_index(
930 &mut self,
931 collection: &str,
932 index_name: &str,
933 field: &str,
934 unique: bool,
935 ) -> Result<()> {
936 self.send(op(json!({"CreateIndex": {
937 "collection": collection,
938 "index_name": index_name,
939 "field": field,
940 "unique": unique,
941 }})))
942 .map(|_| ())
943 }
944
945 pub fn document_drop_index(&mut self, collection: &str, index_name: &str) -> Result<()> {
947 self.send(op(json!({"DropIndex": {
948 "collection": collection,
949 "index_name": index_name,
950 }})))
951 .map(|_| ())
952 }
953
954 pub fn document_list_indexes(&mut self, collection: &str) -> Result<Vec<DocumentIndex>> {
956 #[derive(Deserialize)]
957 struct Indexes {
958 #[serde(default)]
959 indexes: Vec<DocumentIndex>,
960 }
961 let response = self.send(op(json!({"ListIndexes": {"collection": collection}})))?;
962 let out: Indexes = response.decode("ListIndexes")?;
963 Ok(out.indexes)
964 }
965
966 pub fn document_analyze(&mut self, collection: &str) -> Result<DocumentStats> {
969 let response = self.send(op(json!({"Analyze": {"collection": collection}})))?;
970 response.decode("Analyze")
971 }
972
973 pub fn document_aggregate(
990 &mut self,
991 collection: &str,
992 pipeline: &[AggregateStage],
993 ) -> Result<Vec<Document>> {
994 let response = self.send(op(json!({"Aggregate": {
995 "collection": collection,
996 "pipeline": pipeline,
997 }})))?;
998 documents_of(&response, "Aggregate")
999 }
1000
1001 pub fn document_replace(
1007 &mut self,
1008 collection: &str,
1009 id: &str,
1010 document: &impl Serialize,
1011 options: &ReplaceOptions,
1012 ) -> Result<ReplaceResult> {
1013 let mut body = Map::new();
1014 body.insert("collection".into(), json!(collection));
1015 body.insert("id".into(), json!(id));
1016 body.insert("document".into(), object_value(document)?);
1017 body.insert("upsert".into(), json!(options.upsert));
1018 if options.return_document != ReturnDocument::None {
1019 body.insert("return".into(), json!(options.return_document));
1020 }
1021 if let Some(version) = options.expected_version {
1022 body.insert("expected_version".into(), json!(version));
1023 }
1024 let response = self.send(op(json!({"Replace": Value::Object(body)})))?;
1025 response.decode("Replace")
1026 }
1027
1028 pub fn document_insert_many(
1034 &mut self,
1035 collection: &str,
1036 documents: &[impl Serialize],
1037 ) -> Result<Vec<String>> {
1038 #[derive(Deserialize)]
1039 struct Inserted {
1040 #[serde(default)]
1041 ids: Vec<String>,
1042 }
1043 let documents = documents
1044 .iter()
1045 .map(object_value)
1046 .collect::<Result<Vec<Value>>>()?;
1047 let response = self.send(op(json!({"InsertMany": {
1048 "collection": collection,
1049 "documents": documents,
1050 }})))?;
1051 let out: Inserted = response.decode("InsertMany")?;
1052 Ok(out.ids)
1053 }
1054
1055 pub fn document_delete_many(
1057 &mut self,
1058 collection: &str,
1059 filter: &DocumentFilter,
1060 ) -> Result<i64> {
1061 #[derive(Deserialize)]
1062 struct Deleted {
1063 #[serde(default)]
1064 deleted: i64,
1065 }
1066 let response = self.send(op(json!({"DeleteMany": {
1067 "collection": collection,
1068 "filter": filter,
1069 }})))?;
1070 let out: Deleted = response.decode("DeleteMany")?;
1071 Ok(out.deleted)
1072 }
1073
1074 pub fn document_rename_collection(&mut self, collection: &str, to: &str) -> Result<()> {
1077 self.send(op(json!({"RenameCollection": {
1078 "collection": collection,
1079 "to": to,
1080 }})))
1081 .map(|_| ())
1082 }
1083
1084 pub fn document_purge_expired(&mut self, collection: &str) -> Result<PurgeCounts> {
1086 let response = self.send(op(json!({"PurgeExpired": {"collection": collection}})))?;
1087 response.decode("PurgeExpired")
1088 }
1089
1090 pub fn document_explain(
1092 &mut self,
1093 collection: &str,
1094 filter: &DocumentFilter,
1095 options: &ExplainOptions,
1096 ) -> Result<DocumentPlan> {
1097 let mut body = Map::new();
1098 body.insert("collection".into(), json!(collection));
1099 body.insert("filter".into(), json!(filter));
1100 if let Some(limit) = options.limit {
1101 body.insert("limit".into(), json!(limit));
1102 }
1103 if !options.sort.is_empty() {
1104 body.insert("sort".into(), json!(options.sort));
1105 }
1106 if let Some(skip) = options.skip {
1107 body.insert("skip".into(), json!(skip));
1108 }
1109 let response = self.send(op(json!({"Explain": Value::Object(body)})))?;
1110 response.decode("Explain")
1111 }
1112
1113 pub fn document_begin_transaction(&mut self, serializable: bool) -> Result<String> {
1131 #[derive(Deserialize)]
1132 struct Begun {
1133 #[serde(default)]
1134 txn: String,
1135 }
1136 let response = self.send_in(
1137 op(json!({"BeginTransaction": {"serializable": serializable}})),
1138 None,
1139 )?;
1140 let out: Begun = response.decode("BeginTransaction")?;
1141 if out.txn.is_empty() {
1142 return Err(Error::protocol(
1143 "BeginTransaction answered with no transaction id",
1144 ));
1145 }
1146 Ok(out.txn)
1147 }
1148
1149 pub fn document_commit_transaction(&mut self, txn: &str) -> Result<DocumentCommit> {
1155 let outcome = self.send_in(op(json!("CommitTransaction")), Some(txn));
1156 self.forget_txn(txn);
1157 outcome?.decode("CommitTransaction")
1158 }
1159
1160 pub fn document_rollback_transaction(&mut self, txn: &str) -> Result<()> {
1162 let outcome = self.send_in(op(json!("RollbackTransaction")), Some(txn));
1163 self.forget_txn(txn);
1164 outcome.map(|_| ())
1165 }
1166
1167 pub fn document_rebuild_index(
1170 &mut self,
1171 collection: &str,
1172 index_name: &str,
1173 ) -> Result<IndexRebuild> {
1174 let response = self.send(op(json!({"RebuildIndex": {
1175 "collection": collection,
1176 "index_name": index_name,
1177 }})))?;
1178 response.decode("RebuildIndex")
1179 }
1180
1181 pub fn document_set_collection_options(
1185 &mut self,
1186 collection: &str,
1187 options: &CollectionOptions,
1188 ) -> Result<i64> {
1189 #[derive(Deserialize)]
1190 struct Updated {
1191 #[serde(default)]
1192 documents_checked: i64,
1193 }
1194 let response = self.send(op(json!({"SetCollectionOptions": {
1195 "collection": collection,
1196 "options": options,
1197 }})))?;
1198 let out: Updated = response.decode("SetCollectionOptions")?;
1199 Ok(out.documents_checked)
1200 }
1201
1202 pub fn document_get_collection_options(
1204 &mut self,
1205 collection: &str,
1206 ) -> Result<CollectionOptions> {
1207 #[derive(Deserialize)]
1208 struct Wire {
1209 #[serde(default)]
1210 options: CollectionOptions,
1211 }
1212 let response = self.send(op(
1213 json!({"GetCollectionOptions": {"collection": collection}}),
1214 ))?;
1215 let out: Wire = response.decode("GetCollectionOptions")?;
1216 Ok(out.options)
1217 }
1218
1219 pub fn document_bulk_write(
1223 &mut self,
1224 collection: &str,
1225 ops: &[BulkOp],
1226 ) -> Result<BulkWriteResult> {
1227 let response = self.send(op(json!({"BulkWrite": {
1228 "collection": collection,
1229 "ops": ops,
1230 }})))?;
1231 response.decode("BulkWrite")
1232 }
1233}
1234
1235fn object_value(document: &impl Serialize) -> Result<Value> {
1237 let document = serde_json::to_value(document)
1238 .map_err(|e| Error::invalid(format!("the document cannot be encoded as JSON: {e}")))?;
1239 if !document.is_object() {
1240 return Err(Error::invalid(
1241 "a document must encode to a JSON object, not a scalar or an array",
1242 ));
1243 }
1244 Ok(document)
1245}
1246
1247#[derive(Deserialize)]
1248struct UpdateOne {
1249 #[serde(default)]
1250 #[allow(dead_code)]
1251 updated: bool,
1252 #[serde(default)]
1253 inserted: bool,
1254}
1255
1256fn documents_of(response: &Response, what: &str) -> Result<Vec<Document>> {
1257 let data = response.expect("Documents", what)?;
1258 serde_json::from_value(data.clone())
1259 .map_err(|e| Error::protocol(format!("malformed Documents payload from {what}: {e}")))
1260}
1261
1262#[cfg(test)]
1263mod tests {
1264 use super::*;
1265
1266 fn wire(value: &impl Serialize) -> Value {
1267 serde_json::to_value(value).unwrap()
1268 }
1269
1270 #[test]
1271 fn filters_are_externally_tagged() {
1272 assert_eq!(wire(&DocumentFilter::all()), json!("All"));
1273 assert_eq!(
1274 wire(&DocumentFilter::eq("kind", "widget")),
1275 json!({"Eq": {"field": "kind", "value": "widget"}})
1276 );
1277 assert_eq!(
1278 wire(&DocumentFilter::lt("price", 10)),
1279 json!({"Lt": {"field": "price", "value": 10}})
1280 );
1281 assert_eq!(
1282 wire(&DocumentFilter::is_in("id", ["a", "b"])),
1283 json!({"In": {"field": "id", "values": ["a", "b"]}})
1284 );
1285 }
1286
1287 #[test]
1288 fn and_nests_its_children_in_order() {
1289 let filter = DocumentFilter::and([DocumentFilter::eq("a", 1), DocumentFilter::gt("b", 2)]);
1290 let value = wire(&filter);
1291 assert_eq!(value["And"][0]["Eq"]["field"], "a");
1292 assert_eq!(value["And"][1]["Gt"]["field"], "b");
1293 }
1294
1295 #[test]
1296 fn an_update_omits_the_half_it_does_not_use() {
1297 let update = DocumentUpdate::new().set("name", "ada");
1298 assert_eq!(wire(&update), json!({"set": {"name": "ada"}}));
1299 let update = DocumentUpdate::new().inc("hits", 1);
1300 assert_eq!(wire(&update), json!({"inc": {"hits": 1}}));
1301 assert!(DocumentUpdate::new().is_empty());
1302 }
1303
1304 #[test]
1305 fn pipeline_stages_keep_the_servers_own_names() {
1306 assert_eq!(
1307 wire(&AggregateStage::filter(DocumentFilter::all())),
1308 json!({"Match": "All"})
1309 );
1310 assert_eq!(wire(&AggregateStage::skip(2)), json!({"Skip": 2}));
1311 assert_eq!(wire(&AggregateStage::limit(5)), json!({"Limit": 5}));
1312 assert_eq!(
1313 wire(&AggregateStage::count("n")),
1314 json!({"Count": {"field": "n"}})
1315 );
1316 assert_eq!(
1317 wire(&AggregateStage::project(["a", "b"], true)),
1318 json!({"Project": {"fields": ["a", "b"], "include": true}})
1319 );
1320 }
1321
1322 #[test]
1323 fn a_group_stage_carries_its_key_and_accumulators() {
1324 let stage = AggregateStage::group(
1325 GroupKey::field("customer"),
1326 [
1327 GroupAccumulator::new("total", AccumulatorOp::sum("amount")),
1328 GroupAccumulator::new("orders", AccumulatorOp::count()),
1329 ],
1330 );
1331 let value = wire(&stage);
1332 assert_eq!(value["Group"]["by"], json!({"Field": "customer"}));
1333 assert_eq!(value["Group"]["accumulators"][0]["output"], "total");
1334 assert_eq!(
1335 value["Group"]["accumulators"][0]["op"],
1336 json!({"Sum": "amount"})
1337 );
1338 assert_eq!(value["Group"]["accumulators"][1]["op"], json!("Count"));
1339 }
1340
1341 #[test]
1342 fn sort_keys_say_which_way_they_go() {
1343 assert_eq!(
1344 wire(&AggregateStage::sort([SortKey::descending("total")])),
1345 json!({"Sort": [{"field": "total", "descending": true}]})
1346 );
1347 assert_eq!(
1348 wire(&SortKey::ascending("name")),
1349 json!({"field": "name", "descending": false})
1350 );
1351 }
1352}