drizzle_core/row/
count.rs1use super::{AggStatus, PkGroup, Scoped, SelectAs, SelectCols, SelectExpr, SelectStar};
10use crate::error::DrizzleError;
11use crate::expr::{AllAgg, AllScalar, MixedAgg};
12use crate::{Cons, ExecutableState};
13
14mod sealed {
15 pub trait Sealed {}
16
17 impl Sealed for super::ExactlyOne {}
18 impl Sealed for super::ZeroOrMore {}
19}
20
21pub trait RowCount: sealed::Sealed {
24 type Get<R>;
26
27 fn first<R>(row: Option<R>) -> Result<Self::Get<R>, DrizzleError>;
34}
35
36#[derive(Debug, Clone, Copy, Default)]
38pub struct ExactlyOne;
39
40impl RowCount for ExactlyOne {
41 type Get<R> = R;
42
43 fn first<R>(row: Option<R>) -> Result<R, DrizzleError> {
44 row.ok_or(DrizzleError::NotFound)
45 }
46}
47
48#[derive(Debug, Clone, Copy, Default)]
50pub struct ZeroOrMore;
51
52impl RowCount for ZeroOrMore {
53 type Get<R> = Option<R>;
54
55 fn first<R>(row: Option<R>) -> Result<Option<R>, DrizzleError> {
56 Ok(row)
57 }
58}
59
60pub trait QueryRows<Grouped, State> {
63 type Rows: RowCount;
65}
66
67impl<Mk, Grouped, State> QueryRows<Grouped, State> for Mk
68where
69 Mk: SelectionRows,
70 Grouped: GroupingRows,
71 State: ExecutableState,
72{
73 type Rows = State::Rows<Grouped::Rows<Mk::Rows>>;
74}
75
76pub type GetRow<Mk, Grouped, State, R> =
79 <<Mk as QueryRows<Grouped, State>>::Rows as RowCount>::Get<R>;
80
81pub trait SelectionRows {
84 type Rows: RowCount;
86}
87
88impl<M: SelectionRows, Scope, Used> SelectionRows for Scoped<M, Scope, Used> {
89 type Rows = M::Rows;
90}
91
92impl SelectionRows for SelectStar {
93 type Rows = ZeroOrMore;
94}
95
96impl SelectionRows for SelectExpr {
97 type Rows = ZeroOrMore;
98}
99
100impl<R> SelectionRows for SelectAs<R> {
101 type Rows = ZeroOrMore;
102}
103
104impl<Cols> SelectionRows for SelectCols<Cols>
105where
106 Cols: AggStatus,
107 Cols::Status: StatusRows,
108{
109 type Rows = <Cols::Status as StatusRows>::Rows;
110}
111
112pub trait GroupingRows {
115 type Rows<R: RowCount>: RowCount;
117}
118
119impl GroupingRows for () {
120 type Rows<R: RowCount> = R;
121}
122
123impl<Head, Tail> GroupingRows for Cons<Head, Tail> {
124 type Rows<R: RowCount> = ZeroOrMore;
125}
126
127impl<Table> GroupingRows for PkGroup<Table> {
128 type Rows<R: RowCount> = ZeroOrMore;
129}
130
131pub trait StatusRows {
133 type Rows: RowCount;
135}
136
137impl StatusRows for AllAgg {
138 type Rows = ExactlyOne;
139}
140
141impl StatusRows for AllScalar {
142 type Rows = ZeroOrMore;
143}
144
145impl StatusRows for MixedAgg {
146 type Rows = ZeroOrMore;
147}
148
149impl<V: crate::SQLParam> crate::expr::HasAggStatus for crate::sql::SQL<'_, V> {
152 type Status = AllScalar;
153}
154
155#[doc(hidden)]
164pub fn first_row<Mk, Grouped, State, R>(
165 row: Option<R>,
166) -> Result<GetRow<Mk, Grouped, State, R>, DrizzleError>
167where
168 Mk: QueryRows<Grouped, State>,
169{
170 <Mk::Rows as RowCount>::first(row)
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use crate::builder::{SelectFromSet, SelectOrderSet, SelectSetOpSet, SelectWhereSet};
177
178 fn rows_of<S: ExecutableState>() -> &'static str {
179 core::any::type_name::<S::Rows<ExactlyOne>>()
180 }
181
182 #[test]
183 fn only_clauses_that_keep_every_row_keep_an_aggregate_s_one_row() {
184 assert!(rows_of::<SelectFromSet>().ends_with("ExactlyOne"));
185 assert!(rows_of::<SelectWhereSet>().ends_with("ExactlyOne"));
186 assert!(rows_of::<SelectSetOpSet>().ends_with("ZeroOrMore"));
188 assert!(rows_of::<SelectOrderSet>().ends_with("ZeroOrMore"));
189 }
190}