1use crate::capabilities::{BackendCapabilities, Feature};
8use crate::error::BackendCapabilityError;
9use crate::expr::{Expr, Ident};
10use crate::value::Value;
11
12#[derive(Debug, Clone, PartialEq)]
14pub struct InsertPlan {
15 pub table: Ident,
17 pub columns: Vec<Ident>,
19 pub rows: Vec<Vec<Value>>,
21 pub returning: Vec<Ident>,
23}
24
25#[derive(Debug, Clone, PartialEq)]
27pub struct UpdatePlan {
28 pub table: Ident,
30 pub assignments: Vec<(Ident, Expr)>,
32 pub filter: Option<Expr>,
34 pub returning: Vec<Ident>,
36}
37
38#[derive(Debug, Clone, PartialEq)]
40pub struct DeletePlan {
41 pub table: Ident,
43 pub filter: Option<Expr>,
45 pub returning: Vec<Ident>,
47}
48
49#[derive(Debug, Clone, PartialEq)]
51pub enum WritePlan {
52 Insert(InsertPlan),
54 Update(UpdatePlan),
56 Delete(DeletePlan),
58}
59
60impl WritePlan {
61 pub fn returning(&self) -> &[Ident] {
63 match self {
64 WritePlan::Insert(p) => &p.returning,
65 WritePlan::Update(p) => &p.returning,
66 WritePlan::Delete(p) => &p.returning,
67 }
68 }
69
70 pub fn required_features(&self) -> Vec<Feature> {
72 let mut out = Vec::new();
73 if !self.returning().is_empty() {
74 out.push(Feature::Returning);
75 }
76 let exprs: Vec<&Expr> = match self {
77 WritePlan::Insert(_) => Vec::new(),
78 WritePlan::Update(p) => p
79 .assignments
80 .iter()
81 .map(|(_, e)| e)
82 .chain(p.filter.iter())
83 .collect(),
84 WritePlan::Delete(p) => p.filter.iter().collect(),
85 };
86 for feature in exprs.into_iter().flat_map(Expr::required_features) {
87 if !out.contains(&feature) {
88 out.push(feature);
89 }
90 }
91 out
92 }
93
94 pub fn check(&self, caps: &BackendCapabilities) -> Result<(), BackendCapabilityError> {
99 self.required_features()
100 .into_iter()
101 .try_for_each(|f| caps.require(f))
102 }
103}