vantage_table/table/impls/
conditions.rs1use vantage_core::{Result, error};
2use vantage_types::Entity;
3
4use crate::{conditions::ConditionHandle, table::Table, traits::table_source::TableSource};
5
6impl<T: TableSource, E: Entity<T::Value>> Table<T, E> {
7 pub fn add_condition(&mut self, condition: impl Into<T::Condition>) {
10 let condition = condition.into();
11 if let Some((column, value)) = self.data_source.condition_equality(&condition) {
12 self.add_invariant(column, value);
13 }
14 let id = -self.next_condition_id;
15 self.next_condition_id += 1;
16 self.conditions.insert(id, condition);
17 }
18
19 pub fn temp_add_condition(&mut self, condition: impl Into<T::Condition>) -> ConditionHandle {
21 let id = self.next_condition_id;
22 self.next_condition_id += 1;
23 self.conditions.insert(id, condition.into());
24 ConditionHandle::new(id)
25 }
26
27 pub fn temp_remove_condition(&mut self, handle: ConditionHandle) -> Result<()> {
31 if handle.0 <= 0 {
32 return Err(error!("Cannot remove permanent condition"));
33 }
34 match self.conditions.shift_remove(&handle.0) {
35 Some(_) => Ok(()),
36 None => Err(
37 error!("No temporary condition for this handle", handle = handle.0)
38 .mark_not_found(),
39 ),
40 }
41 }
42
43 pub fn replace_temp_condition(
48 &mut self,
49 old: Option<ConditionHandle>,
50 new: Option<T::Condition>,
51 ) -> Result<Option<ConditionHandle>> {
52 if let Some(handle) = old {
53 self.temp_remove_condition(handle)?;
54 }
55 Ok(new.map(|condition| self.temp_add_condition(condition)))
56 }
57
58 pub fn conditions(&self) -> impl Iterator<Item = &T::Condition> {
60 self.conditions.values()
61 }
62
63 pub fn with_condition(mut self, condition: impl Into<T::Condition>) -> Self {
65 self.add_condition(condition);
66 self
67 }
68
69 pub fn add_search(&mut self, value: &str)
72 where
73 T: Sized,
74 {
75 let condition = self.data_source().search_table_condition(self, value);
76 self.add_condition(condition);
77 }
78
79 pub fn with_search(mut self, value: &str) -> Self
81 where
82 T: Sized,
83 {
84 self.add_search(value);
85 self
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use crate::mocks::mock_table_source::MockTableSource;
92
93 use super::*;
94 use vantage_expressions::expr_any;
95 use vantage_types::EmptyEntity;
96
97 #[test]
98 fn test_temp_conditions() {
99 let ds = MockTableSource::new();
100 let mut table = Table::<_, EmptyEntity>::new("test", ds);
101
102 table.add_condition(expr_any!("perm1"));
104 assert_eq!(table.conditions().count(), 1);
105
106 let handle1 = table.temp_add_condition(expr_any!("temp1"));
108 let handle2 = table.temp_add_condition(expr_any!("temp2"));
109 assert_eq!(table.conditions().count(), 3);
110
111 table.temp_remove_condition(handle1).unwrap();
113 assert_eq!(table.conditions().count(), 2);
114
115 table.add_condition(expr_any!("perm2"));
117 assert_eq!(table.conditions().count(), 3);
118
119 table.temp_remove_condition(handle2).unwrap();
121 assert_eq!(table.conditions().count(), 2);
122
123 assert_eq!(table.conditions().count(), 2);
125 }
126
127 #[test]
128 fn literal_equality_condition_registers_an_invariant() {
129 use serde_json::json;
130 use vantage_expressions::{Expression, ExpressiveEnum};
131 let mut table = Table::<_, EmptyEntity>::new("t", MockTableSource::new());
132 table.add_condition(Expression::new(
133 "{} = {}",
134 vec![
135 ExpressiveEnum::Nested(Expression::new("parent", vec![])),
136 ExpressiveEnum::Nested(Expression::new(
137 "{}",
138 vec![ExpressiveEnum::Scalar(json!("p1"))],
139 )),
140 ],
141 ));
142 assert_eq!(table.invariants().get("parent"), Some(&json!("p1")));
143 let pattern = "%x%".to_string();
144 let _ = table.temp_add_condition(expr_any!("name LIKE {}", pattern));
145 assert_eq!(
146 table.invariants().len(),
147 1,
148 "temp conditions register nothing"
149 );
150 }
151
152 #[test]
153 fn removing_a_stale_handle_is_not_found() {
154 let mut table = Table::<_, EmptyEntity>::new("test", MockTableSource::new());
155 let handle = table.temp_add_condition(expr_any!("temp"));
156 table.temp_remove_condition(handle).unwrap();
157
158 let err = table.temp_remove_condition(handle).unwrap_err();
159 assert!(err.is_not_found(), "{err}");
160 assert_eq!(table.conditions().count(), 0);
161 }
162
163 #[test]
164 fn replace_temp_condition_swaps_and_clears() {
165 let mut table = Table::<_, EmptyEntity>::new("test", MockTableSource::new());
166 table.add_condition(expr_any!("perm"));
167 let first = table
168 .replace_temp_condition(None, Some(expr_any!("a")))
169 .unwrap();
170 let second = table
171 .replace_temp_condition(first, Some(expr_any!("b")))
172 .unwrap();
173 let previews: Vec<String> = table.conditions().map(|c| c.preview()).collect();
174 assert_eq!(previews, ["perm", "b"]);
175
176 let cleared = table.replace_temp_condition(second, None).unwrap();
177 assert!(cleared.is_none());
178 let previews: Vec<String> = table.conditions().map(|c| c.preview()).collect();
179 assert_eq!(previews, ["perm"]);
180
181 let err = table
182 .replace_temp_condition(first, Some(expr_any!("c")))
183 .unwrap_err();
184 assert!(err.is_not_found(), "{err}");
185 assert_eq!(table.conditions().count(), 1, "a refused swap adds nothing");
186 }
187
188 #[test]
189 fn test_cannot_remove_permanent_condition() {
190 let ds = MockTableSource::new();
191 let mut table = Table::<_, EmptyEntity>::new("test", ds);
192
193 table.add_condition(expr_any!("perm"));
194 let _handle = table.temp_add_condition(expr_any!("temp"));
195
196 let fake_handle = ConditionHandle::new(-1);
198 let result = table.temp_remove_condition(fake_handle);
199 assert!(result.is_err());
200 }
201}