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 root_graphs: Vec<GraphNode>,
231}
232
233impl RuntimeModule {
234 pub fn new() -> Self {
235 Self::default()
236 }
237
238 pub fn entity<T: TeaqlEntity>(mut self) -> Self {
239 let descriptor = T::entity_descriptor();
240 self.entity_registry.register(descriptor.name.clone());
241 self.metadata.register(descriptor);
242 self
243 }
244
245 pub fn entity_with_behavior<T, B>(mut self, behavior: B) -> Self
246 where
247 T: TeaqlEntity,
248 B: EntityDataServiceBehavior + 'static,
249 {
250 let descriptor = T::entity_descriptor();
251 let entity_name = descriptor.name.clone();
252 self.entity_registry.register(entity_name.clone());
253 self.metadata.register(descriptor);
254 self.behaviors.register(entity_name, behavior);
255 self
256 }
257
258 pub fn descriptor(mut self, descriptor: EntityDescriptor) -> Self {
259 self.entity_registry.register(descriptor.name.clone());
260 self.metadata.register(descriptor);
261 self
262 }
263
264 pub fn behavior(
265 mut self,
266 entity: impl Into<String>,
267 behavior: impl EntityDataServiceBehavior + 'static,
268 ) -> Self {
269 self.behaviors.register(entity, behavior);
270 self
271 }
272
273 pub fn checker(mut self, checker: impl Checker + 'static) -> Self {
274 self.checkers.register(checker);
275 self
276 }
277
278 pub fn event_sink(mut self, sink: impl RawAuditEventSink + 'static) -> Self {
279 self.event_sinks.register(sink);
280 self
281 }
282
283 pub fn language(mut self, language: Language) -> Self {
284 self.language = Some(language);
285 self
286 }
287
288 pub fn initial_graph(mut self, graph: GraphNode) -> Self {
289 self.initial_graphs.push(graph);
290 self
291 }
292
293 pub fn initial_graphs(mut self, graphs: impl IntoIterator<Item = GraphNode>) -> Self {
294 self.initial_graphs.extend(graphs);
295 self
296 }
297
298 pub fn root_graph(mut self, graph: GraphNode) -> Self {
301 self.root_graphs.push(graph);
302 self
303 }
304
305 pub fn root_graphs(mut self, graphs: impl IntoIterator<Item = GraphNode>) -> Self {
306 self.root_graphs.extend(graphs);
307 self
308 }
309
310 pub fn apply_to(self, context: &mut UserContext) {
311 context.set_metadata(self.metadata);
312 context.set_entity_registry(self.entity_registry);
313 context.set_entity_data_service_behavior_registry(self.behaviors);
314 context.set_checker_registry(self.checkers);
315 context.set_event_sink(self.event_sinks);
316 context.set_initial_graphs(self.initial_graphs);
317 context.set_root_graphs(self.root_graphs);
318 if let Some(language) = self.language {
319 context.set_language(language);
320 }
321 }
322
323 pub fn into_context(self) -> UserContext {
324 let mut context = UserContext::new();
325 self.apply_to(&mut context);
326 context
327 }
328}
329
330#[macro_export]
331macro_rules! module {
332 ($($entity:ty $(=> $behavior:expr)?),+ $(,)?) => {{
333 let module = $crate::RuntimeModule::new();
334 $crate::module!(@build module; $($entity $(=> $behavior)?),+)
335 }};
336
337 (@build $module:expr; $entity:ty => $behavior:expr, $($rest:tt)*) => {{
338 let module = $module.entity_with_behavior::<$entity, _>($behavior);
339 $crate::module!(@build module; $($rest)*)
340 }};
341
342 (@build $module:expr; $entity:ty, $($rest:tt)*) => {{
343 let module = $module.entity::<$entity>();
344 $crate::module!(@build module; $($rest)*)
345 }};
346
347 (@build $module:expr; $entity:ty => $behavior:expr) => {
348 $module.entity_with_behavior::<$entity, _>($behavior)
349 };
350
351 (@build $module:expr; $entity:ty) => {
352 $module.entity::<$entity>()
353 };
354}