Skip to main content

teaql_runtime/
generated_support.rs

1#![allow(unused_imports)]
2#![allow(async_fn_in_trait)]
3
4use crate::{DataServiceError, GraphNode, RuntimeError, UserContext};
5use std::collections::BTreeMap;
6use teaql_core::request::{
7    QueryOptions, QuerySelection, apply_runtime_metadata, merge_outer_filter_into_facet_aggregates,
8    runtime_relation_aggregates,
9};
10use teaql_core::{
11    Expr, Record, RelationAggregate as RuntimeRelationAggregate, SelectQuery, SmartList, TraceNode,
12};
13
14pub trait TeaqlRecordDataService {
15    type Error: std::error::Error + Send + Sync + 'static;
16
17    async fn fetch_all(
18        &self,
19        query: &SelectQuery,
20    ) -> Result<Vec<Record>, DataServiceError<Self::Error>>;
21
22    async fn fetch_smart_list(
23        &self,
24        query: &SelectQuery,
25    ) -> Result<SmartList<Record>, DataServiceError<Self::Error>>;
26
27    async fn fetch_smart_list_with_relation_aggregates(
28        &self,
29        query: &SelectQuery,
30        relation_aggregates: &[RuntimeRelationAggregate],
31    ) -> Result<SmartList<Record>, DataServiceError<Self::Error>>;
32
33    async fn fetch_stream(
34        &self,
35        query: &SelectQuery,
36    ) -> Result<Vec<teaql_data_service::StreamChunk>, DataServiceError<Self::Error>>;
37}
38
39pub trait TeaqlEntityDataService: TeaqlRecordDataService {
40    async fn fetch_enhanced_entities<T>(
41        &self,
42        query: &SelectQuery,
43    ) -> Result<SmartList<T>, DataServiceError<Self::Error>>
44    where
45        T: teaql_core::Entity;
46
47    async fn fetch_enhanced_entities_with_relation_aggregates<T>(
48        &self,
49        query: &SelectQuery,
50        relation_aggregates: &[RuntimeRelationAggregate],
51    ) -> Result<SmartList<T>, DataServiceError<Self::Error>>
52    where
53        T: teaql_core::Entity;
54
55    async fn save_entity_graph<T>(
56        &self,
57        entity: T,
58    ) -> Result<GraphNode, DataServiceError<Self::Error>>
59    where
60        T: teaql_core::Entity;
61}
62
63impl<'a, E> TeaqlRecordDataService for crate::EntityDataService<'a, E>
64where
65    E: teaql_data_service::QueryExecutor
66        + teaql_data_service::MutationExecutor
67        + teaql_data_service::StreamQueryExecutor
68        + Send
69        + Sync
70        + 'static,
71{
72    type Error = E::Error;
73
74    async fn fetch_all(
75        &self,
76        query: &SelectQuery,
77    ) -> Result<Vec<Record>, DataServiceError<Self::Error>> {
78        crate::EntityDataService::fetch_all(self, query).await
79    }
80
81    async fn fetch_smart_list(
82        &self,
83        query: &SelectQuery,
84    ) -> Result<SmartList<Record>, DataServiceError<Self::Error>> {
85        crate::EntityDataService::fetch_smart_list(self, query).await
86    }
87
88    async fn fetch_smart_list_with_relation_aggregates(
89        &self,
90        query: &SelectQuery,
91        relation_aggregates: &[RuntimeRelationAggregate],
92    ) -> Result<SmartList<Record>, DataServiceError<Self::Error>> {
93        crate::EntityDataService::fetch_smart_list_with_relation_aggregates(
94            self,
95            query,
96            relation_aggregates,
97        )
98        .await
99    }
100
101    async fn fetch_stream(
102        &self,
103        query: &SelectQuery,
104    ) -> Result<Vec<teaql_data_service::StreamChunk>, DataServiceError<Self::Error>> {
105        crate::EntityDataService::fetch_stream(self, query).await
106    }
107}
108
109impl<'a, E> TeaqlEntityDataService for crate::EntityDataService<'a, E>
110where
111    E: teaql_data_service::QueryExecutor
112        + teaql_data_service::MutationExecutor
113        + teaql_data_service::StreamQueryExecutor
114        + Send
115        + Sync
116        + 'static,
117{
118    async fn fetch_enhanced_entities<T>(
119        &self,
120        query: &SelectQuery,
121    ) -> Result<SmartList<T>, DataServiceError<Self::Error>>
122    where
123        T: teaql_core::Entity,
124    {
125        crate::EntityDataService::fetch_enhanced_entities(self, query).await
126    }
127
128    async fn fetch_enhanced_entities_with_relation_aggregates<T>(
129        &self,
130        query: &SelectQuery,
131        relation_aggregates: &[RuntimeRelationAggregate],
132    ) -> Result<SmartList<T>, DataServiceError<Self::Error>>
133    where
134        T: teaql_core::Entity,
135    {
136        crate::EntityDataService::fetch_enhanced_entities_with_relation_aggregates(
137            self,
138            query,
139            relation_aggregates,
140        )
141        .await
142    }
143
144    async fn save_entity_graph<T>(
145        &self,
146        entity: T,
147    ) -> Result<GraphNode, DataServiceError<Self::Error>>
148    where
149        T: teaql_core::Entity,
150    {
151        crate::EntityDataService::save_entity_graph(self, entity).await
152    }
153}
154
155pub type TeaqlDataServiceError<R> = DataServiceError<<R as TeaqlRecordDataService>::Error>;
156
157pub trait TeaqlRuntime {
158    fn user_context(&self) -> &UserContext;
159
160    fn fetch_facet_smart_list(
161        &self,
162        entity: &str,
163        query: &SelectQuery,
164        relation_aggregates: &[RuntimeRelationAggregate],
165        trace_context: Vec<TraceNode>,
166    ) -> impl std::future::Future<Output = Result<SmartList<Record>, RuntimeError>> + Send;
167}
168
169/// Internal trait for audited save access. Application code should not use this trait directly.
170#[doc(hidden)]
171pub trait AuditedSave<'a, C>
172where
173    C: TeaqlRuntime + ?Sized + 'a,
174{
175    type Error;
176    fn save(
177        self,
178        ctx: &'a C,
179    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<GraphNode, Self::Error>> + '_>>;
180}
181
182pub struct PurposedQuery<T> {
183    pub inner: T,
184    pub purpose: String,
185}
186
187impl<T> PurposedQuery<T> {
188    pub fn new(inner: T, purpose: impl Into<String>) -> Self {
189        Self {
190            inner,
191            purpose: purpose.into(),
192        }
193    }
194}
195
196pub async fn execute_facets<C>(
197    ctx: &C,
198    outer_query: &SelectQuery,
199    options: &QueryOptions,
200) -> Result<BTreeMap<String, SmartList<Record>>, RuntimeError>
201where
202    C: TeaqlRuntime + ?Sized,
203{
204    let mut facets = BTreeMap::new();
205    for facet in &options.facets {
206        let mut selection = facet.query.clone();
207        merge_outer_filter_into_facet_aggregates(&mut selection, outer_query);
208        if !facet.include_all_facets {
209            selection =
210                restrict_facet_to_outer_query(ctx, selection, outer_query, &facet.relation_name)?;
211        }
212        let relation_aggregates = runtime_relation_aggregates(&selection.query_options);
213        let query = apply_runtime_metadata(
214            selection.query,
215            &selection.query_options,
216            &selection.child_enhancements,
217        );
218        let mut chain = outer_query.trace_chain.clone();
219        chain.push(TraceNode {
220            entity_type: query.entity.clone(),
221            entity_id: None,
222            comment: facet.facet_name.clone(),
223        });
224
225        let facet_rows = ctx
226            .fetch_facet_smart_list(&query.entity, &query, &relation_aggregates, chain)
227            .await?;
228        facets.insert(facet.facet_name.clone(), facet_rows);
229    }
230    Ok(facets)
231}
232
233pub fn restrict_facet_to_outer_query<C>(
234    ctx: &C,
235    mut selection: QuerySelection,
236    outer_query: &SelectQuery,
237    relation_name: &str,
238) -> Result<QuerySelection, RuntimeError>
239where
240    C: TeaqlRuntime + ?Sized,
241{
242    let descriptor = ctx
243        .user_context()
244        .entity(&outer_query.entity)
245        .cloned()
246        .ok_or_else(|| RuntimeError::Graph(format!("missing entity: {}", outer_query.entity)))?;
247    let relation = descriptor
248        .relation_by_name(relation_name)
249        .cloned()
250        .ok_or_else(|| RuntimeError::MissingRelation {
251            entity: outer_query.entity.clone(),
252            relation: relation_name.to_owned(),
253        })?;
254    let mut subquery = outer_query.clone();
255    subquery.projection.clear();
256    subquery.expr_projection.clear();
257    subquery.order_by.clear();
258    subquery.slice = None;
259    subquery.aggregates.clear();
260    subquery.group_by.clear();
261    subquery.relations.clear();
262    selection.query = selection.query.and_filter(Expr::in_subquery(
263        relation.foreign_key,
264        descriptor,
265        subquery,
266        relation.local_key,
267    ));
268    Ok(selection)
269}