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