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