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 {
150 let mut range = request.top_level_range.clone();
151
152 if let Some(from_params) = request.query_params.ranges.get("") {
153 if from_params.limit.is_some() {
154 range.limit = from_params.limit;
155 }
156 if from_params.offset != 0 {
157 range.offset = from_params.offset;
158 }
159 }
160
161 range
162}
163
164fn build_where_clauses(request: &ApiRequest, table: &Table) -> Result<Vec<CoercibleLogicTree>> {
166 let type_resolver = |name: &str| -> String {
170 table
171 .get_column(name)
172 .map(|c| c.nominal_type.clone())
173 .unwrap_or_else(|| "text".to_string())
174 };
175
176 let mut clauses = Vec::new();
177
178 for filter in &request.query_params.filters_root {
180 let pg_type = type_resolver(&filter.field.name);
181 clauses.push(CoercibleLogicTree::Stmt(CoercibleFilter::from_filter(
182 filter, &pg_type,
183 )));
184 }
185
186 for (path, tree) in &request.query_params.logic {
188 if path.is_empty() {
189 clauses.push(CoercibleLogicTree::from_logic_tree(tree, type_resolver));
190 }
191 }
192
193 Ok(clauses)
194}
195
196fn build_order_terms(request: &ApiRequest, table: &Table) -> Result<Vec<CoercibleOrderTerm>> {
198 let mut terms = Vec::new();
199
200 for (path, order_terms) in &request.query_params.order {
201 if path.is_empty() {
202 for term in order_terms {
203 let field_name = match term {
204 crate::api_request::OrderTerm::Field { field, .. } => &field.name,
205 crate::api_request::OrderTerm::Relation { field, .. } => &field.name,
206 };
207
208 let pg_type = table
209 .get_column(field_name)
210 .map(|c| c.data_type.as_str())
211 .unwrap_or("text");
212
213 terms.push(CoercibleOrderTerm::from_order_term(term, pg_type));
214 }
215 }
216 }
217
218 Ok(terms)
219}
220
221fn build_relation_selects(
223 items: &[SelectItem],
224 table: &Table,
225 schema_cache: &SchemaCache,
226) -> Result<Vec<RelSelectField>> {
227 let mut rel_selects = Vec::new();
228
229 for item in items {
230 match item {
231 SelectItem::Relation {
232 relation,
233 alias,
234 hint: _,
235 join_type,
236 } => {
237 let _rel = schema_cache
239 .find_relationship(&table.qualified_identifier(), relation, &table.schema)
240 .ok_or_else(|| Error::RelationshipNotFound(relation.clone()))?;
241
242 rel_selects.push(RelSelectField {
243 name: relation.clone(),
244 agg_alias: alias
245 .clone()
246 .unwrap_or_else(|| format!("pgrst_{}", relation)),
247 join_type: join_type.clone().unwrap_or_default(),
248 is_spread: false,
249 });
250 }
251 SelectItem::SpreadRelation {
252 relation,
253 hint: _,
254 join_type,
255 } => {
256 let _rel = schema_cache
257 .find_relationship(&table.qualified_identifier(), relation, &table.schema)
258 .ok_or_else(|| Error::RelationshipNotFound(relation.clone()))?;
259
260 rel_selects.push(RelSelectField {
261 name: relation.clone(),
262 agg_alias: format!("pgrst_spread_{}", relation),
263 join_type: join_type.clone().unwrap_or_default(),
264 is_spread: true,
265 });
266 }
267 _ => {}
268 }
269 }
270
271 Ok(rel_selects)
272}
273
274#[derive(Clone, Debug)]
276pub struct ReadPlanTree {
277 pub root: ReadPlan,
279 pub children: Vec<ReadPlanTree>,
281}
282
283impl ReadPlanTree {
284 pub fn empty() -> Self {
286 Self {
287 root: ReadPlan {
288 select: vec![],
289 from: QualifiedIdentifier::unqualified(""),
290 from_alias: None,
291 where_clauses: vec![],
292 order: vec![],
293 range: Range::default(),
294 rel_name: String::new(),
295 rel_to_parent: None,
296 rel_join_conds: vec![],
297 rel_join_type: None,
298 rel_select: vec![],
299 depth: 0,
300 },
301 children: vec![],
302 }
303 }
304
305 pub fn leaf(plan: ReadPlan) -> Self {
307 Self {
308 root: plan,
309 children: vec![],
310 }
311 }
312
313 pub fn add_child(&mut self, child: ReadPlanTree) {
315 self.children.push(child);
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use super::*;
322
323 #[test]
324 fn test_read_plan_tree_empty() {
325 let tree = ReadPlanTree::empty();
326 assert!(tree.root.select.is_empty());
327 assert!(tree.children.is_empty());
328 }
329}