uqa_sql/ast/
assignment_target.rs1use serde::{Deserialize, Deserializer, Serialize, Serializer};
10
11#[derive(Debug, Clone, PartialEq)]
13pub struct AssignmentTarget<E = super::Expr> {
14 pub column: String,
15 pub indirection: Vec<AssignmentStep<E>>,
16}
17
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19pub enum AssignmentStep<E> {
20 Field(String),
21 Index(Box<E>),
22 Slice {
23 lower: Option<Box<E>>,
24 upper: Option<Box<E>>,
25 },
26}
27
28impl<E> From<String> for AssignmentTarget<E> {
29 fn from(column: String) -> Self {
30 Self {
31 column,
32 indirection: Vec::new(),
33 }
34 }
35}
36
37impl<E> From<&str> for AssignmentTarget<E> {
38 fn from(column: &str) -> Self {
39 column.to_owned().into()
40 }
41}
42
43impl<E> AssignmentTarget<E> {
44 pub fn is_whole_column(&self) -> bool {
45 self.indirection.is_empty()
46 }
47
48 pub fn expressions(&self) -> impl Iterator<Item = &E> {
49 self.indirection.iter().flat_map(|step| {
50 match step {
51 AssignmentStep::Field(_) => [None, None],
52 AssignmentStep::Index(index) => [Some(index.as_ref()), None],
53 AssignmentStep::Slice { lower, upper } => [lower.as_deref(), upper.as_deref()],
54 }
55 .into_iter()
56 .flatten()
57 })
58 }
59
60 pub fn expressions_mut(&mut self) -> impl Iterator<Item = &mut E> {
61 self.indirection.iter_mut().flat_map(|step| {
62 match step {
63 AssignmentStep::Field(_) => [None, None],
64 AssignmentStep::Index(index) => [Some(index.as_mut()), None],
65 AssignmentStep::Slice { lower, upper } => {
66 [lower.as_deref_mut(), upper.as_deref_mut()]
67 }
68 }
69 .into_iter()
70 .flatten()
71 })
72 }
73
74 pub fn map<T>(self, mut map: impl FnMut(E) -> T) -> AssignmentTarget<T> {
75 AssignmentTarget {
76 column: self.column,
77 indirection: self
78 .indirection
79 .into_iter()
80 .map(|step| match step {
81 AssignmentStep::Field(field) => AssignmentStep::Field(field),
82 AssignmentStep::Index(index) => AssignmentStep::Index(Box::new(map(*index))),
83 AssignmentStep::Slice { lower, upper } => AssignmentStep::Slice {
84 lower: lower.map(|value| Box::new(map(*value))),
85 upper: upper.map(|value| Box::new(map(*value))),
86 },
87 })
88 .collect(),
89 }
90 }
91}
92
93impl<E: Serialize> Serialize for AssignmentTarget<E> {
94 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
95 #[derive(Serialize)]
96 #[serde(untagged)]
97 enum Target<'a, E> {
98 Column(&'a str),
99 Partial {
100 column: &'a str,
101 indirection: &'a [AssignmentStep<E>],
102 },
103 }
104 if self.is_whole_column() {
105 Target::<E>::Column(&self.column).serialize(serializer)
106 } else {
107 Target::Partial {
108 column: &self.column,
109 indirection: &self.indirection,
110 }
111 .serialize(serializer)
112 }
113 }
114}
115
116impl<'de, E: Deserialize<'de>> Deserialize<'de> for AssignmentTarget<E> {
117 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
118 #[derive(Deserialize)]
119 #[serde(untagged)]
120 enum Target<E> {
121 Column(String),
122 Partial {
123 column: String,
124 indirection: Vec<AssignmentStep<E>>,
125 },
126 }
127 Ok(match Target::deserialize(deserializer)? {
128 Target::Column(column) => column.into(),
129 Target::Partial {
130 column,
131 indirection,
132 } => Self {
133 column,
134 indirection,
135 },
136 })
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn ordinary_target_encoding_preserves_predecessor_definitions() {
146 let target: AssignmentTarget<i32> = serde_json::from_str("\"value\"").unwrap();
147 assert!(target.is_whole_column());
148 assert_eq!(target.column, "value");
149 assert_eq!(serde_json::to_string(&target).unwrap(), "\"value\"");
150 }
151
152 #[test]
153 fn partial_targets_keep_bound_omission_order_and_expression_rewrites() {
154 let mut target = AssignmentTarget {
155 column: "value".into(),
156 indirection: vec![
157 AssignmentStep::Index(Box::new(1)),
158 AssignmentStep::Field("items".into()),
159 AssignmentStep::Slice {
160 lower: None,
161 upper: Some(Box::new(2)),
162 },
163 AssignmentStep::Slice {
164 lower: Some(Box::new(3)),
165 upper: None,
166 },
167 ],
168 };
169 for value in target.expressions_mut() {
170 *value += 10;
171 }
172 assert_eq!(
173 target.expressions().copied().collect::<Vec<_>>(),
174 [11, 12, 13]
175 );
176 let rendered = serde_json::to_string(&target).unwrap();
177 assert_eq!(
178 serde_json::from_str::<AssignmentTarget<i32>>(&rendered).unwrap(),
179 target
180 );
181 let lowered = target.map(|value| value.to_string());
182 assert_eq!(
183 lowered
184 .expressions()
185 .map(String::as_str)
186 .collect::<Vec<_>>(),
187 ["11", "12", "13"]
188 );
189 assert!(matches!(
190 lowered.indirection[2],
191 AssignmentStep::Slice { lower: None, .. }
192 ));
193 assert!(matches!(
194 lowered.indirection[3],
195 AssignmentStep::Slice { upper: None, .. }
196 ));
197 }
198}