1use std::marker::PhantomData;
4use std::sync::Arc;
5
6use crate::entity::{
7 IEntitySnapshot, IEntityType, IFromRow, IGetKeyValues, ILazyInit, INavigationSetter,
8};
9use crate::error::EFResult;
10use crate::provider::{DbValue, IDatabaseProvider};
11
12use super::super::ast::{BoolExpr, FilterCondition, OrderBy, OrderDirection};
13use super::super::compile::{compile_bool_expr, resolve_state_subqueries};
14use super::super::execute_update::ExecuteUpdateBuilder;
15use super::super::state::QueryState;
16use super::core::QueryBuilder;
17
18impl<T: IEntityType> QueryBuilder<T> {
19 pub async fn find(self, id: impl Into<DbValue>) -> EFResult<Option<T>>
26 where
27 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
28 {
29 let meta = T::entity_meta();
30 let pk_col = meta
31 .primary_keys
32 .first()
33 .map(|s| s.as_ref())
34 .or_else(|| {
35 meta.properties
36 .iter()
37 .find(|p| p.is_primary_key)
38 .map(|p| p.column_name.as_ref())
39 })
40 .ok_or_else(|| {
41 crate::error::EFError::query(format!(
42 "entity {} has no primary key defined",
43 std::any::type_name::<T>()
44 ))
45 })?;
46 let col_const = pk_col.to_string();
47 self.filter(BoolExpr::Filter(FilterCondition::with_values(
48 col_const,
49 "=",
50 vec![id.into()],
51 )))
52 .first_or_default()
53 .await
54 }
55
56 pub async fn find_by_key(mut self, keys: &[(&str, DbValue)]) -> EFResult<Option<T>>
59 where
60 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
61 {
62 for (col, val) in keys {
63 self = self.filter(BoolExpr::Filter(FilterCondition::with_values(
64 col.to_string(),
65 "=",
66 vec![val.clone()],
67 )));
68 }
69 self.first_or_default().await
70 }
71
72 pub async fn exists_by_id(self, id: impl Into<DbValue>) -> EFResult<bool> {
78 let meta = T::entity_meta();
79 let pk_col = meta
80 .primary_keys
81 .first()
82 .map(|s| s.as_ref())
83 .or_else(|| {
84 meta.properties
85 .iter()
86 .find(|p| p.is_primary_key)
87 .map(|p| p.column_name.as_ref())
88 })
89 .ok_or_else(|| {
90 crate::error::EFError::query(format!(
91 "entity {} has no primary key defined",
92 std::any::type_name::<T>()
93 ))
94 })?;
95 let col_const = pk_col.to_string();
96 self.filter(BoolExpr::Filter(FilterCondition::with_values(
97 col_const,
98 "=",
99 vec![id.into()],
100 )))
101 .any()
102 .await
103 }
104
105 pub async fn exists_by_key(mut self, keys: &[(&str, DbValue)]) -> EFResult<bool> {
109 for (col, val) in keys {
110 self = self.filter(BoolExpr::Filter(FilterCondition::with_values(
111 col.to_string(),
112 "=",
113 vec![val.clone()],
114 )));
115 }
116 self.any().await
117 }
118
119 pub fn to_sql(&self) -> String {
125 let state = self.resolved_state();
126 if let Some(provider) = &self.provider {
127 let gen = provider.sql_generator();
128 state.to_sql_with(gen)
129 } else {
130 state.to_sql()
131 }
132 }
133
134 pub fn compile_sql(&self) -> (String, Vec<DbValue>) {
135 (self.to_sql(), self.state.all_params())
136 }
137
138 pub(super) fn resolved_state(&self) -> QueryState {
141 let mut state = self.state.clone();
142 resolve_state_subqueries::<T>(&mut state);
143 state
144 }
145
146 pub(super) fn compile_state_sql(
147 state: &QueryState,
148 provider: &Arc<dyn IDatabaseProvider>,
149 ) -> String {
150 let mut resolved = state.clone();
151 resolve_state_subqueries::<T>(&mut resolved);
152 resolved.to_sql_with(provider.sql_generator())
153 }
154
155 pub async fn to_list(self) -> EFResult<Vec<T>>
161 where
162 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
163 {
164 let includes = self.state.includes.clone();
165 let lazy_loading = self.lazy_loading_enabled;
166 let (sql, params) = self.compile_sql();
167 let provider = self.provider.as_ref().ok_or_else(|| {
168 crate::error::EFError::configuration(
169 "No provider attached to QueryBuilder. Use DbSet::query() or attach a provider."
170 .to_string(),
171 )
172 })?;
173 let mut conn = provider.get_connection().await?;
174 let rows = conn.query(&sql, ¶ms).await?;
175 let mut entities = crate::entity::materialize_entities::<T>(&rows)?;
176 if !includes.is_empty() {
177 crate::navigation_loader::load_includes(
178 &mut entities,
179 &includes,
180 &**provider,
181 self.filter_map.as_deref(),
182 )
183 .await?;
184 }
185 if lazy_loading && includes.is_empty() {
186 let provider_arc = Arc::clone(provider);
187 let filter_map = self.filter_map.clone();
188 for entity in &mut entities {
189 entity.attach_lazy_contexts(Arc::clone(&provider_arc), filter_map.clone(), 0);
190 }
191 }
192 Ok(entities)
193 }
194
195 pub async fn to_list_with_includes(self) -> EFResult<Vec<T>>
197 where
198 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
199 {
200 self.to_list().await
201 }
202
203 pub async fn first(self) -> EFResult<T>
205 where
206 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
207 {
208 let mut results = self.take(1).to_list().await?;
209 results
210 .pop()
211 .ok_or_else(|| crate::error::EFError::not_found("Entity not found".to_string()))
212 }
213
214 pub async fn first_or_default(self) -> EFResult<Option<T>>
216 where
217 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
218 {
219 let mut results = self.take(1).to_list().await?;
220 Ok(results.pop())
221 }
222
223 pub async fn count(self) -> EFResult<i64> {
225 let mut state = self.state.clone();
226 state.is_count = true;
227 let provider = self.provider.as_ref().ok_or_else(|| {
228 crate::error::EFError::configuration(
229 "No provider attached to QueryBuilder.".to_string(),
230 )
231 })?;
232 let sql = Self::compile_state_sql(&state, provider);
233 let params = state.all_params();
234 let mut conn = provider.get_connection().await?;
235 let rows = conn.query(&sql, ¶ms).await?;
236 if let Some(first_row) = rows.first() {
237 if let Some(first_val) = first_row.first() {
238 if matches!(first_val, crate::provider::DbValue::Null) {
239 return Ok(0);
240 }
241 return i64::try_from(first_val.clone()).map_err(|e| {
242 crate::error::EFError::type_conversion(format!(
243 "COUNT result is not i64: {}",
244 e
245 ))
246 });
247 }
248 }
249 Ok(0)
250 }
251
252 pub async fn any(self) -> EFResult<bool> {
254 let mut state = self.state.clone();
255 state.is_exists = true;
256 state.limit = Some(1);
257 let provider = self.provider.as_ref().ok_or_else(|| {
258 crate::error::EFError::configuration(
259 "No provider attached to QueryBuilder.".to_string(),
260 )
261 })?;
262 let sql = Self::compile_state_sql(&state, provider);
263 let params = state.all_params();
264 let mut conn = provider.get_connection().await?;
265 let rows = conn.query(&sql, ¶ms).await?;
266 Ok(!rows.is_empty())
267 }
268
269 pub async fn last(self) -> EFResult<T>
276 where
277 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
278 {
279 let mut results = self.last_or_default().await?;
280 results
281 .take()
282 .ok_or_else(|| crate::error::EFError::not_found("Entity not found".to_string()))
283 }
284
285 pub async fn last_or_default(mut self) -> EFResult<Option<T>>
294 where
295 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
296 {
297 if self.state.orderings.is_empty() {
298 let meta = T::entity_meta();
299 let pk_col = meta
300 .primary_keys
301 .first()
302 .map(|s| s.as_ref())
303 .or_else(|| {
304 meta.properties
305 .iter()
306 .find(|p| p.is_primary_key)
307 .map(|p| p.column_name.as_ref())
308 })
309 .ok_or_else(|| {
310 crate::error::EFError::query(format!(
311 "last_or_default requires a primary key on {} when no explicit ordering is set",
312 std::any::type_name::<T>()
313 ))
314 })?;
315 self.state
316 .orderings
317 .push(OrderBy::new(pk_col.to_string(), OrderDirection::Descending));
318 } else {
319 for o in &mut self.state.orderings {
320 o.direction = match o.direction {
321 OrderDirection::Ascending => OrderDirection::Descending,
322 OrderDirection::Descending => OrderDirection::Ascending,
323 };
324 }
325 }
326 let mut results = self.take(1).to_list().await?;
327 Ok(results.pop())
328 }
329
330 pub async fn single(self) -> EFResult<T>
333 where
334 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
335 {
336 let mut results = self.take(2).to_list().await?;
337 if results.len() > 1 {
338 return Err(crate::error::EFError::query(
339 "Sequence contains more than one element".to_string(),
340 ));
341 }
342 results.pop().ok_or_else(|| {
343 crate::error::EFError::not_found("Sequence contains no elements".to_string())
344 })
345 }
346
347 pub async fn single_or_default(self) -> EFResult<Option<T>>
350 where
351 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
352 {
353 let mut results = self.take(2).to_list().await?;
354 if results.len() > 1 {
355 return Err(crate::error::EFError::query(
356 "Sequence contains more than one element".to_string(),
357 ));
358 }
359 Ok(results.pop())
360 }
361
362 pub async fn long_count(self) -> EFResult<i64> {
366 self.count().await
367 }
368
369 pub async fn all<F>(self, predicate: F) -> EFResult<bool>
372 where
373 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
374 F: Fn(&T) -> bool,
375 {
376 let items = self.to_list().await?;
377 Ok(items.iter().all(predicate))
378 }
379
380 pub async fn contains(self, id: impl Into<DbValue>) -> EFResult<bool>
383 where
384 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
385 {
386 self.find(id).await.map(|opt| opt.is_some())
387 }
388
389 pub async fn to_dictionary<K, F>(
393 self,
394 key_selector: F,
395 ) -> EFResult<std::collections::HashMap<K, T>>
396 where
397 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
398 K: std::hash::Hash + Eq,
399 F: Fn(&T) -> K,
400 {
401 let items = self.to_list().await?;
402 let mut map = std::collections::HashMap::with_capacity(items.len());
403 for item in items {
404 let key = key_selector(&item);
405 map.insert(key, item);
406 }
407 Ok(map)
408 }
409
410 pub fn execute_update(self) -> ExecuteUpdateBuilder<T> {
416 ExecuteUpdateBuilder {
417 state: self.resolved_state(),
418 updates: Vec::new(),
419 provider: self.provider.clone(),
420 _phantom: PhantomData,
421 }
422 }
423
424 pub async fn execute_delete(self) -> EFResult<u64> {
426 let provider = self.provider.as_ref().ok_or_else(|| {
427 crate::error::EFError::configuration(
428 "No provider attached to QueryBuilder.".to_string(),
429 )
430 })?;
431 let gen = provider.sql_generator();
432 let resolved = self.resolved_state();
433 let where_clause = match &resolved.where_expr {
434 Some(expr) => {
435 let mut param_idx = 1usize;
436 compile_bool_expr(expr, gen, &mut param_idx)
437 }
438 None => String::new(),
439 };
440 let sql = if where_clause.is_empty() {
441 format!("DELETE FROM {}", self.state.from)
442 } else {
443 format!("DELETE FROM {} WHERE {}", self.state.from, where_clause)
444 };
445 let params = self.state.all_params();
446 let mut conn = provider.get_connection().await?;
447 conn.execute(&sql, ¶ms).await
448 }
449}