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]
53 pub const fn query(&self) -> &Query<E> {
54 &self.query
55 }
56
57 pub(super) fn map_query(mut self, map: impl FnOnce(Query<E>) -> Query<E>) -> Self {
58 self.query = map(self.query);
59 self
60 }
61
62 pub(super) fn try_map_query(
63 mut self,
64 map: impl FnOnce(Query<E>) -> Result<Query<E>, QueryError>,
65 ) -> Result<Self, QueryError> {
66 self.query = map(self.query)?;
67 Ok(self)
68 }
69
70 #[must_use]
78 pub fn by_id(mut self, id: Id<E>) -> Self {
79 self.query = self.query.by_id(id.key());
80 self
81 }
82
83 #[must_use]
87 pub fn by_ids<I>(mut self, ids: I) -> Self
88 where
89 I: IntoIterator<Item = Id<E>>,
90 {
91 self.query = self.query.by_ids(ids.into_iter().map(|id| id.key()));
92 self
93 }
94
95 #[must_use]
101 pub fn filter(self, predicate: Predicate) -> Self {
102 self.map_query(|query| query.filter(predicate))
103 }
104
105 pub fn filter_expr(self, expr: FilterExpr) -> Result<Self, QueryError> {
107 self.try_map_query(|query| query.filter_expr(expr))
108 }
109
110 pub fn sort_expr(self, expr: SortExpr) -> Result<Self, QueryError> {
112 self.try_map_query(|query| query.sort_expr(expr))
113 }
114
115 #[must_use]
117 pub fn order_by(self, field: impl AsRef<str>) -> Self {
118 self.map_query(|query| query.order_by(field))
119 }
120
121 #[must_use]
123 pub fn order_by_desc(self, field: impl AsRef<str>) -> Self {
124 self.map_query(|query| query.order_by_desc(field))
125 }
126
127 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
129 let field = field.as_ref().to_owned();
130 self.try_map_query(|query| query.group_by(&field))
131 }
132
133 #[must_use]
135 pub fn aggregate(self, aggregate: AggregateExpr) -> Self {
136 self.map_query(|query| query.aggregate(aggregate))
137 }
138
139 #[must_use]
141 pub fn grouped_limits(self, max_groups: u64, max_group_bytes: u64) -> Self {
142 self.map_query(|query| query.grouped_limits(max_groups, max_group_bytes))
143 }
144
145 pub fn having_group(
147 self,
148 field: impl AsRef<str>,
149 op: CompareOp,
150 value: Value,
151 ) -> Result<Self, QueryError> {
152 let field = field.as_ref().to_owned();
153 self.try_map_query(|query| query.having_group(&field, op, value))
154 }
155
156 pub fn having_aggregate(
158 self,
159 aggregate_index: usize,
160 op: CompareOp,
161 value: Value,
162 ) -> Result<Self, QueryError> {
163 self.try_map_query(|query| query.having_aggregate(aggregate_index, op, value))
164 }
165
166 #[must_use]
172 pub fn limit(self, limit: u32) -> Self {
173 self.map_query(|query| query.limit(limit))
174 }
175
176 #[must_use]
182 pub fn offset(self, offset: u32) -> Self {
183 self.map_query(|query| query.offset(offset))
184 }
185
186 #[must_use]
192 pub fn cursor(mut self, token: impl Into<String>) -> Self {
193 self.cursor_token = Some(token.into());
194 self
195 }
196
197 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
203 self.query.explain()
204 }
205
206 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
208 self.query.plan_hash_hex()
209 }
210
211 pub fn trace(&self) -> Result<QueryTracePlan, QueryError> {
213 self.session.trace_query(self.query())
214 }
215
216 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
218 if let Some(err) = self.cursor_intent_error() {
219 return Err(QueryError::Intent(err));
220 }
221
222 self.query.planned()
223 }
224
225 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
227 if let Some(err) = self.cursor_intent_error() {
228 return Err(QueryError::Intent(err));
229 }
230
231 self.query.plan()
232 }
233}
234
235impl<E> FluentLoadQuery<'_, E>
236where
237 E: EntityKind + SingletonEntity,
238 E::Key: Default,
239{
240 #[must_use]
242 pub fn only(self) -> Self {
243 self.map_query(Query::only)
244 }
245}