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::{OrderBy, OrderDirection};
13use super::super::compile::{
14 build_where_clauses, compile_bool_expr, has_subqueries, resolve_subqueries,
15};
16use super::super::execute_update::ExecuteUpdateBuilder;
17use super::super::state::QueryState;
18use super::core::QueryBuilder;
19
20impl<T: IEntityType> QueryBuilder<T> {
21 pub async fn find(self, id: impl Into<DbValue>) -> EFResult<Option<T>>
28 where
29 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
30 {
31 let meta = T::entity_meta();
32 let pk_col = meta
33 .primary_keys
34 .first()
35 .map(|s| s.as_ref())
36 .or_else(|| {
37 meta.properties
38 .iter()
39 .find(|p| p.is_primary_key)
40 .map(|p| p.column_name.as_ref())
41 })
42 .ok_or_else(|| {
43 crate::error::EFError::query(format!(
44 "entity {} has no primary key defined",
45 std::any::type_name::<T>()
46 ))
47 })?;
48 let col_const = pk_col.to_string();
49 self.filter_column(&col_const, "=", id)
50 .first_or_default()
51 .await
52 }
53
54 pub async fn find_by_key(mut self, keys: &[(&str, DbValue)]) -> EFResult<Option<T>>
57 where
58 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
59 {
60 for (col, val) in keys {
61 self = self.filter_column(col, "=", val.clone());
62 }
63 self.first_or_default().await
64 }
65
66 pub async fn exists_by_id(self, id: impl Into<DbValue>) -> EFResult<bool> {
72 let meta = T::entity_meta();
73 let pk_col = meta
74 .primary_keys
75 .first()
76 .map(|s| s.as_ref())
77 .or_else(|| {
78 meta.properties
79 .iter()
80 .find(|p| p.is_primary_key)
81 .map(|p| p.column_name.as_ref())
82 })
83 .ok_or_else(|| {
84 crate::error::EFError::query(format!(
85 "entity {} has no primary key defined",
86 std::any::type_name::<T>()
87 ))
88 })?;
89 let col_const = pk_col.to_string();
90 self.filter_column(&col_const, "=", id).any().await
91 }
92
93 pub async fn exists_by_key(mut self, keys: &[(&str, DbValue)]) -> EFResult<bool> {
97 for (col, val) in keys {
98 self = self.filter_column(col, "=", val.clone());
99 }
100 self.any().await
101 }
102
103 pub fn to_sql(&self) -> String {
109 let mut state = self.state.clone();
110 if let Some(ref mut expr) = state.where_expr {
111 if has_subqueries(expr) {
112 let meta = T::entity_meta();
113 resolve_subqueries(expr, &meta);
114 }
115 }
116 if let Some(provider) = &self.provider {
117 let gen = provider.sql_generator();
118 state.to_sql_with(gen)
119 } else {
120 state.to_sql()
121 }
122 }
123
124 pub fn compile_sql(&self) -> (String, Vec<DbValue>) {
125 (self.to_sql(), self.state.all_params())
126 }
127
128 pub(super) fn compile_state_sql(
129 state: &QueryState,
130 provider: &Arc<dyn IDatabaseProvider>,
131 ) -> String {
132 let gen = provider.sql_generator();
133 let mut resolved = state.clone();
134 if let Some(ref mut expr) = resolved.where_expr {
135 if has_subqueries(expr) {
136 let meta = T::entity_meta();
137 resolve_subqueries(expr, &meta);
138 }
139 }
140 resolved.to_sql_with(gen)
141 }
142
143 pub async fn to_list(self) -> EFResult<Vec<T>>
149 where
150 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
151 {
152 let includes = self.state.includes.clone();
153 let lazy_loading = self.lazy_loading_enabled;
154 let (sql, params) = self.compile_sql();
155 let provider = self.provider.as_ref().ok_or_else(|| {
156 crate::error::EFError::configuration(
157 "No provider attached to QueryBuilder. Use DbSet::query() or attach a provider."
158 .to_string(),
159 )
160 })?;
161 let mut conn = provider.get_connection().await?;
162 let rows = conn.query(&sql, ¶ms).await?;
163 let mut entities = crate::entity::materialize_entities::<T>(&rows)?;
164 if !includes.is_empty() {
165 crate::navigation_loader::load_includes(
166 &mut entities,
167 &includes,
168 &**provider,
169 self.filter_map.as_deref(),
170 )
171 .await?;
172 }
173 if lazy_loading && includes.is_empty() {
174 let provider_arc = Arc::clone(provider);
175 let filter_map = self.filter_map.clone();
176 for entity in &mut entities {
177 entity.attach_lazy_contexts(Arc::clone(&provider_arc), filter_map.clone(), 0);
178 }
179 }
180 Ok(entities)
181 }
182
183 pub async fn to_list_with_includes(self) -> EFResult<Vec<T>>
185 where
186 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
187 {
188 self.to_list().await
189 }
190
191 pub async fn first(self) -> EFResult<T>
193 where
194 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
195 {
196 let mut results = self.take(1).to_list().await?;
197 results
198 .pop()
199 .ok_or_else(|| crate::error::EFError::not_found("Entity not found".to_string()))
200 }
201
202 pub async fn first_or_default(self) -> EFResult<Option<T>>
204 where
205 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
206 {
207 let mut results = self.take(1).to_list().await?;
208 Ok(results.pop())
209 }
210
211 pub async fn count(self) -> EFResult<i64> {
213 let mut state = self.state.clone();
214 state.is_count = true;
215 let provider = self.provider.as_ref().ok_or_else(|| {
216 crate::error::EFError::configuration(
217 "No provider attached to QueryBuilder.".to_string(),
218 )
219 })?;
220 let sql = Self::compile_state_sql(&state, provider);
221 let params = state.all_params();
222 let mut conn = provider.get_connection().await?;
223 let rows = conn.query(&sql, ¶ms).await?;
224 if let Some(first_row) = rows.first() {
225 if let Some(first_val) = first_row.first() {
226 if matches!(first_val, crate::provider::DbValue::Null) {
227 return Ok(0);
228 }
229 return i64::try_from(first_val.clone()).map_err(|e| {
230 crate::error::EFError::type_conversion(format!(
231 "COUNT result is not i64: {}",
232 e
233 ))
234 });
235 }
236 }
237 Ok(0)
238 }
239
240 pub async fn any(self) -> EFResult<bool> {
242 let mut state = self.state.clone();
243 state.is_exists = true;
244 state.limit = Some(1);
245 let provider = self.provider.as_ref().ok_or_else(|| {
246 crate::error::EFError::configuration(
247 "No provider attached to QueryBuilder.".to_string(),
248 )
249 })?;
250 let sql = Self::compile_state_sql(&state, provider);
251 let params = state.all_params();
252 let mut conn = provider.get_connection().await?;
253 let rows = conn.query(&sql, ¶ms).await?;
254 Ok(!rows.is_empty())
255 }
256
257 pub async fn last(self) -> EFResult<T>
264 where
265 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
266 {
267 let mut results = self.last_or_default().await?;
268 results
269 .take()
270 .ok_or_else(|| crate::error::EFError::not_found("Entity not found".to_string()))
271 }
272
273 pub async fn last_or_default(mut self) -> EFResult<Option<T>>
282 where
283 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
284 {
285 if self.state.orderings.is_empty() {
286 let meta = T::entity_meta();
287 let pk_col = meta
288 .primary_keys
289 .first()
290 .map(|s| s.as_ref())
291 .or_else(|| {
292 meta.properties
293 .iter()
294 .find(|p| p.is_primary_key)
295 .map(|p| p.column_name.as_ref())
296 })
297 .ok_or_else(|| {
298 crate::error::EFError::query(format!(
299 "last_or_default requires a primary key on {} when no explicit ordering is set",
300 std::any::type_name::<T>()
301 ))
302 })?;
303 self.state
304 .orderings
305 .push(OrderBy::new(pk_col.to_string(), OrderDirection::Descending));
306 } else {
307 for o in &mut self.state.orderings {
308 o.direction = match o.direction {
309 OrderDirection::Ascending => OrderDirection::Descending,
310 OrderDirection::Descending => OrderDirection::Ascending,
311 };
312 }
313 }
314 let mut results = self.take(1).to_list().await?;
315 Ok(results.pop())
316 }
317
318 pub async fn single(self) -> EFResult<T>
321 where
322 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
323 {
324 let mut results = self.take(2).to_list().await?;
325 if results.len() > 1 {
326 return Err(crate::error::EFError::query(
327 "Sequence contains more than one element".to_string(),
328 ));
329 }
330 results.pop().ok_or_else(|| {
331 crate::error::EFError::not_found("Sequence contains no elements".to_string())
332 })
333 }
334
335 pub async fn single_or_default(self) -> EFResult<Option<T>>
338 where
339 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
340 {
341 let mut results = self.take(2).to_list().await?;
342 if results.len() > 1 {
343 return Err(crate::error::EFError::query(
344 "Sequence contains more than one element".to_string(),
345 ));
346 }
347 Ok(results.pop())
348 }
349
350 pub async fn long_count(self) -> EFResult<i64> {
354 self.count().await
355 }
356
357 pub async fn all<F>(self, predicate: F) -> EFResult<bool>
360 where
361 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
362 F: Fn(&T) -> bool,
363 {
364 let items = self.to_list().await?;
365 Ok(items.iter().all(predicate))
366 }
367
368 pub async fn contains(self, id: impl Into<DbValue>) -> EFResult<bool>
371 where
372 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
373 {
374 self.find(id).await.map(|opt| opt.is_some())
375 }
376
377 pub async fn to_dictionary<K, F>(
381 self,
382 key_selector: F,
383 ) -> EFResult<std::collections::HashMap<K, T>>
384 where
385 T: IFromRow + INavigationSetter + IGetKeyValues + IEntitySnapshot + ILazyInit,
386 K: std::hash::Hash + Eq,
387 F: Fn(&T) -> K,
388 {
389 let items = self.to_list().await?;
390 let mut map = std::collections::HashMap::with_capacity(items.len());
391 for item in items {
392 let key = key_selector(&item);
393 map.insert(key, item);
394 }
395 Ok(map)
396 }
397
398 pub fn execute_update(self) -> ExecuteUpdateBuilder<T> {
404 ExecuteUpdateBuilder {
405 state: self.state.clone(),
406 updates: Vec::new(),
407 provider: self.provider.clone(),
408 _phantom: PhantomData,
409 }
410 }
411
412 pub async fn execute_delete(self) -> EFResult<u64> {
414 let provider = self.provider.as_ref().ok_or_else(|| {
415 crate::error::EFError::configuration(
416 "No provider attached to QueryBuilder.".to_string(),
417 )
418 })?;
419 let gen = provider.sql_generator();
420 let mut resolved_expr = self.state.where_expr.clone();
421 if let Some(ref mut expr) = resolved_expr {
422 if has_subqueries(expr) {
423 let meta = T::entity_meta();
424 resolve_subqueries(expr, &meta);
425 }
426 }
427 let where_clause = if let Some(ref expr) = resolved_expr {
428 let mut param_idx = 1usize;
429 compile_bool_expr(expr, gen, &mut param_idx)
430 } else {
431 build_where_clauses(&self.state.filters, gen)
432 };
433 let sql = if where_clause.is_empty() {
434 format!("DELETE FROM {}", self.state.from)
435 } else {
436 format!("DELETE FROM {} WHERE {}", self.state.from, where_clause)
437 };
438 let params = self.state.all_params();
439 let mut conn = provider.get_connection().await?;
440 conn.execute(&sql, ¶ms).await
441 }
442}