1use super::types::*;
4use crate::api_request::{ApiRequest, JoinType, QualifiedIdentifier, Range, SelectItem};
5use crate::error::{Error, Result};
6use crate::schema_cache::{Relationship, SchemaCache, Table};
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Debug, Serialize, Deserialize)]
11pub struct ReadPlan {
12 pub select: Vec<CoercibleSelectField>,
14 pub from: QualifiedIdentifier,
16 pub from_alias: Option<String>,
18 pub where_clauses: Vec<CoercibleLogicTree>,
20 pub order: Vec<CoercibleOrderTerm>,
22 pub range: Range,
24 pub rel_name: String,
26 pub rel_to_parent: Option<Relationship>,
28 pub rel_join_conds: Vec<JoinCondition>,
30 pub rel_join_type: Option<JoinType>,
32 pub rel_select: Vec<RelSelectField>,
34 pub depth: u32,
36}
37
38impl ReadPlan {
39 pub fn from_request(
41 request: &ApiRequest,
42 table: &Table,
43 schema_cache: &SchemaCache,
44 ) -> Result<Self> {
45 let qi = table.qualified_identifier();
46
47 let select = build_select_fields(&request.query_params.select, table)?;
49
50 let where_clauses = build_where_clauses(request, table)?;
52
53 let order = build_order_terms(request, table)?;
55
56 let rel_select = build_relation_selects(&request.query_params.select, table, schema_cache)?;
58
59 Ok(Self {
60 select,
61 from: qi,
62 from_alias: None,
63 where_clauses,
64 order,
65 range: resolve_top_level_range(request),
66 rel_name: table.name.clone(),
67 rel_to_parent: None,
68 rel_join_conds: vec![],
69 rel_join_type: None,
70 rel_select,
71 depth: 0,
72 })
73 }
74
75 pub fn for_mutation(
77 request: &ApiRequest,
78 table: &Table,
79 schema_cache: &SchemaCache,
80 ) -> Result<Self> {
81 let mut plan = Self::from_request(request, table, schema_cache)?;
82 plan.from_alias = Some("pgrst_mutation_result".to_string());
84 Ok(plan)
85 }
86
87 pub fn has_where(&self) -> bool {
89 !self.where_clauses.is_empty()
90 }
91
92 pub fn has_order(&self) -> bool {
94 !self.order.is_empty()
95 }
96
97 pub fn has_pagination(&self) -> bool {
99 self.range.limit.is_some() || self.range.offset > 0
100 }
101}
102
103fn build_select_fields(items: &[SelectItem], table: &Table) -> Result<Vec<CoercibleSelectField>> {
105 if items.is_empty() {
106 return Ok(table
108 .columns
109 .iter()
110 .map(|(name, col)| CoercibleSelectField::simple(name, &col.data_type))
111 .collect());
112 }
113
114 let mut fields = Vec::new();
115
116 for item in items {
117 match item {
118 SelectItem::Field {
119 field,
120 aggregate,
121 aggregate_cast,
122 cast,
123 alias,
124 } => {
125 let column = table
126 .get_column(&field.name)
127 .ok_or_else(|| Error::ColumnNotFound(field.name.clone()))?;
128
129 fields.push(CoercibleSelectField {
130 field: CoercibleField::from_field(field, &column.data_type),
131 aggregate: aggregate.clone(),
132 aggregate_cast: aggregate_cast.clone(),
133 cast: cast.clone(),
134 alias: alias.clone(),
135 });
136 }
137 SelectItem::Relation { .. } | SelectItem::SpreadRelation { .. } => {}
139 }
140 }
141
142 Ok(fields)
143}
144
145fn resolve_top_level_range(request: &ApiRequest) -> Range {
153 let mut range = request.top_level_range.clone();
154
155 if let Some(from_params) = request.query_params.ranges.get("") {
156 if from_params.limit.is_some() {
157 range.limit = from_params.limit;
158 }
159 if from_params.offset != 0 {
160 range.offset = from_params.offset;
161 }
162 }
163
164 if let Some(max_rows) = request.max_rows {
165 range.limit = Some(match range.limit {
166 Some(requested) => requested.min(max_rows),
167 None => max_rows,
168 });
169 }
170
171 range
172}
173
174fn build_where_clauses(request: &ApiRequest, table: &Table) -> Result<Vec<CoercibleLogicTree>> {
176 let type_resolver = |name: &str| -> String {
180 table
181 .get_column(name)
182 .map(|c| c.nominal_type.clone())
183 .unwrap_or_else(|| "text".to_string())
184 };
185
186 let mut clauses = Vec::new();
187
188 for filter in &request.query_params.filters_root {
190 let pg_type = type_resolver(&filter.field.name);
191 clauses.push(CoercibleLogicTree::Stmt(CoercibleFilter::from_filter(
192 filter, &pg_type,
193 )));
194 }
195
196 for (path, tree) in &request.query_params.logic {
198 if path.is_empty() {
199 clauses.push(CoercibleLogicTree::from_logic_tree(tree, type_resolver));
200 }
201 }
202
203 Ok(clauses)
204}
205
206fn build_order_terms(request: &ApiRequest, table: &Table) -> Result<Vec<CoercibleOrderTerm>> {
208 let mut terms = Vec::new();
209
210 for (path, order_terms) in &request.query_params.order {
211 if path.is_empty() {
212 for term in order_terms {
213 let field_name = match term {
214 crate::api_request::OrderTerm::Field { field, .. } => &field.name,
215 crate::api_request::OrderTerm::Relation { field, .. } => &field.name,
216 };
217
218 let pg_type = table
219 .get_column(field_name)
220 .map(|c| c.data_type.as_str())
221 .unwrap_or("text");
222
223 terms.push(CoercibleOrderTerm::from_order_term(term, pg_type));
224 }
225 }
226 }
227
228 Ok(terms)
229}
230
231fn build_relation_selects(
233 items: &[SelectItem],
234 table: &Table,
235 schema_cache: &SchemaCache,
236) -> Result<Vec<RelSelectField>> {
237 let mut rel_selects = Vec::new();
238
239 for item in items {
240 match item {
241 SelectItem::Relation {
242 relation,
243 alias,
244 hint: _,
245 join_type,
246 select: _,
247 } => {
248 let _rel = schema_cache
250 .find_relationship(&table.qualified_identifier(), relation, &table.schema)
251 .ok_or_else(|| Error::RelationshipNotFound(relation.clone()))?;
252
253 rel_selects.push(RelSelectField {
254 name: relation.clone(),
255 agg_alias: alias
256 .clone()
257 .unwrap_or_else(|| format!("pgrst_{}", relation)),
258 join_type: join_type.clone().unwrap_or_default(),
259 is_spread: false,
260 });
261 }
262 SelectItem::SpreadRelation {
263 relation,
264 hint: _,
265 join_type,
266 } => {
267 let _rel = schema_cache
268 .find_relationship(&table.qualified_identifier(), relation, &table.schema)
269 .ok_or_else(|| Error::RelationshipNotFound(relation.clone()))?;
270
271 rel_selects.push(RelSelectField {
272 name: relation.clone(),
273 agg_alias: format!("pgrst_spread_{}", relation),
274 join_type: join_type.clone().unwrap_or_default(),
275 is_spread: true,
276 });
277 }
278 _ => {}
279 }
280 }
281
282 Ok(rel_selects)
283}
284
285#[derive(Clone, Debug)]
287pub struct ReadPlanTree {
288 pub root: ReadPlan,
290 pub children: Vec<ReadPlanTree>,
292}
293
294impl ReadPlanTree {
295 pub fn empty() -> Self {
297 Self {
298 root: ReadPlan {
299 select: vec![],
300 from: QualifiedIdentifier::unqualified(""),
301 from_alias: None,
302 where_clauses: vec![],
303 order: vec![],
304 range: Range::default(),
305 rel_name: String::new(),
306 rel_to_parent: None,
307 rel_join_conds: vec![],
308 rel_join_type: None,
309 rel_select: vec![],
310 depth: 0,
311 },
312 children: vec![],
313 }
314 }
315
316 pub fn leaf(plan: ReadPlan) -> Self {
318 Self {
319 root: plan,
320 children: vec![],
321 }
322 }
323
324 pub fn add_child(&mut self, child: ReadPlanTree) {
326 self.children.push(child);
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[test]
335 fn test_read_plan_tree_empty() {
336 let tree = ReadPlanTree::empty();
337 assert!(tree.root.select.is_empty());
338 assert!(tree.children.is_empty());
339 }
340}