1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4use teaql_core::{
5 CompactRow, DeleteCommand, Entity, EntityDescriptor, EntityDescriptorStore, EntityError,
6 IdentifiableEntity, InsertCommand, RecoverCommand, SelectQuery, TeaqlEntity, UpdateCommand,
7};
8
9use crate::{
10 Checker, EntityGraphBuilder, EntityRoot, GraphNode, InMemoryCheckerRegistry,
11 InMemoryRawAuditEventSink, Language, RawAuditEventSink, RuntimeError, UserContext,
12};
13
14type CompactEntityGraphDecoder =
15 fn(CompactRow, &EntityRoot, &mut EntityGraphBuilder) -> Result<(), EntityError>;
16type CompactEntityGraphListDecoder = fn(
17 Vec<CompactRow>,
18 &EntityRoot,
19 &mut EntityGraphBuilder,
20 &str,
21 u64,
22 &str,
23) -> Result<(), EntityError>;
24
25#[derive(Default, Clone)]
26pub struct InMemoryEntityGraphDecoderRegistry {
27 compact_decoders: BTreeMap<String, CompactEntityGraphDecoder>,
28 compact_list_decoders: BTreeMap<String, CompactEntityGraphListDecoder>,
29 compact_option_decoders: BTreeMap<String, CompactEntityGraphListDecoder>,
30}
31
32impl InMemoryEntityGraphDecoderRegistry {
33 pub fn contains(&self, entity: &str) -> bool {
34 self.compact_decoders.contains_key(entity)
35 }
36
37 pub fn register<T>(&mut self)
38 where
39 T: Entity + IdentifiableEntity + Send + Sync + 'static,
40 {
41 fn decode_compact<T>(
42 row: CompactRow,
43 root: &EntityRoot,
44 graph: &mut EntityGraphBuilder,
45 ) -> Result<(), EntityError>
46 where
47 T: Entity + IdentifiableEntity + Send + Sync + 'static,
48 {
49 let mut entity = T::from_compact_row(row)?;
50 entity.on_loaded(root as &dyn std::any::Any);
51 let id = entity.id_value().try_u64().ok_or_else(|| {
52 EntityError::new(T::ENTITY_NAME, "identity graph requires a u64 entity id")
53 })?;
54 graph.install(id, entity);
55 Ok(())
56 }
57
58 fn decode_compact_list<T>(
59 rows: Vec<CompactRow>,
60 root: &EntityRoot,
61 graph: &mut EntityGraphBuilder,
62 owner_entity: &str,
63 owner_id: u64,
64 relation: &str,
65 ) -> Result<(), EntityError>
66 where
67 T: Entity + IdentifiableEntity + Send + Sync + 'static,
68 {
69 let entities = rows
70 .into_iter()
71 .map(|row| {
72 let mut entity = T::from_compact_row(row)?;
73 entity.on_loaded(root as &dyn std::any::Any);
74 Ok(entity)
75 })
76 .collect::<Result<Vec<T>, EntityError>>()?;
77 graph.install_relation_list(
78 owner_entity,
79 owner_id,
80 relation,
81 teaql_core::SmartList::new(entities),
82 );
83 Ok(())
84 }
85
86 fn decode_compact_option<T>(
87 rows: Vec<CompactRow>,
88 root: &EntityRoot,
89 graph: &mut EntityGraphBuilder,
90 owner_entity: &str,
91 owner_id: u64,
92 relation: &str,
93 ) -> Result<(), EntityError>
94 where
95 T: Entity + IdentifiableEntity + Send + Sync + 'static,
96 {
97 let value = rows
98 .into_iter()
99 .next()
100 .map(|row| {
101 let mut entity = T::from_compact_row(row)?;
102 entity.on_loaded(root as &dyn std::any::Any);
103 Ok(entity)
104 })
105 .transpose()?;
106 graph.install_relation_option(owner_entity, owner_id, relation, value);
107 Ok(())
108 }
109
110 self.compact_decoders
111 .insert(T::ENTITY_NAME.to_owned(), decode_compact::<T>);
112 self.compact_list_decoders
113 .insert(T::ENTITY_NAME.to_owned(), decode_compact_list::<T>);
114 self.compact_option_decoders
115 .insert(T::ENTITY_NAME.to_owned(), decode_compact_option::<T>);
116 }
117
118 pub fn decode_compact(
119 &self,
120 entity: &str,
121 row: CompactRow,
122 root: &EntityRoot,
123 graph: &mut EntityGraphBuilder,
124 ) -> Result<(), EntityError> {
125 self.compact_decoders.get(entity).ok_or_else(|| {
126 EntityError::new(
127 entity,
128 "entity has no compact identity graph decoder in RuntimeModule",
129 )
130 })?(row, root, graph)
131 }
132
133 pub fn decode_compact_list(
134 &self,
135 entity: &str,
136 rows: Vec<CompactRow>,
137 root: &EntityRoot,
138 graph: &mut EntityGraphBuilder,
139 owner_entity: &str,
140 owner_id: u64,
141 relation: &str,
142 ) -> Result<(), EntityError> {
143 self.compact_list_decoders.get(entity).ok_or_else(|| {
144 EntityError::new(
145 entity,
146 "entity has no compact identity graph list decoder in RuntimeModule",
147 )
148 })?(rows, root, graph, owner_entity, owner_id, relation)
149 }
150
151 pub fn decode_compact_option(
152 &self,
153 entity: &str,
154 rows: Vec<CompactRow>,
155 root: &EntityRoot,
156 graph: &mut EntityGraphBuilder,
157 owner_entity: &str,
158 owner_id: u64,
159 relation: &str,
160 ) -> Result<(), EntityError> {
161 self.compact_option_decoders.get(entity).ok_or_else(|| {
162 EntityError::new(
163 entity,
164 "entity has no compact identity graph option decoder in RuntimeModule",
165 )
166 })?(rows, root, graph, owner_entity, owner_id, relation)
167 }
168}
169
170pub trait MetadataStore: Send + Sync {
171 fn entity(&self, name: &str) -> Option<&EntityDescriptor>;
172 fn all_entities(&self) -> Vec<&EntityDescriptor>;
173 fn record_metadata_log(&self, _metadata: &teaql_data_service::ExecutionMetadata) {}
174 fn capture_query_debug(&self) -> bool {
175 true
176 }
177}
178
179pub trait EntityRegistry: Send + Sync {
180 fn contains(&self, entity: &str) -> bool;
181}
182
183pub trait RequestPolicy: Send + Sync {
184 fn enforce_select(
185 &self,
186 _ctx: &UserContext,
187 _query: &mut SelectQuery,
188 ) -> Result<(), RuntimeError> {
189 Ok(())
190 }
191
192 fn enforce_insert(
193 &self,
194 _ctx: &UserContext,
195 _command: &mut InsertCommand,
196 ) -> Result<(), RuntimeError> {
197 Ok(())
198 }
199
200 fn enforce_update(
201 &self,
202 _ctx: &UserContext,
203 _command: &mut UpdateCommand,
204 ) -> Result<(), RuntimeError> {
205 Ok(())
206 }
207
208 fn enforce_delete(
209 &self,
210 _ctx: &UserContext,
211 _command: &mut DeleteCommand,
212 ) -> Result<(), RuntimeError> {
213 Ok(())
214 }
215
216 fn enforce_recover(
217 &self,
218 _ctx: &UserContext,
219 _command: &mut RecoverCommand,
220 ) -> Result<(), RuntimeError> {
221 Ok(())
222 }
223}
224
225pub trait EntityDataServiceBehavior: Send + Sync {
226 fn before_select(
227 &self,
228 _ctx: &UserContext,
229 _query: &mut SelectQuery,
230 ) -> Result<(), RuntimeError> {
231 Ok(())
232 }
233
234 fn before_insert(
235 &self,
236 _ctx: &UserContext,
237 _command: &mut InsertCommand,
238 ) -> Result<(), RuntimeError> {
239 Ok(())
240 }
241
242 fn before_update(
243 &self,
244 _ctx: &UserContext,
245 _command: &mut UpdateCommand,
246 ) -> Result<(), RuntimeError> {
247 Ok(())
248 }
249
250 fn before_delete(
251 &self,
252 _ctx: &UserContext,
253 _command: &mut DeleteCommand,
254 ) -> Result<(), RuntimeError> {
255 Ok(())
256 }
257
258 fn before_recover(
259 &self,
260 _ctx: &UserContext,
261 _command: &mut RecoverCommand,
262 ) -> Result<(), RuntimeError> {
263 Ok(())
264 }
265
266 fn relation_loads(&self, _ctx: &UserContext) -> Vec<String> {
267 Vec::new()
268 }
269}
270
271pub trait EntityDataServiceBehaviorRegistry: Send + Sync {
272 fn behavior(&self, entity: &str) -> Option<Arc<dyn EntityDataServiceBehavior>>;
273}
274
275#[derive(Debug, Default, Clone)]
276pub struct InMemoryMetadataStore {
277 entities: BTreeMap<String, EntityDescriptor>,
278}
279
280impl InMemoryMetadataStore {
281 pub fn new() -> Self {
282 Self::default()
283 }
284
285 pub fn register(&mut self, entity: EntityDescriptor) {
286 self.entities.insert(entity.name.clone(), entity);
287 }
288
289 pub fn with_entity(mut self, entity: EntityDescriptor) -> Self {
290 self.register(entity);
291 self
292 }
293}
294
295impl MetadataStore for InMemoryMetadataStore {
296 fn entity(&self, name: &str) -> Option<&EntityDescriptor> {
297 self.entities.get(name)
298 }
299
300 fn all_entities(&self) -> Vec<&EntityDescriptor> {
301 self.entities.values().collect()
302 }
303}
304
305impl teaql_data_service::SchemaProvider for InMemoryMetadataStore {
306 fn get_entity(&self, name: &str) -> Option<std::sync::Arc<teaql_core::EntityDescriptor>> {
307 self.entities
308 .get(name)
309 .map(|e| std::sync::Arc::new(e.clone()))
310 }
311}
312
313impl EntityDescriptorStore for InMemoryMetadataStore {
314 fn register_descriptor(&mut self, descriptor: EntityDescriptor) {
315 self.register(descriptor);
316 }
317}
318
319#[derive(Debug, Default, Clone)]
320pub struct InMemoryEntityRegistry {
321 entities: BTreeMap<String, String>,
322}
323
324impl InMemoryEntityRegistry {
325 pub fn new() -> Self {
326 Self::default()
327 }
328
329 pub fn register(&mut self, entity: impl Into<String>) {
330 let entity = entity.into();
331 self.entities.insert(entity.clone(), entity);
332 }
333
334 pub fn with_entity(mut self, entity: impl Into<String>) -> Self {
335 self.register(entity);
336 self
337 }
338}
339
340impl EntityRegistry for InMemoryEntityRegistry {
341 fn contains(&self, entity: &str) -> bool {
342 self.entities.contains_key(entity)
343 }
344}
345
346#[derive(Default, Clone)]
347pub struct InMemoryEntityDataServiceBehaviorRegistry {
348 behaviors: BTreeMap<String, Arc<dyn EntityDataServiceBehavior>>,
349}
350
351impl InMemoryEntityDataServiceBehaviorRegistry {
352 pub fn new() -> Self {
353 Self::default()
354 }
355
356 pub fn register(
357 &mut self,
358 entity: impl Into<String>,
359 behavior: impl EntityDataServiceBehavior + 'static,
360 ) {
361 self.behaviors.insert(entity.into(), Arc::new(behavior));
362 }
363
364 pub fn with_behavior(
365 mut self,
366 entity: impl Into<String>,
367 behavior: impl EntityDataServiceBehavior + 'static,
368 ) -> Self {
369 self.register(entity, behavior);
370 self
371 }
372}
373
374impl EntityDataServiceBehaviorRegistry for InMemoryEntityDataServiceBehaviorRegistry {
375 fn behavior(&self, entity: &str) -> Option<Arc<dyn EntityDataServiceBehavior>> {
376 self.behaviors.get(entity).cloned()
377 }
378}
379
380#[derive(Default, Clone)]
381pub struct RuntimeModule {
382 pub metadata: InMemoryMetadataStore,
383 entity_registry: InMemoryEntityRegistry,
384 behaviors: InMemoryEntityDataServiceBehaviorRegistry,
385 checkers: InMemoryCheckerRegistry,
386 event_sinks: InMemoryRawAuditEventSink,
387 language: Option<Language>,
388 initial_graphs: Vec<GraphNode>,
389 root_graphs: Vec<GraphNode>,
390 graph_decoders: InMemoryEntityGraphDecoderRegistry,
391}
392
393impl RuntimeModule {
394 pub fn new() -> Self {
395 Self::default()
396 }
397
398 pub fn entity<T>(mut self) -> Self
399 where
400 T: Entity + IdentifiableEntity + Send + Sync + 'static,
401 {
402 let descriptor = T::entity_descriptor();
403 self.entity_registry.register(descriptor.name.clone());
404 self.metadata.register(descriptor);
405 self.graph_decoders.register::<T>();
406 self
407 }
408
409 pub fn entity_with_behavior<T, B>(mut self, behavior: B) -> Self
410 where
411 T: Entity + IdentifiableEntity + Send + Sync + 'static,
412 B: EntityDataServiceBehavior + 'static,
413 {
414 let descriptor = T::entity_descriptor();
415 let entity_name = descriptor.name.clone();
416 self.entity_registry.register(entity_name.clone());
417 self.metadata.register(descriptor);
418 self.behaviors.register(entity_name, behavior);
419 self.graph_decoders.register::<T>();
420 self
421 }
422
423 pub fn descriptor(mut self, descriptor: EntityDescriptor) -> Self {
424 self.entity_registry.register(descriptor.name.clone());
425 self.metadata.register(descriptor);
426 self
427 }
428
429 pub fn behavior(
430 mut self,
431 entity: impl Into<String>,
432 behavior: impl EntityDataServiceBehavior + 'static,
433 ) -> Self {
434 self.behaviors.register(entity, behavior);
435 self
436 }
437
438 pub fn checker(mut self, checker: impl Checker + 'static) -> Self {
439 self.checkers.register(checker);
440 self
441 }
442
443 pub fn event_sink(mut self, sink: impl RawAuditEventSink + 'static) -> Self {
444 self.event_sinks.register(sink);
445 self
446 }
447
448 pub fn language(mut self, language: Language) -> Self {
449 self.language = Some(language);
450 self
451 }
452
453 pub fn initial_graph(mut self, graph: GraphNode) -> Self {
454 self.initial_graphs.push(graph);
455 self
456 }
457
458 pub fn initial_graphs(mut self, graphs: impl IntoIterator<Item = GraphNode>) -> Self {
459 self.initial_graphs.extend(graphs);
460 self
461 }
462
463 pub fn root_graph(mut self, graph: GraphNode) -> Self {
466 self.root_graphs.push(graph);
467 self
468 }
469
470 pub fn root_graphs(mut self, graphs: impl IntoIterator<Item = GraphNode>) -> Self {
471 self.root_graphs.extend(graphs);
472 self
473 }
474
475 pub fn apply_to(self, context: &mut UserContext) {
476 context.set_metadata(self.metadata);
477 context.set_entity_registry(self.entity_registry);
478 context.set_entity_data_service_behavior_registry(self.behaviors);
479 context.set_checker_registry(self.checkers);
480 context.set_event_sink(self.event_sinks);
481 context.set_initial_graphs(self.initial_graphs);
482 context.set_root_graphs(self.root_graphs);
483 context.set_entity_graph_decoder_registry(self.graph_decoders);
484 if let Some(language) = self.language {
485 context.set_language(language);
486 }
487 }
488
489 pub fn into_context(self) -> UserContext {
490 let mut context = UserContext::new();
491 self.apply_to(&mut context);
492 context
493 }
494}
495
496#[macro_export]
497macro_rules! module {
498 ($($entity:ty $(=> $behavior:expr)?),+ $(,)?) => {{
499 let module = $crate::RuntimeModule::new();
500 $crate::module!(@build module; $($entity $(=> $behavior)?),+)
501 }};
502
503 (@build $module:expr; $entity:ty => $behavior:expr, $($rest:tt)*) => {{
504 let module = $module.entity_with_behavior::<$entity, _>($behavior);
505 $crate::module!(@build module; $($rest)*)
506 }};
507
508 (@build $module:expr; $entity:ty, $($rest:tt)*) => {{
509 let module = $module.entity::<$entity>();
510 $crate::module!(@build module; $($rest)*)
511 }};
512
513 (@build $module:expr; $entity:ty => $behavior:expr) => {
514 $module.entity_with_behavior::<$entity, _>($behavior)
515 };
516
517 (@build $module:expr; $entity:ty) => {
518 $module.entity::<$entity>()
519 };
520}