1use super::compile::{
4 CompiledDelete, CompiledInsert, CompiledQuery, CompiledUpdate, CompiledWrite, Keys, UpdateSpec,
5 compile_query, compile_write,
6};
7use super::value::from_bson;
8use ::mongodb::action::Action;
9use ::mongodb::bson::{Bson, Document, doc};
10use ::mongodb::error::{Error as DriverError, ErrorKind};
11use ::mongodb::options::ReturnDocument;
12use ::mongodb::{Client, ClientSession, Collection, Cursor, Database};
13use async_trait::async_trait;
14use siderite_orm::{
15 Backend, BackendCapabilities, BackendCapabilityError, BackendError, BackendKind, ExecResult,
16 Executor, Feature, IsolationLevel, OrmError, QueryError, QueryPlan, QueryResult, Row,
17 Transaction, Value, WritePlan,
18};
19use std::sync::Arc;
20use tokio::sync::Mutex;
21
22const COUNTERS: &str = "siderite_counters";
25
26#[derive(Debug, Clone)]
33pub struct MongoBackend {
34 client: Client,
35 db: Database,
36 keys: Arc<Keys>,
37}
38
39impl MongoBackend {
40 pub async fn connect(url: &str, database: &str) -> Result<Self, BackendError> {
46 let client = Client::with_uri_str(url)
47 .await
48 .map_err(|e| BackendError::Connection(e.to_string()))?;
49 client
50 .database("admin")
51 .run_command(doc! { "ping": 1_i32 })
52 .await
53 .map_err(|e| BackendError::Connection(e.to_string()))?;
54 Ok(Self::from_client(client, database))
55 }
56
57 pub fn from_client(client: Client, database: &str) -> Self {
59 Self {
60 db: client.database(database),
61 client,
62 keys: Arc::new(Keys::default()),
63 }
64 }
65
66 #[must_use]
69 pub fn with_keys(mut self, keys: Keys) -> Self {
70 self.keys = Arc::new(keys);
71 self
72 }
73
74 pub fn database(&self) -> &Database {
76 &self.db
77 }
78
79 pub async fn raw_command(&self, command: Document) -> Result<Document, OrmError> {
85 self.db
86 .run_command(command)
87 .await
88 .map_err(|e| map_error(&e).into())
89 }
90
91 pub async fn create_unique_index(
98 &self,
99 collection: &str,
100 column: &str,
101 ) -> Result<(), OrmError> {
102 let field = if column == self.keys.pk(collection) {
103 "_id"
104 } else {
105 column
106 };
107 let index = ::mongodb::IndexModel::builder()
108 .keys(doc! { field: 1_i32 })
109 .options(
110 ::mongodb::options::IndexOptions::builder()
111 .unique(true)
112 .build(),
113 )
114 .build();
115 self.db
116 .collection::<Document>(collection)
117 .create_index(index)
118 .await
119 .map_err(|e| OrmError::from(map_error(&e)))?;
120 Ok(())
121 }
122
123 async fn run_fetch(
124 &self,
125 plan: &QueryPlan,
126 session: Option<&mut ClientSession>,
127 ) -> Result<QueryResult, OrmError> {
128 let compiled = compile_query(plan, &self.keys)?;
129 Io {
130 db: &self.db,
131 session,
132 }
133 .query(&compiled)
134 .await
135 }
136
137 async fn run_execute(
138 &self,
139 plan: &WritePlan,
140 session: Option<&mut ClientSession>,
141 ) -> Result<ExecResult, OrmError> {
142 let compiled = compile_write(plan, &self.keys)?;
143 Io {
144 db: &self.db,
145 session,
146 }
147 .write(compiled)
148 .await
149 }
150}
151
152fn raw_unsupported() -> OrmError {
153 BackendCapabilityError::from_feature(BackendKind::MongoDb, Feature::RawSql).into()
154}
155
156#[async_trait]
157impl Executor for MongoBackend {
158 fn capabilities(&self) -> BackendCapabilities {
159 BackendCapabilities::mongodb()
160 }
161
162 async fn fetch(&self, plan: &QueryPlan) -> Result<QueryResult, OrmError> {
163 self.run_fetch(plan, None).await
164 }
165
166 async fn execute(&self, plan: &WritePlan) -> Result<ExecResult, OrmError> {
167 self.run_execute(plan, None).await
168 }
169
170 async fn fetch_raw(&self, _sql: &str, _params: Vec<Value>) -> Result<QueryResult, OrmError> {
171 Err(raw_unsupported())
172 }
173
174 async fn execute_raw(&self, _sql: &str, _params: Vec<Value>) -> Result<u64, OrmError> {
175 Err(raw_unsupported())
176 }
177
178 async fn execute_script(&self, _sql: &str) -> Result<(), OrmError> {
179 Err(raw_unsupported())
180 }
181}
182
183#[async_trait]
184impl Backend for MongoBackend {
185 async fn begin(
186 &self,
187 isolation: Option<IsolationLevel>,
188 ) -> Result<Box<dyn Transaction>, OrmError> {
189 if let Some(level) = isolation {
190 self.capabilities().require(Feature::Isolation(level))?;
191 }
192 let mut session = self
193 .client
194 .start_session()
195 .await
196 .map_err(|e| OrmError::from(map_error(&e)))?;
197 session
198 .start_transaction()
199 .await
200 .map_err(|e| OrmError::from(map_error(&e)))?;
201 Ok(Box::new(MongoTransaction {
202 backend: self.clone(),
203 session: Mutex::new(Some(session)),
204 }))
205 }
206}
207
208struct MongoTransaction {
210 backend: MongoBackend,
211 session: Mutex<Option<ClientSession>>,
212}
213
214impl MongoTransaction {
215 async fn take(&self) -> Result<ClientSession, QueryError> {
216 self.session
217 .lock()
218 .await
219 .take()
220 .ok_or(QueryError::TransactionClosed)
221 }
222}
223
224#[async_trait]
225impl Executor for MongoTransaction {
226 fn capabilities(&self) -> BackendCapabilities {
227 BackendCapabilities::mongodb()
228 }
229
230 async fn fetch(&self, plan: &QueryPlan) -> Result<QueryResult, OrmError> {
231 let compiled = compile_query(plan, &self.backend.keys)?;
233 let mut guard = self.session.lock().await;
234 let session = guard.as_mut().ok_or(QueryError::TransactionClosed)?;
235 Io {
236 db: &self.backend.db,
237 session: Some(session),
238 }
239 .query(&compiled)
240 .await
241 }
242
243 async fn execute(&self, plan: &WritePlan) -> Result<ExecResult, OrmError> {
244 let compiled = compile_write(plan, &self.backend.keys)?;
245 let mut guard = self.session.lock().await;
246 let session = guard.as_mut().ok_or(QueryError::TransactionClosed)?;
247 Io {
248 db: &self.backend.db,
249 session: Some(session),
250 }
251 .write(compiled)
252 .await
253 }
254
255 async fn fetch_raw(&self, _sql: &str, _params: Vec<Value>) -> Result<QueryResult, OrmError> {
256 Err(raw_unsupported())
257 }
258
259 async fn execute_raw(&self, _sql: &str, _params: Vec<Value>) -> Result<u64, OrmError> {
260 Err(raw_unsupported())
261 }
262
263 async fn execute_script(&self, _sql: &str) -> Result<(), OrmError> {
264 Err(raw_unsupported())
265 }
266}
267
268#[async_trait]
269impl Transaction for MongoTransaction {
270 async fn commit(&self) -> Result<(), OrmError> {
271 let mut session = self.take().await?;
272 session
273 .commit_transaction()
274 .await
275 .map_err(|e| map_error(&e).into())
276 }
277
278 async fn rollback(&self) -> Result<(), OrmError> {
279 let mut session = self.take().await?;
280 session
281 .abort_transaction()
282 .await
283 .map_err(|e| map_error(&e).into())
284 }
285}
286
287fn map_error(e: &DriverError) -> BackendError {
290 let message = e.to_string();
291 if message.contains("E11000")
292 || message.contains("code: 11000")
293 || message.contains("code: 121")
294 {
295 return BackendError::Constraint(message);
296 }
297 match e.kind.as_ref() {
298 ErrorKind::ServerSelection { .. }
299 | ErrorKind::Io(_)
300 | ErrorKind::DnsResolve { .. }
301 | ErrorKind::Authentication { .. } => BackendError::Connection(message),
302 _ => BackendError::Database(message),
303 }
304}
305
306fn db_err(e: &DriverError) -> OrmError {
307 map_error(e).into()
308}
309
310fn doc_to_row(doc: Document, columns: &[String], pk: &str) -> Result<Row, QueryError> {
313 if columns.is_empty() {
314 let has_pk_field = doc.contains_key(pk);
315 let mut out = Vec::with_capacity(doc.len());
316 for (key, value) in doc {
317 let name = if key == "_id" {
318 if has_pk_field {
319 continue;
320 }
321 pk.to_owned()
322 } else {
323 key
324 };
325 let value = from_bson(value, &name)?;
326 out.push((name, value));
327 }
328 return Ok(Row::new(out));
329 }
330 let mut out = Vec::with_capacity(columns.len());
331 for column in columns {
332 let key = if column == pk { "_id" } else { column.as_str() };
333 let value = match doc.get(key) {
334 Some(bson) => from_bson(bson.clone(), column)?,
335 None => Value::Null,
336 };
337 out.push((column.clone(), value));
338 }
339 Ok(Row::new(out))
340}
341
342struct Io<'a> {
344 db: &'a Database,
345 session: Option<&'a mut ClientSession>,
346}
347
348impl Io<'_> {
349 fn coll(&self, name: &str) -> Collection<Document> {
350 self.db.collection(name)
351 }
352
353 fn session(&mut self) -> Option<&mut ClientSession> {
354 self.session.as_deref_mut()
355 }
356
357 async fn aggregate(
358 &mut self,
359 collection: &str,
360 pipeline: Vec<Document>,
361 ) -> Result<Vec<Document>, OrmError> {
362 let coll = self.coll(collection);
363 let mut out = Vec::new();
364 match self.session() {
365 Some(session) => {
366 let mut cursor = coll
367 .aggregate(pipeline)
368 .session(&mut *session)
369 .await
370 .map_err(|e| db_err(&e))?;
371 while cursor.advance(session).await.map_err(|e| db_err(&e))? {
372 out.push(cursor.deserialize_current().map_err(|e| db_err(&e))?);
373 }
374 }
375 None => {
376 let cursor = coll.aggregate(pipeline).await.map_err(|e| db_err(&e))?;
377 out = drain(cursor).await?;
378 }
379 }
380 Ok(out)
381 }
382
383 async fn find(
384 &mut self,
385 collection: &str,
386 filter: Document,
387 projection: Option<Document>,
388 ) -> Result<Vec<Document>, OrmError> {
389 let coll = self.coll(collection);
390 let mut out = Vec::new();
391 match self.session() {
392 Some(session) => {
393 let mut cursor = coll
394 .find(filter)
395 .optional(projection, |a, p| a.projection(p))
396 .session(&mut *session)
397 .await
398 .map_err(|e| db_err(&e))?;
399 while cursor.advance(session).await.map_err(|e| db_err(&e))? {
400 out.push(cursor.deserialize_current().map_err(|e| db_err(&e))?);
401 }
402 }
403 None => {
404 let cursor = coll
405 .find(filter)
406 .optional(projection, |a, p| a.projection(p))
407 .await
408 .map_err(|e| db_err(&e))?;
409 out = drain(cursor).await?;
410 }
411 }
412 Ok(out)
413 }
414
415 async fn insert_many(&mut self, collection: &str, docs: Vec<Document>) -> Result<(), OrmError> {
416 let coll = self.coll(collection);
417 match self.session() {
418 Some(session) => coll.insert_many(docs).session(session).await,
419 None => coll.insert_many(docs).await,
420 }
421 .map(|_| ())
422 .map_err(|e| db_err(&e))
423 }
424
425 async fn update_many(
426 &mut self,
427 collection: &str,
428 filter: Document,
429 update: UpdateSpec,
430 ) -> Result<u64, OrmError> {
431 let coll = self.coll(collection);
432 let result = match (update, self.session()) {
433 (UpdateSpec::Set(doc), Some(s)) => coll.update_many(filter, doc).session(s).await,
434 (UpdateSpec::Set(doc), None) => coll.update_many(filter, doc).await,
435 (UpdateSpec::Pipeline(p), Some(s)) => coll.update_many(filter, p).session(s).await,
436 (UpdateSpec::Pipeline(p), None) => coll.update_many(filter, p).await,
437 };
438 result.map(|r| r.matched_count).map_err(|e| db_err(&e))
439 }
440
441 async fn delete_many(&mut self, collection: &str, filter: Document) -> Result<u64, OrmError> {
442 let coll = self.coll(collection);
443 match self.session() {
444 Some(session) => coll.delete_many(filter).session(session).await,
445 None => coll.delete_many(filter).await,
446 }
447 .map(|r| r.deleted_count)
448 .map_err(|e| db_err(&e))
449 }
450
451 async fn reserve_keys(&self, collection: &str, n: usize) -> Result<i64, OrmError> {
456 let n = i64::try_from(n).map_err(|_| QueryError::InvalidPlan("too many rows".into()))?;
457 let counters: Collection<Document> = self.db.collection(COUNTERS);
458 let after = counters
459 .find_one_and_update(doc! { "_id": collection }, doc! { "$inc": { "seq": n } })
460 .upsert(true)
461 .return_document(ReturnDocument::After)
462 .await
463 .map_err(|e| db_err(&e))?
464 .and_then(|d| d.get("seq").and_then(as_i64))
465 .ok_or_else(|| BackendError::Database("key counter has no `seq`".into()))?;
466 Ok(after - n + 1)
467 }
468
469 async fn query(&mut self, compiled: &CompiledQuery) -> Result<QueryResult, OrmError> {
470 let docs = self
471 .aggregate(&compiled.collection, compiled.pipeline.clone())
472 .await?;
473 if docs.is_empty()
474 && let Some(values) = &compiled.empty_row
475 {
476 let row = compiled
477 .columns
478 .iter()
479 .cloned()
480 .zip(values.iter().cloned())
481 .collect();
482 return Ok(QueryResult {
483 rows: vec![Row::new(row)],
484 });
485 }
486 let rows = docs
487 .into_iter()
488 .map(|d| doc_to_row(d, &compiled.columns, &compiled.pk))
489 .collect::<Result<_, _>>()?;
490 Ok(QueryResult { rows })
491 }
492
493 async fn write(&mut self, compiled: CompiledWrite) -> Result<ExecResult, OrmError> {
494 match compiled {
495 CompiledWrite::Insert(p) => self.insert(p).await,
496 CompiledWrite::Update(p) => self.update(p).await,
497 CompiledWrite::Delete(p) => self.delete(p).await,
498 }
499 }
500
501 async fn insert(&mut self, plan: CompiledInsert) -> Result<ExecResult, OrmError> {
502 let CompiledInsert {
503 collection,
504 pk,
505 docs,
506 returning,
507 } = plan;
508 if docs.is_empty() {
509 return Ok(ExecResult::default());
510 }
511 let missing = docs.iter().filter(|d| !d.contains_key("_id")).count();
512 let mut next = if missing > 0 {
513 self.reserve_keys(&collection, missing).await?
514 } else {
515 0
516 };
517 let docs: Vec<Document> = docs
518 .into_iter()
519 .map(|doc| {
520 if doc.contains_key("_id") {
521 return doc;
522 }
523 let mut with_id = doc! { "_id": next };
525 next += 1;
526 with_id.extend(doc);
527 with_id
528 })
529 .collect();
530 self.insert_many(&collection, docs.clone()).await?;
531 let mut result = ExecResult {
532 rows_affected: docs.len() as u64,
533 returning: Vec::new(),
534 };
535 if !returning.is_empty() {
536 result.returning = docs
538 .into_iter()
539 .map(|d| doc_to_row(d, &returning, &pk))
540 .collect::<Result<_, _>>()?;
541 }
542 Ok(result)
543 }
544
545 async fn update(&mut self, plan: CompiledUpdate) -> Result<ExecResult, OrmError> {
546 let CompiledUpdate {
547 collection,
548 pk,
549 filter,
550 update,
551 returning,
552 } = plan;
553 if returning.is_empty() {
554 let matched = self.update_many(&collection, filter, update).await?;
555 return Ok(ExecResult {
556 rows_affected: matched,
557 returning: Vec::new(),
558 });
559 }
560 let ids = self.matching_ids(&collection, filter).await?;
563 if ids.is_empty() {
564 return Ok(ExecResult::default());
565 }
566 let by_id = doc! { "_id": { "$in": ids } };
567 let matched = self.update_many(&collection, by_id.clone(), update).await?;
568 let rows = self
569 .find(&collection, by_id, None)
570 .await?
571 .into_iter()
572 .map(|d| doc_to_row(d, &returning, &pk))
573 .collect::<Result<_, _>>()?;
574 Ok(ExecResult {
575 rows_affected: matched,
576 returning: rows,
577 })
578 }
579
580 async fn delete(&mut self, plan: CompiledDelete) -> Result<ExecResult, OrmError> {
581 let CompiledDelete {
582 collection,
583 pk,
584 filter,
585 returning,
586 } = plan;
587 if returning.is_empty() {
588 let deleted = self.delete_many(&collection, filter).await?;
589 return Ok(ExecResult {
590 rows_affected: deleted,
591 returning: Vec::new(),
592 });
593 }
594 let docs = self.find(&collection, filter, None).await?;
595 let ids: Vec<Bson> = docs.iter().filter_map(|d| d.get("_id").cloned()).collect();
596 if ids.is_empty() {
597 return Ok(ExecResult::default());
598 }
599 let deleted = self
600 .delete_many(&collection, doc! { "_id": { "$in": ids } })
601 .await?;
602 let rows = docs
603 .into_iter()
604 .map(|d| doc_to_row(d, &returning, &pk))
605 .collect::<Result<_, _>>()?;
606 Ok(ExecResult {
607 rows_affected: deleted,
608 returning: rows,
609 })
610 }
611
612 async fn matching_ids(
613 &mut self,
614 collection: &str,
615 filter: Document,
616 ) -> Result<Vec<Bson>, OrmError> {
617 Ok(self
618 .find(collection, filter, Some(doc! { "_id": 1_i32 }))
619 .await?
620 .into_iter()
621 .filter_map(|d| d.get("_id").cloned())
622 .collect())
623 }
624}
625
626fn as_i64(value: &Bson) -> Option<i64> {
627 match value {
628 Bson::Int32(i) => Some(i64::from(*i)),
629 Bson::Int64(i) => Some(*i),
630 _ => None,
631 }
632}
633
634async fn drain(mut cursor: Cursor<Document>) -> Result<Vec<Document>, OrmError> {
635 let mut out = Vec::new();
636 while cursor.advance().await.map_err(|e| db_err(&e))? {
637 out.push(cursor.deserialize_current().map_err(|e| db_err(&e))?);
638 }
639 Ok(out)
640}