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