1use std::sync::Arc;
19
20use mea::once::OnceCell;
21
22use super::MONGODB_SCHEME;
23use super::config::MongodbConfig;
24use super::core::*;
25use super::deleter::MongodbDeleter;
26use super::reader::*;
27use super::writer::MongodbWriter;
28use opendal_core::raw::*;
29use opendal_core::*;
30
31#[doc = include_str!("docs.md")]
32#[derive(Debug, Default)]
33pub struct MongodbBuilder {
34 pub(super) config: MongodbConfig,
35}
36
37impl MongodbBuilder {
38 pub fn connection_string(mut self, v: &str) -> Self {
59 if !v.is_empty() {
60 self.config.connection_string = Some(v.to_string());
61 }
62 self
63 }
64 pub fn root(mut self, root: &str) -> Self {
68 self.config.root = if root.is_empty() {
69 None
70 } else {
71 Some(root.to_string())
72 };
73
74 self
75 }
76
77 pub fn database(mut self, database: &str) -> Self {
79 if !database.is_empty() {
80 self.config.database = Some(database.to_string());
81 }
82 self
83 }
84
85 pub fn collection(mut self, collection: &str) -> Self {
87 if !collection.is_empty() {
88 self.config.collection = Some(collection.to_string());
89 }
90 self
91 }
92
93 pub fn key_field(mut self, key_field: &str) -> Self {
97 if !key_field.is_empty() {
98 self.config.key_field = Some(key_field.to_string());
99 }
100 self
101 }
102
103 pub fn value_field(mut self, value_field: &str) -> Self {
107 if !value_field.is_empty() {
108 self.config.value_field = Some(value_field.to_string());
109 }
110 self
111 }
112}
113
114impl Builder for MongodbBuilder {
115 type Config = MongodbConfig;
116
117 fn build(self) -> Result<impl Service> {
118 let conn = match &self.config.connection_string.clone() {
119 Some(v) => v.clone(),
120 None => {
121 return Err(
122 Error::new(ErrorKind::ConfigInvalid, "connection_string is required")
123 .with_context("service", MONGODB_SCHEME),
124 );
125 }
126 };
127 let database = match &self.config.database.clone() {
128 Some(v) => v.clone(),
129 None => {
130 return Err(Error::new(ErrorKind::ConfigInvalid, "database is required")
131 .with_context("service", MONGODB_SCHEME));
132 }
133 };
134 let collection = match &self.config.collection.clone() {
135 Some(v) => v.clone(),
136 None => {
137 return Err(
138 Error::new(ErrorKind::ConfigInvalid, "collection is required")
139 .with_context("service", MONGODB_SCHEME),
140 );
141 }
142 };
143 let key_field = match &self.config.key_field.clone() {
144 Some(v) => v.clone(),
145 None => "key".to_string(),
146 };
147 let value_field = match &self.config.value_field.clone() {
148 Some(v) => v.clone(),
149 None => "value".to_string(),
150 };
151 let root = normalize_root(
152 self.config
153 .root
154 .clone()
155 .unwrap_or_else(|| "/".to_string())
156 .as_str(),
157 );
158 Ok(MongodbBackend::new(MongodbCore {
159 connection_string: conn,
160 database,
161 collection,
162 collection_instance: OnceCell::new(),
163 key_field,
164 value_field,
165 })
166 .with_normalized_root(root))
167 }
168}
169
170#[derive(Clone, Debug)]
172pub struct MongodbBackend {
173 pub(crate) core: Arc<MongodbCore>,
174 pub(crate) root: String,
175 pub(crate) info: ServiceInfo,
176 pub(crate) capability: Capability,
177}
178
179impl MongodbBackend {
180 pub fn new(core: MongodbCore) -> Self {
181 let info = ServiceInfo::new(
182 MONGODB_SCHEME,
183 "/",
184 format!("{}/{}", core.database, core.collection),
185 );
186 let capability = Capability {
187 read: true,
188 stat: true,
189 write: true,
190 write_can_empty: true,
191 delete: true,
192 shared: true,
193 ..Default::default()
194 };
195
196 Self {
197 core: Arc::new(core),
198 root: "/".to_string(),
199 info,
200 capability,
201 }
202 }
203
204 fn with_normalized_root(mut self, root: String) -> Self {
205 self.info = self.info.with_root(&root);
206 self.root = root;
207 self
208 }
209}
210
211impl Service for MongodbBackend {
212 type Reader = oio::StreamReader<MongodbReader>;
213 type Writer = MongodbWriter;
214 type Lister = ();
215 type Deleter = oio::OneShotDeleter<MongodbDeleter>;
216 type Copier = ();
217
218 fn info(&self) -> ServiceInfo {
219 self.info.clone()
220 }
221
222 fn capability(&self) -> Capability {
223 self.capability
224 }
225
226 async fn create_dir(
227 &self,
228 _ctx: &OperationContext,
229 _path: &str,
230 _args: OpCreateDir,
231 ) -> Result<RpCreateDir> {
232 Err(Error::new(
233 ErrorKind::Unsupported,
234 "operation is not supported",
235 ))
236 }
237
238 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
239 let p = build_abs_path(&self.root, path);
240
241 if p == build_abs_path(&self.root, "") {
242 Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
243 } else {
244 match self.core.get_length(&p).await? {
245 Some(length) => Ok(RpStat::new(
246 Metadata::new(EntryMode::FILE).with_content_length(length as u64),
247 )),
248 None => Err(Error::new(ErrorKind::NotFound, "kv not found in mongodb")),
249 }
250 }
251 }
252 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
253 let output: oio::StreamReader<MongodbReader> = {
254 Ok(oio::StreamReader::new(MongodbReader::new(
255 self.clone(),
256 path,
257 args,
258 )))
259 }?;
260
261 Ok(output)
262 }
263
264 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
265 let output: MongodbWriter = {
266 let p = build_abs_path(&self.root, path);
267 Ok(MongodbWriter::new(self.core.clone(), p))
268 }?;
269
270 Ok(output)
271 }
272
273 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
274 let output: oio::OneShotDeleter<MongodbDeleter> = {
275 Ok(oio::OneShotDeleter::new(MongodbDeleter::new(
276 self.core.clone(),
277 self.root.clone(),
278 )))
279 }?;
280
281 Ok(output)
282 }
283
284 fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
285 Err(Error::new(
286 ErrorKind::Unsupported,
287 "operation is not supported",
288 ))
289 }
290
291 fn copy(
292 &self,
293 _ctx: &OperationContext,
294 _from: &str,
295 _to: &str,
296 _args: OpCopy,
297 _opts: OpCopier,
298 ) -> Result<Self::Copier> {
299 Err(Error::new(
300 ErrorKind::Unsupported,
301 "operation is not supported",
302 ))
303 }
304
305 async fn rename(
306 &self,
307 _ctx: &OperationContext,
308 _from: &str,
309 _to: &str,
310 _args: OpRename,
311 ) -> Result<RpRename> {
312 Err(Error::new(
313 ErrorKind::Unsupported,
314 "operation is not supported",
315 ))
316 }
317
318 async fn presign(
319 &self,
320 _ctx: &OperationContext,
321 _path: &str,
322 _args: OpPresign,
323 ) -> Result<RpPresign> {
324 Err(Error::new(
325 ErrorKind::Unsupported,
326 "operation is not supported",
327 ))
328 }
329}