icydb_core/db/query/fluent/load/
builder.rs1use crate::{
2 db::{
3 DbSession,
4 predicate::{CompareOp, Predicate},
5 query::{
6 builder::aggregate::AggregateExpr,
7 explain::ExplainPlan,
8 expr::{FilterExpr, SortExpr},
9 intent::{CompiledQuery, PlannedQuery, Query, QueryError},
10 trace::QueryTracePlan,
11 },
12 },
13 traits::{EntityKind, SingletonEntity},
14 types::Id,
15 value::Value,
16};
17
18pub struct FluentLoadQuery<'a, E>
27where
28 E: EntityKind,
29{
30 pub(super) session: &'a DbSession<E::Canister>,
31 pub(super) query: Query<E>,
32 pub(super) cursor_token: Option<String>,
33}
34
35impl<'a, E> FluentLoadQuery<'a, E>
36where
37 E: EntityKind,
38{
39 pub(crate) const fn new(session: &'a DbSession<E::Canister>, query: Query<E>) -> Self {
40 Self {
41 session,
42 query,
43 cursor_token: None,
44 }
45 }
46
47 #[must_use]
52 pub const fn query(&self) -> &Query<E> {
53 &self.query
54 }
55
56 pub(super) fn map_query(mut self, map: impl FnOnce(Query<E>) -> Query<E>) -> Self {
57 self.query = map(self.query);
58 self
59 }
60
61 pub(super) fn try_map_query(
62 mut self,
63 map: impl FnOnce(Query<E>) -> Result<Query<E>, QueryError>,
64 ) -> Result<Self, QueryError> {
65 self.query = map(self.query)?;
66 Ok(self)
67 }
68
69 #[must_use]
77 pub fn by_id(mut self, id: Id<E>) -> Self {
78 self.query = self.query.by_id(id.key());
79 self
80 }
81
82 #[must_use]
86 pub fn by_ids<I>(mut self, ids: I) -> Self
87 where
88 I: IntoIterator<Item = Id<E>>,
89 {
90 self.query = self.query.by_ids(ids.into_iter().map(|id| id.key()));
91 self
92 }
93
94 #[must_use]
99 pub fn filter(self, predicate: Predicate) -> Self {
100 self.map_query(|query| query.filter(predicate))
101 }
102
103 pub fn filter_expr(self, expr: FilterExpr) -> Result<Self, QueryError> {
104 self.try_map_query(|query| query.filter_expr(expr))
105 }
106
107 pub fn sort_expr(self, expr: SortExpr) -> Result<Self, QueryError> {
108 self.try_map_query(|query| query.sort_expr(expr))
109 }
110
111 #[must_use]
112 pub fn order_by(self, field: impl AsRef<str>) -> Self {
113 self.map_query(|query| query.order_by(field))
114 }
115
116 #[must_use]
117 pub fn order_by_desc(self, field: impl AsRef<str>) -> Self {
118 self.map_query(|query| query.order_by_desc(field))
119 }
120
121 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
123 let field = field.as_ref().to_owned();
124 self.try_map_query(|query| query.group_by(&field))
125 }
126
127 #[must_use]
129 pub fn aggregate(self, aggregate: AggregateExpr) -> Self {
130 self.map_query(|query| query.aggregate(aggregate))
131 }
132
133 #[must_use]
135 pub fn grouped_limits(self, max_groups: u64, max_group_bytes: u64) -> Self {
136 self.map_query(|query| query.grouped_limits(max_groups, max_group_bytes))
137 }
138
139 pub fn having_group(
141 self,
142 field: impl AsRef<str>,
143 op: CompareOp,
144 value: Value,
145 ) -> Result<Self, QueryError> {
146 let field = field.as_ref().to_owned();
147 self.try_map_query(|query| query.having_group(&field, op, value))
148 }
149
150 pub fn having_aggregate(
152 self,
153 aggregate_index: usize,
154 op: CompareOp,
155 value: Value,
156 ) -> Result<Self, QueryError> {
157 self.try_map_query(|query| query.having_aggregate(aggregate_index, op, value))
158 }
159
160 #[must_use]
166 pub fn limit(self, limit: u32) -> Self {
167 self.map_query(|query| query.limit(limit))
168 }
169
170 #[must_use]
176 pub fn offset(self, offset: u32) -> Self {
177 self.map_query(|query| query.offset(offset))
178 }
179
180 #[must_use]
186 pub fn cursor(mut self, token: impl Into<String>) -> Self {
187 self.cursor_token = Some(token.into());
188 self
189 }
190
191 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
196 self.query.explain()
197 }
198
199 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
201 self.query.plan_hash_hex()
202 }
203
204 pub fn trace(&self) -> Result<QueryTracePlan, QueryError> {
206 self.session.trace_query(self.query())
207 }
208
209 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
210 if let Some(err) = self.cursor_intent_error() {
211 return Err(QueryError::Intent(err));
212 }
213
214 self.query.planned()
215 }
216
217 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
218 if let Some(err) = self.cursor_intent_error() {
219 return Err(QueryError::Intent(err));
220 }
221
222 self.query.plan()
223 }
224}
225
226impl<E> FluentLoadQuery<'_, E>
227where
228 E: EntityKind + SingletonEntity,
229 E::Key: Default,
230{
231 #[must_use]
232 pub fn only(self) -> Self {
233 self.map_query(Query::only)
234 }
235}