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