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