teaql_runtime/
entity_runtime.rs1use std::collections::BTreeMap;
2use std::sync::{Arc, Mutex};
3
4use teaql_core::{Record, Value};
5
6#[derive(Debug, Clone)]
7pub struct EntityKey {
8 pub entity: String,
9 pub id: Value,
10 id_key: String,
11}
12
13impl EntityKey {
14 pub fn new(entity: impl Into<String>, id: impl Into<Value>) -> Self {
15 let id = id.into();
16 Self {
17 entity: entity.into(),
18 id_key: value_key(&id),
19 id,
20 }
21 }
22}
23
24impl PartialEq for EntityKey {
25 fn eq(&self, other: &Self) -> bool {
26 self.entity == other.entity && self.id_key == other.id_key
27 }
28}
29
30impl Eq for EntityKey {}
31
32impl PartialOrd for EntityKey {
33 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
34 Some(self.cmp(other))
35 }
36}
37
38impl Ord for EntityKey {
39 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
40 self.entity
41 .cmp(&other.entity)
42 .then_with(|| self.id_key.cmp(&other.id_key))
43 }
44}
45
46fn value_key(value: &Value) -> String {
47 match value {
48 Value::Null => "null".to_owned(),
49 Value::Bool(value) => format!("bool:{value}"),
50 Value::I64(value) => format!("i64:{value}"),
51 Value::U64(value) => format!("u64:{value}"),
52 Value::F64(value) => format!("f64:{value}"),
53 Value::Decimal(value) => format!("decimal:{value}"),
54 Value::Text(value) => format!("text:{value}"),
55 Value::Json(value) => format!("json:{value}"),
56 Value::Date(value) => format!("date:{value}"),
57 Value::Timestamp(value) => format!("timestamp:{}", value.to_rfc3339()),
58 Value::Object(_) => "object".to_owned(),
59 Value::List(_) => "list".to_owned(),
60 }
61}
62
63#[derive(Debug, Clone, Default, PartialEq)]
64pub struct EntityChangeSet {
65 changes: BTreeMap<EntityKey, Record>,
66}
67
68impl EntityChangeSet {
69 pub fn is_empty(&self) -> bool {
70 self.changes.is_empty()
71 }
72
73 pub fn set(&mut self, key: EntityKey, field: impl Into<String>, value: Value) {
74 self.changes
75 .entry(key)
76 .or_default()
77 .insert(field.into(), value);
78 }
79
80 pub fn get(&self, key: &EntityKey, field: &str) -> Option<&Value> {
81 self.changes.get(key).and_then(|changes| changes.get(field))
82 }
83
84 pub fn changes(&self) -> &BTreeMap<EntityKey, Record> {
85 &self.changes
86 }
87}
88
89#[derive(Debug, Clone, Default, PartialEq)]
90pub struct ChangeSetStack {
91 stack: Vec<EntityChangeSet>,
92}
93
94impl ChangeSetStack {
95 pub fn current_mut(&mut self) -> &mut EntityChangeSet {
96 if self.stack.is_empty() {
97 self.stack.push(EntityChangeSet::default());
98 }
99 self.stack.last_mut().expect("change set stack has current")
100 }
101
102 pub fn current(&self) -> Option<&EntityChangeSet> {
103 self.stack.last()
104 }
105
106 pub fn push(&mut self) {
107 self.stack.push(EntityChangeSet::default());
108 }
109
110 pub fn pop(&mut self) -> Option<EntityChangeSet> {
111 self.stack.pop()
112 }
113
114 pub fn get(&self, key: &EntityKey, field: &str) -> Option<Value> {
115 self.stack
116 .iter()
117 .rev()
118 .find_map(|change_set| change_set.get(key, field).cloned())
119 }
120
121 pub fn set(&mut self, key: EntityKey, field: impl Into<String>, value: Value) {
122 self.current_mut().set(key, field, value);
123 }
124
125 pub fn clear_current(&mut self) {
126 if let Some(current) = self.stack.last_mut() {
127 *current = EntityChangeSet::default();
128 }
129 }
130}
131
132#[derive(Debug, Default)]
133pub struct RootContext {
134 change_sets: ChangeSetStack,
135 comment: Option<String>,
137}
138
139#[derive(Debug, Clone, Default)]
140pub struct EntityRoot {
141 inner: Arc<Mutex<RootContext>>,
142}
143
144impl PartialEq for EntityRoot {
145 fn eq(&self, other: &Self) -> bool {
146 Arc::ptr_eq(&self.inner, &other.inner)
147 }
148}
149
150impl EntityRoot {
151 pub fn push_change_set(&self) {
152 self.inner
153 .lock()
154 .expect("entity root mutex")
155 .change_sets
156 .push();
157 }
158
159 pub fn pop_change_set(&self) -> Option<EntityChangeSet> {
160 self.inner
161 .lock()
162 .expect("entity root mutex")
163 .change_sets
164 .pop()
165 }
166
167 pub fn clear_current_change_set(&self) {
168 self.inner
169 .lock()
170 .expect("entity root mutex")
171 .change_sets
172 .clear_current();
173 }
174
175 pub fn set(&self, key: EntityKey, field: impl Into<String>, value: impl Into<Value>) {
176 self.inner
177 .lock()
178 .expect("entity root mutex")
179 .change_sets
180 .set(key, field, value.into());
181 }
182
183 pub fn get(&self, key: &EntityKey, field: &str) -> Option<Value> {
184 self.inner
185 .lock()
186 .expect("entity root mutex")
187 .change_sets
188 .get(key, field)
189 }
190
191 pub fn current_change_set(&self) -> EntityChangeSet {
192 self.inner
193 .lock()
194 .expect("entity root mutex")
195 .change_sets
196 .current()
197 .cloned()
198 .unwrap_or_default()
199 }
200
201 pub fn set_comment(&self, comment: impl Into<String>) {
204 self.inner
205 .lock()
206 .expect("entity root mutex")
207 .comment = Some(comment.into());
208 }
209
210 pub fn get_comment(&self) -> Option<String> {
212 self.inner
213 .lock()
214 .expect("entity root mutex")
215 .comment
216 .clone()
217 }
218}