use super::{
MongodbConfigStore,
serde::{now_as_datetime, transform_from_mongo, transform_to_mongo, try_to_object_id},
};
use crate::storage::Error;
use mongodb::{
ClientSession, Collection,
bson::Document,
results::{InsertOneResult, UpdateResult},
};
use pbbson::Model;
use pbbson::bson::{self, Bson, doc};
use std::fmt::Debug;
use std::str::FromStr;
pub async fn create<B: Clone + Debug + FromStr + Send + Sync + ToString>(
this: &MongodbConfigStore<B>,
mut session: Option<&mut ClientSession>,
bucket: B,
model: Model,
) -> Result<Model, Error> {
let coll: Collection<Document> = this.db.collection(&bucket.to_string());
let now = now_as_datetime();
let mut model = model.clone();
model.set_datetime("createdAt", now);
if model.get("id").is_none() {
model.insert("id", bson::oid::ObjectId::new());
}
let mut local_model = transform_to_mongo(model.clone())?;
let local_model_id: Bson = match model.get("id") {
Some(Bson::Binary(binary)) => binary.into(),
Some(Bson::ObjectId(object_id)) => object_id.into(),
Some(Bson::String(id)) => try_to_object_id(id)?.into(),
_ => return Err(Error::internal("Unsupported id type")),
};
local_model.insert("_id", local_model_id.clone());
let maybe_created_by_account_id = local_model.get("createdByAccountId");
let _res: InsertOneResult = {
let op = coll.insert_one(local_model.clone());
if let Some(ref mut session) = session {
op.session(&mut **session).await?
} else {
op.await?
}
};
for belongs_to in this
.belongs_tos_by_bucket
.get(&bucket.to_string())
.cloned()
.unwrap_or_default()
{
let local_value = local_model.get(&belongs_to.local);
match local_value {
None => {}
Some(Bson::ObjectId(id)) => {
match belongs_to.inverse {
None => {
}
Some(inverse) => {
let add_to_set = doc! {&inverse: &local_model_id};
let mut set = doc! {"updatedAt": now};
if let Some(created_by_account_id) = maybe_created_by_account_id {
set.insert("updatedByAccountId", created_by_account_id);
}
let update = doc! {"$addToSet": add_to_set, "$set": set};
let remote_coll: Collection<Document> = this.db.collection(&belongs_to.remote.to_string());
let filter = doc! { "_id": id };
let res: UpdateResult = {
let op = remote_coll.update_one(filter, update);
if let Some(ref mut session) = session {
op.session(&mut **session).await?
} else {
op.await?
}
};
if res.matched_count == 0 {
}
}
}
}
_ => {
log::error!("Unknown fk type: {local_value:?}");
}
}
}
for has_many in this
.has_manys_by_bucket
.get(&bucket.to_string())
.cloned()
.unwrap_or_default()
{
let local_value = model.get(&has_many.local);
match local_value {
Some(Bson::Array(array)) => {
match has_many.inverse {
None => {
}
Some(inverse) => {
let remote_coll: Collection<Document> = this.db.collection(&has_many.remote.to_string());
for id in array.iter() {
let id = match id {
Bson::ObjectId(object_id) => *object_id,
Bson::String(id) => try_to_object_id(id)?,
_ => return Err(Error::invalid_argument("Unsupport fk datatype")),
};
let set = doc! {&inverse: &local_model_id, "updatedAt": now};
let update = doc! {"$set": set};
let filter = doc! { "_id": id };
let res: UpdateResult = {
let op = remote_coll.update_one(filter, update);
if let Some(ref mut session) = session {
op.session(&mut **session).await?
} else {
op.await?
}
};
if res.matched_count == 0 {
}
}
}
}
}
_ => {
log::error!("Unknown fk type: {local_value:?}");
}
}
}
transform_from_mongo(model)
}