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