icydb_core/db/query/
dynamic.rs1use crate::db::query::{
7 builder::AggregateExpr,
8 expr::{FilterExpr, OrderTerm},
9};
10
11#[derive(Clone, Debug)]
20pub struct DynamicQuery {
21 entity: String,
22 filter: Option<FilterExpr>,
23 order: Vec<OrderTerm>,
24 fields: Vec<String>,
25 #[cfg(test)]
26 distinct: bool,
27 limit: Option<u32>,
28 group_fields: Vec<String>,
29 aggregates: Vec<AggregateExpr>,
30 grouped_limits: Option<(u32, u32)>,
31 cursor: Option<String>,
32}
33
34impl DynamicQuery {
35 #[must_use]
37 pub fn new(entity: impl Into<String>) -> Self {
38 Self {
39 entity: entity.into(),
40 filter: None,
41 order: Vec::new(),
42 fields: Vec::new(),
43 #[cfg(test)]
44 distinct: false,
45 limit: None,
46 group_fields: Vec::new(),
47 aggregates: Vec::new(),
48 grouped_limits: None,
49 cursor: None,
50 }
51 }
52
53 #[must_use]
55 pub fn filter(mut self, filter: impl Into<FilterExpr>) -> Self {
56 self.filter = Some(filter.into());
57 self
58 }
59
60 #[must_use]
62 pub fn order_by(mut self, order: OrderTerm) -> Self {
63 self.order.push(order);
64 self
65 }
66
67 #[must_use]
72 pub fn select<I, S>(mut self, fields: I) -> Self
73 where
74 I: IntoIterator<Item = S>,
75 S: Into<String>,
76 {
77 self.fields = fields.into_iter().map(Into::into).collect();
78 self
79 }
80
81 #[must_use]
83 pub const fn limit(mut self, limit: u32) -> Self {
84 self.limit = Some(limit);
85 self
86 }
87
88 #[cfg(test)]
94 #[must_use]
95 pub(in crate::db) const fn distinct_for_internal_execution(mut self) -> Self {
96 self.distinct = true;
97 self
98 }
99
100 #[must_use]
102 pub fn group_by(mut self, field: impl Into<String>) -> Self {
103 self.group_fields.push(field.into());
104 self
105 }
106
107 #[must_use]
109 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
110 self.aggregates.push(aggregate);
111 self
112 }
113
114 #[must_use]
119 pub const fn grouped_limits(mut self, max_groups: u32, max_group_bytes: u32) -> Self {
120 self.grouped_limits = Some((max_groups, max_group_bytes));
121 self
122 }
123
124 #[must_use]
126 pub fn cursor(mut self, cursor: impl Into<String>) -> Self {
127 self.cursor = Some(cursor.into());
128 self
129 }
130
131 pub(in crate::db) const fn entity(&self) -> &str {
132 self.entity.as_str()
133 }
134
135 pub(in crate::db) const fn filter_expr(&self) -> Option<&FilterExpr> {
136 self.filter.as_ref()
137 }
138
139 pub(in crate::db) const fn order_terms(&self) -> &[OrderTerm] {
140 self.order.as_slice()
141 }
142
143 pub(in crate::db) const fn selected_fields(&self) -> &[String] {
144 self.fields.as_slice()
145 }
146
147 pub(in crate::db) const fn row_limit(&self) -> Option<u32> {
148 self.limit
149 }
150
151 #[cfg(test)]
152 pub(in crate::db) const fn projection_is_distinct(&self) -> bool {
153 self.distinct
154 }
155
156 pub(in crate::db) const fn has_grouping(&self) -> bool {
157 !self.group_fields.is_empty() || !self.aggregates.is_empty()
158 }
159
160 pub(in crate::db) const fn group_fields(&self) -> &[String] {
161 self.group_fields.as_slice()
162 }
163
164 pub(in crate::db) const fn aggregates(&self) -> &[AggregateExpr] {
165 self.aggregates.as_slice()
166 }
167
168 pub(in crate::db) const fn grouped_execution_limits(&self) -> Option<(u32, u32)> {
169 self.grouped_limits
170 }
171
172 pub(in crate::db) fn continuation_cursor(&self) -> Option<&str> {
173 self.cursor.as_deref()
174 }
175}