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#[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}