Skip to main content

teaql_runtime/
generated_support.rs

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