1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use super::MemoryConfigStore;
use crate::storage::Error;
use pbbson::Model;
use pbbson::bson::Bson;
use std::fmt::Debug;
use std::str::FromStr;
pub async fn perform<B: Clone + Debug + FromStr + Send + Sync + ToString>(
this: &MemoryConfigStore<B>,
bucket: B,
model: Model,
) -> Result<Model, Error> {
let doc_holder = this.doc_holder(&bucket)?;
let mut model = model.clone();
let model_id = match model.id() {
Ok(id) => id,
_ => {
let id = xid::new().to_string();
model.insert("id", id.clone());
id
}
};
let mut docs = doc_holder
.docs
.lock()
.map_err(|e| Error::failed_precondition(e.to_string()))?;
// Store
docs.insert(model_id.clone(), model.clone());
// Maintain belongs-to fk's
for belongs_to in this
.belongs_tos_by_bucket
.get(&bucket.to_string())
.cloned()
.unwrap_or_default()
{
let local_value = model.get(&belongs_to.local);
match local_value {
Some(Bson::String(id)) => {
match belongs_to.inverse.clone() {
None => {
// TODO validate fk only
}
Some(inverse) => {
// Update foreign collection to reference this
let remote_bucket = this.doc_holder(&belongs_to.remote)?;
let mut remote_docs = remote_bucket
.docs
.lock()
.map_err(|e| Error::failed_precondition(e.to_string()))?;
let foreign_model = match remote_docs.get_mut(id) {
None => continue,
Some(foreign_model) => foreign_model,
};
match foreign_model.get_mut(&inverse) {
Some(foreign_field) => {
if let Bson::Array(array) = foreign_field {
array.push(Bson::String(model_id.clone()));
}
}
None => {
let array = vec![Bson::String(model_id.clone())];
foreign_model.insert(inverse.clone(), Bson::Array(array));
}
}
}
}
}
_ => {
log::error!("Unknown fk type: {local_value:?}");
}
}
}
// Maintain has-many fk's
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.clone() {
None => {
// TODO validate fk only
}
Some(inverse) => {
// Update foreign collection to reference this
let remote_bucket = this.doc_holder(&has_many.remote)?;
let mut remote_docs = remote_bucket
.docs
.lock()
.map_err(|e| Error::failed_precondition(e.to_string()))?;
for id in array.iter() {
if let Bson::String(id) = id {
let foreign_model = match remote_docs.get_mut(id.as_str()) {
None => {
continue;
}
Some(foreign_model) => foreign_model,
};
match foreign_model.get_mut(&inverse) {
Some(Bson::Array(array)) => array.push(Bson::String(model_id.clone())),
_ => {
foreign_model.insert(inverse.clone(), Bson::String(model_id.clone()));
}
};
}
}
}
}
}
_ => {
log::error!("Unknown fk type: {local_value:?}");
}
}
}
Ok(model)
}