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