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, EntityEventSink, GraphNode, InMemoryCheckerRegistry, InMemoryEntityEventSink,
11    Language, 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}
18
19pub trait RepositoryRegistry: Send + Sync {
20    fn contains(&self, entity: &str) -> bool;
21}
22
23pub trait RepositoryBehavior: Send + Sync {
24    fn before_select(
25        &self,
26        _ctx: &UserContext,
27        _query: &mut SelectQuery,
28    ) -> Result<(), RuntimeError> {
29        Ok(())
30    }
31
32    fn before_insert(
33        &self,
34        _ctx: &UserContext,
35        _command: &mut InsertCommand,
36    ) -> Result<(), RuntimeError> {
37        Ok(())
38    }
39
40    fn before_update(
41        &self,
42        _ctx: &UserContext,
43        _command: &mut UpdateCommand,
44    ) -> Result<(), RuntimeError> {
45        Ok(())
46    }
47
48    fn before_delete(
49        &self,
50        _ctx: &UserContext,
51        _command: &mut DeleteCommand,
52    ) -> Result<(), RuntimeError> {
53        Ok(())
54    }
55
56    fn before_recover(
57        &self,
58        _ctx: &UserContext,
59        _command: &mut RecoverCommand,
60    ) -> Result<(), RuntimeError> {
61        Ok(())
62    }
63
64    fn relation_loads(&self, _ctx: &UserContext) -> Vec<String> {
65        Vec::new()
66    }
67}
68
69pub trait RepositoryBehaviorRegistry: Send + Sync {
70    fn behavior(&self, entity: &str) -> Option<Arc<dyn RepositoryBehavior>>;
71}
72
73#[derive(Debug, Default, Clone)]
74pub struct InMemoryMetadataStore {
75    entities: BTreeMap<String, EntityDescriptor>,
76}
77
78impl InMemoryMetadataStore {
79    pub fn new() -> Self {
80        Self::default()
81    }
82
83    pub fn register(&mut self, entity: EntityDescriptor) {
84        self.entities.insert(entity.name.clone(), entity);
85    }
86
87    pub fn with_entity(mut self, entity: EntityDescriptor) -> Self {
88        self.register(entity);
89        self
90    }
91}
92
93impl MetadataStore for InMemoryMetadataStore {
94    fn entity(&self, name: &str) -> Option<&EntityDescriptor> {
95        self.entities.get(name)
96    }
97
98    fn all_entities(&self) -> Vec<&EntityDescriptor> {
99        self.entities.values().collect()
100    }
101}
102
103impl EntityDescriptorStore for InMemoryMetadataStore {
104    fn register_descriptor(&mut self, descriptor: EntityDescriptor) {
105        self.register(descriptor);
106    }
107}
108
109#[derive(Debug, Default, Clone)]
110pub struct InMemoryRepositoryRegistry {
111    entities: BTreeMap<String, String>,
112}
113
114impl InMemoryRepositoryRegistry {
115    pub fn new() -> Self {
116        Self::default()
117    }
118
119    pub fn register(&mut self, entity: impl Into<String>) {
120        let entity = entity.into();
121        self.entities.insert(entity.clone(), entity);
122    }
123
124    pub fn with_entity(mut self, entity: impl Into<String>) -> Self {
125        self.register(entity);
126        self
127    }
128}
129
130impl RepositoryRegistry for InMemoryRepositoryRegistry {
131    fn contains(&self, entity: &str) -> bool {
132        self.entities.contains_key(entity)
133    }
134}
135
136#[derive(Default, Clone)]
137pub struct InMemoryRepositoryBehaviorRegistry {
138    behaviors: BTreeMap<String, Arc<dyn RepositoryBehavior>>,
139}
140
141impl InMemoryRepositoryBehaviorRegistry {
142    pub fn new() -> Self {
143        Self::default()
144    }
145
146    pub fn register(
147        &mut self,
148        entity: impl Into<String>,
149        behavior: impl RepositoryBehavior + 'static,
150    ) {
151        self.behaviors.insert(entity.into(), Arc::new(behavior));
152    }
153
154    pub fn with_behavior(
155        mut self,
156        entity: impl Into<String>,
157        behavior: impl RepositoryBehavior + 'static,
158    ) -> Self {
159        self.register(entity, behavior);
160        self
161    }
162}
163
164impl RepositoryBehaviorRegistry for InMemoryRepositoryBehaviorRegistry {
165    fn behavior(&self, entity: &str) -> Option<Arc<dyn RepositoryBehavior>> {
166        self.behaviors.get(entity).cloned()
167    }
168}
169
170#[derive(Default, Clone)]
171pub struct RuntimeModule {
172    metadata: InMemoryMetadataStore,
173    repositories: InMemoryRepositoryRegistry,
174    behaviors: InMemoryRepositoryBehaviorRegistry,
175    checkers: InMemoryCheckerRegistry,
176    event_sinks: InMemoryEntityEventSink,
177    language: Option<Language>,
178    initial_graphs: Vec<GraphNode>,
179}
180
181impl RuntimeModule {
182    pub fn new() -> Self {
183        Self::default()
184    }
185
186    pub fn entity<T: TeaqlEntity>(mut self) -> Self {
187        let descriptor = T::entity_descriptor();
188        self.repositories.register(descriptor.name.clone());
189        self.metadata.register(descriptor);
190        self
191    }
192
193    pub fn entity_with_behavior<T, B>(mut self, behavior: B) -> Self
194    where
195        T: TeaqlEntity,
196        B: RepositoryBehavior + 'static,
197    {
198        let descriptor = T::entity_descriptor();
199        let entity_name = descriptor.name.clone();
200        self.repositories.register(entity_name.clone());
201        self.metadata.register(descriptor);
202        self.behaviors.register(entity_name, behavior);
203        self
204    }
205
206    pub fn descriptor(mut self, descriptor: EntityDescriptor) -> Self {
207        self.repositories.register(descriptor.name.clone());
208        self.metadata.register(descriptor);
209        self
210    }
211
212    pub fn behavior(
213        mut self,
214        entity: impl Into<String>,
215        behavior: impl RepositoryBehavior + 'static,
216    ) -> Self {
217        self.behaviors.register(entity, behavior);
218        self
219    }
220
221    pub fn checker(mut self, checker: impl Checker + 'static) -> Self {
222        self.checkers.register(checker);
223        self
224    }
225
226    pub fn event_sink(mut self, sink: impl EntityEventSink + 'static) -> Self {
227        self.event_sinks.register(sink);
228        self
229    }
230
231    pub fn language(mut self, language: Language) -> Self {
232        self.language = Some(language);
233        self
234    }
235
236    pub fn initial_graph(mut self, graph: GraphNode) -> Self {
237        self.initial_graphs.push(graph);
238        self
239    }
240
241    pub fn initial_graphs(mut self, graphs: impl IntoIterator<Item = GraphNode>) -> Self {
242        self.initial_graphs.extend(graphs);
243        self
244    }
245
246    pub fn apply_to(self, ctx: &mut UserContext) {
247        ctx.set_metadata(self.metadata);
248        ctx.set_repository_registry(self.repositories);
249        ctx.set_repository_behavior_registry(self.behaviors);
250        ctx.set_checker_registry(self.checkers);
251        ctx.set_event_sink(self.event_sinks);
252        ctx.set_initial_graphs(self.initial_graphs);
253        if let Some(language) = self.language {
254            ctx.set_language(language);
255        }
256    }
257
258    pub fn into_context(self) -> UserContext {
259        let mut ctx = UserContext::new();
260        self.apply_to(&mut ctx);
261        ctx
262    }
263}
264
265#[macro_export]
266macro_rules! module {
267    ($($entity:ty $(=> $behavior:expr)?),+ $(,)?) => {{
268        let module = $crate::RuntimeModule::new();
269        $crate::module!(@build module; $($entity $(=> $behavior)?),+)
270    }};
271
272    (@build $module:expr; $entity:ty => $behavior:expr, $($rest:tt)*) => {{
273        let module = $module.entity_with_behavior::<$entity, _>($behavior);
274        $crate::module!(@build module; $($rest)*)
275    }};
276
277    (@build $module:expr; $entity:ty, $($rest:tt)*) => {{
278        let module = $module.entity::<$entity>();
279        $crate::module!(@build module; $($rest)*)
280    }};
281
282    (@build $module:expr; $entity:ty => $behavior:expr) => {
283        $module.entity_with_behavior::<$entity, _>($behavior)
284    };
285
286    (@build $module:expr; $entity:ty) => {
287        $module.entity::<$entity>()
288    };
289}