Skip to main content

tauri_plugin_mongoose/db/
documents.rs

1use mongodb::{bson::{oid::ObjectId, Document}, options::{FindOptions as MongoFindOptions, FindOneOptions as MongoFindOneOptions}};
2use serde_json::Value;
3use serde::Deserialize;
4use futures::stream::TryStreamExt;
5use crate::db::state::{get_client, get_db_name};
6
7#[derive(Debug, Deserialize)]
8pub struct SearchOptions {
9    pub skip: Option<u64>,
10    pub limit: Option<i64>,
11    pub page: Option<u64>,
12    pub sort: Option<Value>,
13}
14
15pub async fn create_document(collection_name: String, document: Value) -> Result<Value, String> {
16    let client = get_client().await?;
17    let db_name = get_db_name().await;
18    
19    let db = client.database(&db_name);
20    let collection = db.collection::<Document>(&collection_name);
21
22    let mut bson_doc = mongodb::bson::to_document(&document).map_err(|e| e.to_string())?;
23    
24    if !bson_doc.contains_key("_id") {
25        bson_doc.insert("_id", ObjectId::new());
26    }
27
28    collection.insert_one(bson_doc.clone(), None).await.map_err(|e| e.to_string())?;
29
30    let json_doc: Value = mongodb::bson::from_document(bson_doc).map_err(|e| e.to_string())?;
31    Ok(json_doc)
32}
33
34pub async fn get_document_by_id(collection_name: String, id: String) -> Result<Option<Value>, String> {
35    let client = get_client().await?;
36    let db_name = get_db_name().await;
37    
38    let db = client.database(&db_name);
39    let collection = db.collection::<Document>(&collection_name);
40
41    let oid = ObjectId::parse_str(&id).map_err(|e| format!("Invalid ID format: {}", e))?;
42    let filter = mongodb::bson::doc! { "_id": oid };
43
44    let result = collection.find_one(filter, None).await.map_err(|e| e.to_string())?;
45
46    match result {
47        Some(doc) => {
48            let json_doc: Value = mongodb::bson::from_document(doc).map_err(|e| e.to_string())?;
49            Ok(Some(json_doc))
50        },
51        None => Ok(None)
52    }
53}
54
55pub async fn find_documents(collection_name: String, filter: Option<Value>, options: Option<SearchOptions>) -> Result<Vec<Value>, String> {
56    let client = get_client().await?;
57    let db_name = get_db_name().await;
58    
59    let db = client.database(&db_name);
60    let collection = db.collection::<Document>(&collection_name);
61
62    let mut find_options = MongoFindOptions::builder().build();
63    
64    if let Some(opts) = options {
65        if let Some(limit) = opts.limit {
66            find_options.limit = Some(limit);
67        }
68        
69        let mut skip = opts.skip.unwrap_or(0);
70        if let Some(page) = opts.page {
71           if page > 0 {
72                let limit = opts.limit.unwrap_or(10); // Default limit 10 if page is set
73                skip = (page as u64 - 1) * (limit as u64);
74                // Also ensure limit is set if it wasn't
75                if find_options.limit.is_none() {
76                    find_options.limit = Some(limit);
77                }
78           }
79        }
80        find_options.skip = Some(skip);
81
82        if let Some(sort) = opts.sort {
83            if let Ok(sort_doc) = mongodb::bson::to_document(&sort) {
84                 find_options.sort = Some(sort_doc);
85            }
86        }
87    }
88
89    let query = if let Some(f) = filter {
90        mongodb::bson::to_document(&f).map_err(|e| e.to_string())?
91    } else {
92        mongodb::bson::doc! {}
93    };
94
95    let mut cursor = collection.find(query, find_options).await.map_err(|e| e.to_string())?;
96    
97    let mut docs = Vec::new();
98    while let Some(result) = cursor.try_next().await.map_err(|e| e.to_string())? {
99        let json_doc: Value = mongodb::bson::from_document(result).map_err(|e| e.to_string())?;
100        docs.push(json_doc);
101    }
102    
103    Ok(docs)
104}
105
106pub async fn find_one_document(collection_name: String, filter: Option<Value>, options: Option<SearchOptions>) -> Result<Option<Value>, String> {
107    let client = get_client().await?;
108    let db_name = get_db_name().await;
109    
110    let db = client.database(&db_name);
111    let collection = db.collection::<Document>(&collection_name);
112
113    let mut find_options = MongoFindOneOptions::builder().build();
114
115    if let Some(opts) = options {
116       if let Some(skip) = opts.skip {
117           find_options.skip = Some(skip);
118       }
119       
120       if let Some(sort) = opts.sort {
121            if let Ok(sort_doc) = mongodb::bson::to_document(&sort) {
122                 find_options.sort = Some(sort_doc);
123            }
124       }
125       // Note: limit and page doesn't make much sense for findOne, usually. 
126       // Start/skip/sort apply.
127    }
128
129    let query = if let Some(f) = filter {
130        mongodb::bson::to_document(&f).map_err(|e| e.to_string())?
131    } else {
132        mongodb::bson::doc! {}
133    };
134
135    let result = collection.find_one(query, find_options).await.map_err(|e| e.to_string())?;
136
137    match result {
138        Some(doc) => {
139            let json_doc: Value = mongodb::bson::from_document(doc).map_err(|e| e.to_string())?;
140            Ok(Some(json_doc))
141        },
142        None => Ok(None)
143    }
144}