Skip to main content

teaql_runtime/
registry.rs

1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4use teaql_core::{
5    DeleteCommand, EntityDescriptor, EntityDescriptorStore, InsertCommand, RecoverCommand,
6    SelectQuery, TeaqlEntity, UpdateCommand,
7};
8
9use crate::{
10    Checker, GraphNode, InMemoryCheckerRegistry, InMemoryRawAuditEventSink, Language,
11    RawAuditEventSink, RuntimeError, UserContext,
12};
13
14pub trait MetadataStore: Send + Sync {
15    fn entity(&self, name: &str) -> Option<&EntityDescriptor>;
16    fn all_entities(&self) -> Vec<&EntityDescriptor>;
17    fn record_metadata_log(&self, _metadata: &teaql_data_service::ExecutionMetadata) {}
18}
19
20pub trait EntityRegistry: Send + Sync {
21    fn contains(&self, entity: &str) -> bool;
22}
23
24pub trait RequestPolicy: Send + Sync {
25    fn enforce_select(
26        &self,
27        _ctx: &UserContext,
28        _query: &mut SelectQuery,
29    ) -> Result<(), RuntimeError> {
30        Ok(())
31    }
32
33    fn enforce_insert(
34        &self,
35        _ctx: &UserContext,
36        _command: &mut InsertCommand,
37    ) -> Result<(), RuntimeError> {
38        Ok(())
39    }
40
41    fn enforce_update(
42        &self,
43        _ctx: &UserContext,
44        _command: &mut UpdateCommand,
45    ) -> Result<(), RuntimeError> {
46        Ok(())
47    }
48
49    fn enforce_delete(
50        &self,
51        _ctx: &UserContext,
52        _command: &mut DeleteCommand,
53    ) -> Result<(), RuntimeError> {
54        Ok(())
55    }
56
57    fn enforce_recover(
58        &self,
59        _ctx: &UserContext,
60        _command: &mut RecoverCommand,
61    ) -> Result<(), RuntimeError> {
62        Ok(())
63    }
64}
65
66pub trait EntityDataServiceBehavior: Send + Sync {
67    fn before_select(
68        &self,
69        _ctx: &UserContext,
70        _query: &mut SelectQuery,
71    ) -> Result<(), RuntimeError> {
72        Ok(())
73    }
74
75    fn before_insert(
76        &self,
77        _ctx: &UserContext,
78        _command: &mut InsertCommand,
79    ) -> Result<(), RuntimeError> {
80        Ok(())
81    }
82
83    fn before_update(
84        &self,
85        _ctx: &UserContext,
86        _command: &mut UpdateCommand,
87    ) -> Result<(), RuntimeError> {
88        Ok(())
89    }
90
91    fn before_delete(
92        &self,
93        _ctx: &UserContext,
94        _command: &mut DeleteCommand,
95    ) -> Result<(), RuntimeError> {
96        Ok(())
97    }
98
99    fn before_recover(
100        &self,
101        _ctx: &UserContext,
102        _command: &mut RecoverCommand,
103    ) -> Result<(), RuntimeError> {
104        Ok(())
105    }
106
107    fn relation_loads(&self, _ctx: &UserContext) -> Vec<String> {
108        Vec::new()
109    }
110}
111
112pub trait EntityDataServiceBehaviorRegistry: Send + Sync {
113    fn behavior(&self, entity: &str) -> Option<Arc<dyn EntityDataServiceBehavior>>;
114}
115
116#[derive(Debug, Default, Clone)]
117pub struct InMemoryMetadataStore {
118    entities: BTreeMap<String, EntityDescriptor>,
119}
120
121impl InMemoryMetadataStore {
122    pub fn new() -> Self {
123        Self::default()
124    }
125
126    pub fn register(&mut self, entity: EntityDescriptor) {
127        self.entities.insert(entity.name.clone(), entity);
128    }
129
130    pub fn with_entity(mut self, entity: EntityDescriptor) -> Self {
131        self.register(entity);
132        self
133    }
134}
135
136impl MetadataStore for InMemoryMetadataStore {
137    fn entity(&self, name: &str) -> Option<&EntityDescriptor> {
138        self.entities.get(name)
139    }
140
141    fn all_entities(&self) -> Vec<&EntityDescriptor> {
142        self.entities.values().collect()
143    }
144}
145
146impl teaql_data_service::SchemaProvider for InMemoryMetadataStore {
147    fn get_entity(&self, name: &str) -> Option<std::sync::Arc<teaql_core::EntityDescriptor>> {
148        self.entities
149            .get(name)
150            .map(|e| std::sync::Arc::new(e.clone()))
151    }
152}
153
154impl EntityDescriptorStore for InMemoryMetadataStore {
155    fn register_descriptor(&mut self, descriptor: EntityDescriptor) {
156        self.register(descriptor);
157    }
158}
159
160#[derive(Debug, Default, Clone)]
161pub struct InMemoryEntityRegistry {
162    entities: BTreeMap<String, String>,
163}
164
165impl InMemoryEntityRegistry {
166    pub fn new() -> Self {
167        Self::default()
168    }
169
170    pub fn register(&mut self, entity: impl Into<String>) {
171        let entity = entity.into();
172        self.entities.insert(entity.clone(), entity);
173    }
174
175    pub fn with_entity(mut self, entity: impl Into<String>) -> Self {
176        self.register(entity);
177        self
178    }
179}
180
181impl EntityRegistry for InMemoryEntityRegistry {
182    fn contains(&self, entity: &str) -> bool {
183        self.entities.contains_key(entity)
184    }
185}
186
187#[derive(Default, Clone)]
188pub struct InMemoryEntityDataServiceBehaviorRegistry {
189    behaviors: BTreeMap<String, Arc<dyn EntityDataServiceBehavior>>,
190}
191
192impl InMemoryEntityDataServiceBehaviorRegistry {
193    pub fn new() -> Self {
194        Self::default()
195    }
196
197    pub fn register(
198        &mut self,
199        entity: impl Into<String>,
200        behavior: impl EntityDataServiceBehavior + 'static,
201    ) {
202        self.behaviors.insert(entity.into(), Arc::new(behavior));
203    }
204
205    pub fn with_behavior(
206        mut self,
207        entity: impl Into<String>,
208        behavior: impl EntityDataServiceBehavior + 'static,
209    ) -> Self {
210        self.register(entity, behavior);
211        self
212    }
213}
214
215impl EntityDataServiceBehaviorRegistry for InMemoryEntityDataServiceBehaviorRegistry {
216    fn behavior(&self, entity: &str) -> Option<Arc<dyn EntityDataServiceBehavior>> {
217        self.behaviors.get(entity).cloned()
218    }
219}
220
221#[derive(Default, Clone)]
222pub struct RuntimeModule {
223    pub metadata: InMemoryMetadataStore,
224    entity_registry: InMemoryEntityRegistry,
225    behaviors: InMemoryEntityDataServiceBehaviorRegistry,
226    checkers: InMemoryCheckerRegistry,
227    event_sinks: InMemoryRawAuditEventSink,
228    language: Option<Language>,
229    initial_graphs: Vec<GraphNode>,
230}
231
232impl RuntimeModule {
233    pub fn new() -> Self {
234        Self::default()
235    }
236
237    pub fn entity<T: TeaqlEntity>(mut self) -> Self {
238        let descriptor = T::entity_descriptor();
239        self.entity_registry.register(descriptor.name.clone());
240        self.metadata.register(descriptor);
241        self
242    }
243
244    pub fn entity_with_behavior<T, B>(mut self, behavior: B) -> Self
245    where
246        T: TeaqlEntity,
247        B: EntityDataServiceBehavior + 'static,
248    {
249        let descriptor = T::entity_descriptor();
250        let entity_name = descriptor.name.clone();
251        self.entity_registry.register(entity_name.clone());
252        self.metadata.register(descriptor);
253        self.behaviors.register(entity_name, behavior);
254        self
255    }
256
257    pub fn descriptor(mut self, descriptor: EntityDescriptor) -> Self {
258        self.entity_registry.register(descriptor.name.clone());
259        self.metadata.register(descriptor);
260        self
261    }
262
263    pub fn behavior(
264        mut self,
265        entity: impl Into<String>,
266        behavior: impl EntityDataServiceBehavior + 'static,
267    ) -> Self {
268        self.behaviors.register(entity, behavior);
269        self
270    }
271
272    pub fn checker(mut self, checker: impl Checker + 'static) -> Self {
273        self.checkers.register(checker);
274        self
275    }
276
277    pub fn event_sink(mut self, sink: impl RawAuditEventSink + 'static) -> Self {
278        self.event_sinks.register(sink);
279        self
280    }
281
282    pub fn language(mut self, language: Language) -> Self {
283        self.language = Some(language);
284        self
285    }
286
287    pub fn initial_graph(mut self, graph: GraphNode) -> Self {
288        self.initial_graphs.push(graph);
289        self
290    }
291
292    pub fn initial_graphs(mut self, graphs: impl IntoIterator<Item = GraphNode>) -> Self {
293        self.initial_graphs.extend(graphs);
294        self
295    }
296
297    pub fn apply_to(self, ctx: &mut UserContext) {
298        ctx.set_metadata(self.metadata);
299        ctx.set_entity_registry(self.entity_registry);
300        ctx.set_entity_data_service_behavior_registry(self.behaviors);
301        ctx.set_checker_registry(self.checkers);
302        ctx.set_event_sink(self.event_sinks);
303        ctx.set_initial_graphs(self.initial_graphs);
304        if let Some(language) = self.language {
305            ctx.set_language(language);
306        }
307    }
308
309    pub fn into_context(self) -> UserContext {
310        let mut ctx = UserContext::new();
311        self.apply_to(&mut ctx);
312        ctx
313    }
314}
315
316#[macro_export]
317macro_rules! module {
318    ($($entity:ty $(=> $behavior:expr)?),+ $(,)?) => {{
319        let module = $crate::RuntimeModule::new();
320        $crate::module!(@build module; $($entity $(=> $behavior)?),+)
321    }};
322
323    (@build $module:expr; $entity:ty => $behavior:expr, $($rest:tt)*) => {{
324        let module = $module.entity_with_behavior::<$entity, _>($behavior);
325        $crate::module!(@build module; $($rest)*)
326    }};
327
328    (@build $module:expr; $entity:ty, $($rest:tt)*) => {{
329        let module = $module.entity::<$entity>();
330        $crate::module!(@build module; $($rest)*)
331    }};
332
333    (@build $module:expr; $entity:ty => $behavior:expr) => {
334        $module.entity_with_behavior::<$entity, _>($behavior)
335    };
336
337    (@build $module:expr; $entity:ty) => {
338        $module.entity::<$entity>()
339    };
340}