icydb_core/db/query/fluent/load/
builder.rs1use crate::{
7 db::{
8 DbSession,
9 predicate::{CompareOp, Predicate},
10 query::{
11 builder::aggregate::AggregateExpr,
12 explain::ExplainPlan,
13 expr::{FilterExpr, SortExpr},
14 intent::{CompiledQuery, PlannedQuery, Query, QueryError},
15 trace::QueryTracePlan,
16 },
17 },
18 traits::{EntityKind, SingletonEntity},
19 types::Id,
20 value::Value,
21};
22
23pub struct FluentLoadQuery<'a, E>
32where
33 E: EntityKind,
34{
35 pub(super) session: &'a DbSession<E::Canister>,
36 pub(super) query: Query<E>,
37 pub(super) cursor_token: Option<String>,
38}
39
40impl<'a, E> FluentLoadQuery<'a, E>
41where
42 E: EntityKind,
43{
44 pub(crate) const fn new(session: &'a DbSession<E::Canister>, query: Query<E>) -> Self {
45 Self {
46 session,
47 query,
48 cursor_token: None,
49 }
50 }
51
52 #[must_use]
58 pub const fn query(&self) -> &Query<E> {
59 &self.query
60 }
61
62 pub(super) fn map_query(mut self, map: impl FnOnce(Query<E>) -> Query<E>) -> Self {
63 self.query = map(self.query);
64 self
65 }
66
67 pub(super) fn try_map_query(
68 mut self,
69 map: impl FnOnce(Query<E>) -> Result<Query<E>, QueryError>,
70 ) -> Result<Self, QueryError> {
71 self.query = map(self.query)?;
72 Ok(self)
73 }
74
75 #[must_use]
83 pub fn by_id(mut self, id: Id<E>) -> Self {
84 self.query = self.query.by_id(id.key());
85 self
86 }
87
88 #[must_use]
92 pub fn by_ids<I>(mut self, ids: I) -> Self
93 where
94 I: IntoIterator<Item = Id<E>>,
95 {
96 self.query = self.query.by_ids(ids.into_iter().map(|id| id.key()));
97 self
98 }
99
100 #[must_use]
106 pub fn filter(self, predicate: Predicate) -> Self {
107 self.map_query(|query| query.filter(predicate))
108 }
109
110 pub fn filter_expr(self, expr: FilterExpr) -> Result<Self, QueryError> {
112 self.try_map_query(|query| query.filter_expr(expr))
113 }
114
115 pub fn sort_expr(self, expr: SortExpr) -> Result<Self, QueryError> {
117 self.try_map_query(|query| query.sort_expr(expr))
118 }
119
120 #[must_use]
122 pub fn order_by(self, field: impl AsRef<str>) -> Self {
123 self.map_query(|query| query.order_by(field))
124 }
125
126 #[must_use]
128 pub fn order_by_desc(self, field: impl AsRef<str>) -> Self {
129 self.map_query(|query| query.order_by_desc(field))
130 }
131
132 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
134 let field = field.as_ref().to_owned();
135 self.try_map_query(|query| query.group_by(&field))
136 }
137
138 #[must_use]
140 pub fn aggregate(self, aggregate: AggregateExpr) -> Self {
141 self.map_query(|query| query.aggregate(aggregate))
142 }
143
144 #[must_use]
146 pub fn grouped_limits(self, max_groups: u64, max_group_bytes: u64) -> Self {
147 self.map_query(|query| query.grouped_limits(max_groups, max_group_bytes))
148 }
149
150 pub fn having_group(
152 self,
153 field: impl AsRef<str>,
154 op: CompareOp,
155 value: Value,
156 ) -> Result<Self, QueryError> {
157 let field = field.as_ref().to_owned();
158 self.try_map_query(|query| query.having_group(&field, op, value))
159 }
160
161 pub fn having_aggregate(
163 self,
164 aggregate_index: usize,
165 op: CompareOp,
166 value: Value,
167 ) -> Result<Self, QueryError> {
168 self.try_map_query(|query| query.having_aggregate(aggregate_index, op, value))
169 }
170
171 #[must_use]
177 pub fn limit(self, limit: u32) -> Self {
178 self.map_query(|query| query.limit(limit))
179 }
180
181 #[must_use]
187 pub fn offset(self, offset: u32) -> Self {
188 self.map_query(|query| query.offset(offset))
189 }
190
191 #[must_use]
197 pub fn cursor(mut self, token: impl Into<String>) -> Self {
198 self.cursor_token = Some(token.into());
199 self
200 }
201
202 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
208 self.query.explain()
209 }
210
211 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
213 self.query.plan_hash_hex()
214 }
215
216 pub fn trace(&self) -> Result<QueryTracePlan, QueryError> {
218 self.session.trace_query(self.query())
219 }
220
221 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
223 if let Some(err) = self.cursor_intent_error() {
224 return Err(QueryError::Intent(err));
225 }
226
227 self.query.planned()
228 }
229
230 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
232 if let Some(err) = self.cursor_intent_error() {
233 return Err(QueryError::Intent(err));
234 }
235
236 self.query.plan()
237 }
238}
239
240impl<E> FluentLoadQuery<'_, E>
241where
242 E: EntityKind + SingletonEntity,
243 E::Key: Default,
244{
245 #[must_use]
247 pub fn only(self) -> Self {
248 self.map_query(Query::only)
249 }
250}