1use reifydb_codec::{
5 encoded::row::EncodedRow,
6 key::encoded::{EncodedKey, EncodedKeyRange},
7};
8use reifydb_value::Result;
9
10use super::{StateIterator, utils};
11use crate::{Operator, transaction::FlowTransaction};
12
13pub trait RawStatefulOperator: Operator {
14 fn state_get(&self, txn: &mut FlowTransaction, key: &EncodedKey) -> Result<Option<EncodedRow>> {
15 utils::state_get(self.id(), txn, key)
16 }
17
18 fn state_set(&self, txn: &mut FlowTransaction, key: &EncodedKey, value: EncodedRow) -> Result<()> {
19 utils::state_set(self.id(), txn, key, value)
20 }
21
22 fn state_remove(&self, txn: &mut FlowTransaction, key: &EncodedKey) -> Result<()> {
23 utils::state_remove(self.id(), txn, key)
24 }
25
26 fn state_drop(&self, txn: &mut FlowTransaction, key: &EncodedKey) -> Result<()> {
27 utils::state_drop(self.id(), txn, key)
28 }
29
30 fn state_scan_all(&self, txn: &mut FlowTransaction) -> Result<Vec<(EncodedKey, EncodedRow)>> {
31 utils::state_scan_all(self.id(), txn)
32 }
33
34 fn state_range<'a>(&self, txn: &'a mut FlowTransaction, range: EncodedKeyRange) -> StateIterator<'a> {
35 utils::state_range(self.id(), txn, range)
36 }
37
38 fn state_clear(&self, txn: &mut FlowTransaction) -> Result<()> {
39 utils::state_clear(self.id(), txn)
40 }
41
42 fn internal_state_get(&self, txn: &mut FlowTransaction, key: &EncodedKey) -> Result<Option<EncodedRow>> {
43 utils::internal_state_get(self.id(), txn, key)
44 }
45
46 fn internal_state_set(&self, txn: &mut FlowTransaction, key: &EncodedKey, value: EncodedRow) -> Result<()> {
47 utils::internal_state_set(self.id(), txn, key, value)
48 }
49
50 fn internal_state_remove(&self, txn: &mut FlowTransaction, key: &EncodedKey) -> Result<()> {
51 utils::internal_state_remove(self.id(), txn, key)
52 }
53
54 fn internal_state_drop(&self, txn: &mut FlowTransaction, key: &EncodedKey) -> Result<()> {
55 utils::internal_state_drop(self.id(), txn, key)
56 }
57}
58
59#[cfg(test)]
60pub mod tests {
61 use std::ops::Bound::{Excluded, Included};
62
63 use reifydb_catalog::catalog::Catalog;
64 use reifydb_core::{common::CommitVersion, interface::catalog::flow::FlowNodeId};
65 use reifydb_runtime::context::clock::{Clock, MockClock};
66 use reifydb_transaction::interceptor::interceptors::Interceptors;
67 use reifydb_value::util::cowvec::CowVec;
68
69 use super::*;
70 use crate::{operator::stateful::test_utils::test::*, transaction::FlowTransaction};
71
72 impl RawStatefulOperator for TestOperator {}
73
74 #[test]
75 fn test_simple_state_get_set() {
76 let mut txn = create_test_transaction();
77 let mut txn = FlowTransaction::deferred(
78 &mut txn,
79 CommitVersion(1),
80 Catalog::testing(),
81 Interceptors::new(),
82 Clock::Mock(MockClock::from_millis(1000)),
83 );
84 let operator = TestOperator::simple(FlowNodeId(1));
85 let key = test_key("simple_test");
86 let value = test_row();
87
88 assert!(operator.state_get(&mut txn, &key).unwrap().is_none());
90
91 operator.state_set(&mut txn, &key, value.clone()).unwrap();
93 let result = operator.state_get(&mut txn, &key).unwrap();
94 assert!(result.is_some());
95 assert_row_eq(&result.unwrap(), &value);
96 }
97
98 #[test]
99 fn test_simple_state_remove() {
100 let mut txn = create_test_transaction();
101 let mut txn = FlowTransaction::deferred(
102 &mut txn,
103 CommitVersion(1),
104 Catalog::testing(),
105 Interceptors::new(),
106 Clock::Mock(MockClock::from_millis(1000)),
107 );
108 let operator = TestOperator::simple(FlowNodeId(1));
109 let key = test_key("remove_test");
110 let value = test_row();
111
112 operator.state_set(&mut txn, &key, value).unwrap();
114 assert!(operator.state_get(&mut txn, &key).unwrap().is_some());
115
116 operator.state_remove(&mut txn, &key).unwrap();
117 assert!(operator.state_get(&mut txn, &key).unwrap().is_none());
118 }
119
120 #[test]
121 fn test_simple_state_scan_all() {
122 let mut txn = create_test_transaction();
123 let mut txn = FlowTransaction::deferred(
124 &mut txn,
125 CommitVersion(1),
126 Catalog::testing(),
127 Interceptors::new(),
128 Clock::Mock(MockClock::from_millis(1000)),
129 );
130 let operator = TestOperator::simple(FlowNodeId(1));
131
132 let entries = vec![("key_a", vec![1, 2]), ("key_b", vec![3, 4]), ("key_c", vec![5, 6])];
134 for (key_suffix, data) in &entries {
135 let key = test_key(key_suffix);
136 let value = EncodedRow(CowVec::new(data.clone()));
137 operator.state_set(&mut txn, &key, value).unwrap();
138 }
139
140 let scanned: Vec<_> = operator.state_scan_all(&mut txn).unwrap();
142 assert_eq!(scanned.len(), 3);
143 }
144
145 #[test]
146 fn test_simple_state_range() {
147 let mut txn = create_test_transaction();
148 let mut txn = FlowTransaction::deferred(
149 &mut txn,
150 CommitVersion(1),
151 Catalog::testing(),
152 Interceptors::new(),
153 Clock::Mock(MockClock::from_millis(1000)),
154 );
155 let operator = TestOperator::simple(FlowNodeId(2));
156
157 for i in 0..10 {
159 let key = test_key(&format!("{:02}", i)); let value = EncodedRow(CowVec::new(vec![i as u8]));
161 operator.state_set(&mut txn, &key, value).unwrap();
162 }
163
164 let range = EncodedKeyRange::new(Included(test_key("02")), Excluded(test_key("05")));
165 let range_result: Vec<_> = operator.state_range(&mut txn, range).collect::<Result<Vec<_>>>().unwrap();
166
167 assert_eq!(range_result.len(), 3);
169 assert_eq!(range_result[0].1.as_slice()[0], 2);
170 assert_eq!(range_result[1].1.as_slice()[0], 3);
171 assert_eq!(range_result[2].1.as_slice()[0], 4);
172 }
173
174 #[test]
175 fn test_simple_state_clear() {
176 let mut txn = create_test_transaction();
177 let mut txn = FlowTransaction::deferred(
178 &mut txn,
179 CommitVersion(1),
180 Catalog::testing(),
181 Interceptors::new(),
182 Clock::Mock(MockClock::from_millis(1000)),
183 );
184 let operator = TestOperator::simple(FlowNodeId(3));
185
186 for i in 0..5 {
188 let key = test_key(&format!("clear_{}", i));
189 let value = EncodedRow(CowVec::new(vec![i as u8]));
190 operator.state_set(&mut txn, &key, value).unwrap();
191 }
192
193 let count = operator.state_scan_all(&mut txn).unwrap().len();
195 assert_eq!(count, 5);
196
197 operator.state_clear(&mut txn).unwrap();
199
200 let count = operator.state_scan_all(&mut txn).unwrap().len();
202 assert_eq!(count, 0);
203 }
204
205 #[test]
206 fn test_operator_isolation() {
207 let mut txn = create_test_transaction();
208 let mut txn = FlowTransaction::deferred(
209 &mut txn,
210 CommitVersion(1),
211 Catalog::testing(),
212 Interceptors::new(),
213 Clock::Mock(MockClock::from_millis(1000)),
214 );
215 let operator1 = TestOperator::simple(FlowNodeId(10));
216 let operator2 = TestOperator::simple(FlowNodeId(20));
217 let shared_key = test_key("shared");
218
219 let value1 = EncodedRow(CowVec::new(vec![1]));
220 let value2 = EncodedRow(CowVec::new(vec![2]));
221
222 operator1.state_set(&mut txn, &shared_key, value1.clone()).unwrap();
224 operator2.state_set(&mut txn, &shared_key, value2.clone()).unwrap();
225
226 let result1 = operator1.state_get(&mut txn, &shared_key).unwrap().unwrap();
228 let result2 = operator2.state_get(&mut txn, &shared_key).unwrap().unwrap();
229
230 assert_row_eq(&result1, &value1);
231 assert_row_eq(&result2, &value2);
232 }
233
234 #[test]
235 fn test_empty_range() {
236 let mut txn = create_test_transaction();
237 let mut txn = FlowTransaction::deferred(
238 &mut txn,
239 CommitVersion(1),
240 Catalog::testing(),
241 Interceptors::new(),
242 Clock::Mock(MockClock::from_millis(1000)),
243 );
244 let operator = TestOperator::simple(FlowNodeId(4));
245
246 for i in 0..5 {
248 let key = test_key(&format!("item_{}", i));
249 let value = test_row();
250 operator.state_set(&mut txn, &key, value).unwrap();
251 }
252
253 let range = EncodedKeyRange::new(Included(test_key("z_aaa")), Excluded(test_key("z_zzz")));
255 let range_result: Vec<_> = operator.state_range(&mut txn, range).collect::<Result<Vec<_>>>().unwrap();
256
257 assert_eq!(range_result.len(), 0);
258 }
259
260 #[test]
261 fn test_overwrite_existing_key() {
262 let mut txn = create_test_transaction();
263 let mut txn = FlowTransaction::deferred(
264 &mut txn,
265 CommitVersion(1),
266 Catalog::testing(),
267 Interceptors::new(),
268 Clock::Mock(MockClock::from_millis(1000)),
269 );
270 let operator = TestOperator::simple(FlowNodeId(5));
271 let key = test_key("overwrite");
272
273 let value1 = EncodedRow(CowVec::new(vec![1, 1, 1]));
274 let value2 = EncodedRow(CowVec::new(vec![2, 2, 2]));
275
276 operator.state_set(&mut txn, &key, value1).unwrap();
278
279 operator.state_set(&mut txn, &key, value2.clone()).unwrap();
281
282 let result = operator.state_get(&mut txn, &key).unwrap().unwrap();
284 assert_row_eq(&result, &value2);
285 }
286
287 #[test]
288 fn test_remove_non_existent_key() {
289 let mut txn = create_test_transaction();
290 let mut txn = FlowTransaction::deferred(
291 &mut txn,
292 CommitVersion(1),
293 Catalog::testing(),
294 Interceptors::new(),
295 Clock::Mock(MockClock::from_millis(1000)),
296 );
297 let operator = TestOperator::simple(FlowNodeId(6));
298 let key = test_key("non_existent");
299
300 operator.state_remove(&mut txn, &key).unwrap();
302
303 assert!(operator.state_get(&mut txn, &key).unwrap().is_none());
305 }
306
307 #[test]
308 fn test_scan_after_partial_removal() {
309 let mut txn = create_test_transaction();
310 let mut txn = FlowTransaction::deferred(
311 &mut txn,
312 CommitVersion(1),
313 Catalog::testing(),
314 Interceptors::new(),
315 Clock::Mock(MockClock::from_millis(1000)),
316 );
317 let operator = TestOperator::simple(FlowNodeId(7));
318
319 for i in 0..5 {
321 let key = test_key(&format!("partial_{}", i));
322 let value = EncodedRow(CowVec::new(vec![i as u8]));
323 operator.state_set(&mut txn, &key, value).unwrap();
324 }
325
326 operator.state_remove(&mut txn, &test_key("partial_1")).unwrap();
328 operator.state_remove(&mut txn, &test_key("partial_3")).unwrap();
329
330 let remaining: Vec<_> = operator.state_scan_all(&mut txn).unwrap();
332 assert_eq!(remaining.len(), 3);
333 }
334}