cratestack_sqlx/query/read/
aggregate_count.rs1use cratestack_core::{CoolContext, CoolError};
4
5use crate::query::support::{ReadPolicyKind, push_scoped_conditions};
6use crate::{FilterExpr, ModelDescriptor, SqlxRuntime, sqlx};
7
8#[derive(Debug, Clone)]
9pub struct AggregateCount<'a, M: 'static, PK: 'static> {
10 runtime: &'a SqlxRuntime,
11 descriptor: &'static ModelDescriptor<M, PK>,
12 filters: Vec<FilterExpr>,
13}
14
15impl<'a, M: 'static, PK: 'static> AggregateCount<'a, M, PK> {
16 pub(super) fn new(
17 runtime: &'a SqlxRuntime,
18 descriptor: &'static ModelDescriptor<M, PK>,
19 ) -> Self {
20 Self {
21 runtime,
22 descriptor,
23 filters: Vec::new(),
24 }
25 }
26
27 pub fn where_(mut self, filter: crate::Filter) -> Self {
28 self.filters.push(FilterExpr::from(filter));
29 self
30 }
31
32 pub fn where_expr(mut self, filter: FilterExpr) -> Self {
33 self.filters.push(filter);
34 self
35 }
36
37 pub fn where_any(mut self, filters: impl IntoIterator<Item = FilterExpr>) -> Self {
38 self.filters.push(FilterExpr::any(filters));
39 self
40 }
41
42 pub fn where_optional<F>(mut self, filter: Option<F>) -> Self
43 where
44 F: Into<FilterExpr>,
45 {
46 if let Some(filter) = filter {
47 self.filters.push(filter.into());
48 }
49 self
50 }
51
52 fn build_query<'q>(&self, ctx: &CoolContext) -> sqlx::QueryBuilder<'q, sqlx::Postgres> {
53 let mut query = sqlx::QueryBuilder::<sqlx::Postgres>::new("SELECT COUNT(*) FROM ");
54 query.push(self.descriptor.table_name);
55 push_scoped_conditions(
56 &mut query,
57 self.descriptor,
58 &self.filters,
59 None::<(&'static str, i64)>,
60 ctx,
61 ReadPolicyKind::List,
62 );
63 query
64 }
65
66 pub async fn run(self, ctx: &CoolContext) -> Result<i64, CoolError> {
67 let mut query = self.build_query(ctx);
68 let value: (i64,) = query
69 .build_query_as::<(i64,)>()
70 .fetch_one(self.runtime.pool())
71 .await
72 .map_err(|error| CoolError::Database(error.to_string()))?;
73 Ok(value.0)
74 }
75
76 pub async fn run_in_tx<'tx>(
77 self,
78 tx: &mut sqlx::Transaction<'tx, sqlx::Postgres>,
79 ctx: &CoolContext,
80 ) -> Result<i64, CoolError> {
81 let mut query = self.build_query(ctx);
82 let value: (i64,) = query
83 .build_query_as::<(i64,)>()
84 .fetch_one(&mut **tx)
85 .await
86 .map_err(|error| CoolError::Database(error.to_string()))?;
87 Ok(value.0)
88 }
89}