etcd_txn_parser/
compare.rs

1//! A compare operation.
2//!
3//! See the [Compare API](https://github.com/etcd-io/etcd/blob/main/etcdctl/README.md#txn-options) for
4//! more information.
5
6use crate::operation::Data;
7use elyze::acceptor::Acceptor;
8use elyze::bytes::components::groups::GroupKind;
9use elyze::bytes::primitives::number::Number;
10use elyze::bytes::primitives::whitespace::OptionalWhitespaces;
11use elyze::bytes::token::Token;
12use elyze::errors::{ParseError, ParseResult};
13use elyze::peek::peek;
14use elyze::recognizer::Recognizer;
15use elyze::scanner::Scanner;
16use elyze::visitor::Visitor;
17
18//----------------------------------------------------------------------------
19// Key
20//----------------------------------------------------------------------------
21
22struct Key<'a>(&'a [u8]);
23
24impl<'a> Visitor<'a, u8> for Key<'a> {
25    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
26        let key_slice =
27            peek(GroupKind::Parenthesis, scanner)?.ok_or(ParseError::UnexpectedToken)?;
28        let mut inner_scanner = Scanner::new(key_slice.peeked_slice());
29        let key = Data::accept(&mut inner_scanner)?.data;
30        scanner.bump_by(key_slice.end_slice);
31
32        Ok(Key(key))
33    }
34}
35
36// ----------------------------------------------------------------------------
37// OpType
38// ----------------------------------------------------------------------------
39
40/// A comparison operator.
41#[derive(Debug, PartialEq)]
42pub enum OpType {
43    /// Equal
44    Equal,
45    /// Greater than
46    GreaterThan,
47    /// Less than
48    LessThan,
49}
50
51impl<'a> Visitor<'a, u8> for OpType {
52    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
53        let operator = Recognizer::new(scanner)
54            .try_or(Token::Equal)?
55            .try_or(Token::GreaterThan)?
56            .try_or(Token::LessThan)?
57            .finish()
58            .ok_or(ParseError::UnexpectedToken)?;
59        match operator {
60            Token::Equal => Ok(OpType::Equal),
61            Token::GreaterThan => Ok(OpType::GreaterThan),
62            Token::LessThan => Ok(OpType::LessThan),
63            _ => unreachable!("Recognizer should have caught this"),
64        }
65    }
66}
67
68// ----------------------------------------------------------------------------
69// Compare create revision
70// ----------------------------------------------------------------------------
71
72/// A create revision compare operation.
73#[derive(Debug, PartialEq)]
74pub struct CreateRevision<'a> {
75    /// The key to compare.
76    pub key: &'a [u8],
77    /// The value to compare with.
78    pub value: u64,
79    /// The comparison operator.
80    pub op: OpType,
81}
82
83impl<'a> Visitor<'a, u8> for CreateRevision<'a> {
84    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
85        OptionalWhitespaces::accept(scanner)?;
86        let prefix = peek(Token::OpenParen, scanner)?
87            .ok_or(ParseError::UnexpectedToken)?
88            .peeked_slice();
89        if prefix.trim_ascii_end() != b"c" && prefix != b"create".trim_ascii_end() {
90            return Err(ParseError::UnexpectedToken);
91        }
92
93        // Advance the scanner by the size of the prefix
94        scanner.bump_by(prefix.len());
95
96        let key = Key::accept(scanner)?.0;
97
98        OptionalWhitespaces::accept(scanner)?;
99        let op = OpType::accept(scanner)?;
100        OptionalWhitespaces::accept(scanner)?;
101        let value = Number::accept(scanner)?.0;
102
103        Ok(CreateRevision { key, value, op })
104    }
105}
106
107// ----------------------------------------------------------------------------
108// Compare mod revision
109// ----------------------------------------------------------------------------
110
111/// A modify revision compare operation.
112#[derive(Debug, PartialEq)]
113pub struct ModRevision<'a> {
114    /// The key to compare.
115    pub key: &'a [u8],
116    /// The value to compare with.
117    pub value: u64,
118    /// The comparison operator.
119    pub op: OpType,
120}
121
122impl<'a> Visitor<'a, u8> for ModRevision<'a> {
123    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
124        OptionalWhitespaces::accept(scanner)?;
125        let prefix = peek(Token::OpenParen, scanner)?
126            .ok_or(ParseError::UnexpectedToken)?
127            .peeked_slice();
128        if prefix.trim_ascii_end() != b"m" && prefix != b"mod".trim_ascii_end() {
129            return Err(ParseError::UnexpectedToken);
130        }
131
132        // Advance the scanner by the size of the prefix
133        scanner.bump_by(prefix.len());
134
135        let key = Key::accept(scanner)?.0;
136
137        OptionalWhitespaces::accept(scanner)?;
138        let op = OpType::accept(scanner)?;
139        OptionalWhitespaces::accept(scanner)?;
140        let value = Number::accept(scanner)?.0;
141
142        Ok(ModRevision { key, value, op })
143    }
144}
145
146// ----------------------------------------------------------------------------
147// Compare value
148// ----------------------------------------------------------------------------
149
150/// A value compare operation.
151#[derive(Debug, PartialEq)]
152pub struct Value<'a> {
153    /// The key to compare.
154    pub key: &'a [u8],
155    /// The value to compare with.
156    pub value: &'a [u8],
157    /// The comparison operator.
158    pub op: OpType,
159}
160
161impl<'a> Visitor<'a, u8> for Value<'a> {
162    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
163        OptionalWhitespaces::accept(scanner)?;
164        let prefix = peek(Token::OpenParen, scanner)?
165            .ok_or(ParseError::UnexpectedToken)?
166            .peeked_slice();
167        if prefix.trim_ascii_end() != b"val" && prefix != b"value".trim_ascii_end() {
168            return Err(ParseError::UnexpectedToken);
169        }
170
171        // Advance the scanner by the size of the prefix
172        scanner.bump_by(prefix.len());
173
174        let key = Key::accept(scanner)?.0;
175
176        OptionalWhitespaces::accept(scanner)?;
177        let op = OpType::accept(scanner)?;
178        OptionalWhitespaces::accept(scanner)?;
179
180        let value = Data::accept(scanner)?.data;
181
182        OptionalWhitespaces::accept(scanner)?;
183
184        Ok(Value { key, value, op })
185    }
186}
187
188// ----------------------------------------------------------------------------
189// Compare version
190// ----------------------------------------------------------------------------
191
192/// A version compare operation.
193#[derive(Debug, PartialEq)]
194pub struct Version<'a> {
195    /// The key to compare.
196    pub key: &'a [u8],
197    /// The value to compare with.
198    pub value: u64,
199    /// The comparison operator.
200    pub op: OpType,
201}
202
203impl<'a> Visitor<'a, u8> for Version<'a> {
204    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
205        OptionalWhitespaces::accept(scanner)?;
206        let prefix = peek(Token::OpenParen, scanner)?
207            .ok_or(ParseError::UnexpectedToken)?
208            .peeked_slice();
209        if prefix.trim_ascii_end() != b"ver" && prefix != b"version".trim_ascii_end() {
210            return Err(ParseError::UnexpectedToken);
211        }
212
213        // Advance the scanner by the size of the prefix
214        scanner.bump_by(prefix.len());
215
216        let key = Key::accept(scanner)?.0;
217
218        OptionalWhitespaces::accept(scanner)?;
219        let op = OpType::accept(scanner)?;
220        OptionalWhitespaces::accept(scanner)?;
221        let value = Number::accept(scanner)?.0;
222
223        Ok(Version { key, value, op })
224    }
225}
226
227// ----------------------------------------------------------------------------
228// Compare lease
229// ----------------------------------------------------------------------------
230
231/// A lease compare operation.
232#[derive(Debug, PartialEq)]
233pub struct Lease<'a> {
234    /// The key to compare.
235    pub key: &'a [u8],
236    /// The value to compare with.
237    pub value: u64,
238    /// The comparison operator.
239    pub op: OpType,
240}
241
242impl<'a> Visitor<'a, u8> for Lease<'a> {
243    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
244        OptionalWhitespaces::accept(scanner)?;
245        let prefix = peek(Token::OpenParen, scanner)?
246            .ok_or(ParseError::UnexpectedToken)?
247            .peeked_slice();
248        if prefix.trim_ascii_end() != b"lease" {
249            return Err(ParseError::UnexpectedToken);
250        }
251
252        // Advance the scanner by the size of the prefix
253        scanner.bump_by(prefix.len());
254
255        let key = Key::accept(scanner)?.0;
256
257        OptionalWhitespaces::accept(scanner)?;
258        let op = OpType::accept(scanner)?;
259        OptionalWhitespaces::accept(scanner)?;
260        let value = Number::accept(scanner)?.0;
261
262        Ok(Lease { key, value, op })
263    }
264}
265
266//----------------------------------------------------------------------------
267// Compare
268//----------------------------------------------------------------------------
269
270/// A compare operation.
271#[derive(Debug, PartialEq)]
272pub enum Compare<'a> {
273    /// A create revision compare operation.
274    CreateRevision(CreateRevision<'a>),
275    /// A modify revision compare operation.
276    ModRevision(ModRevision<'a>),
277    /// A value compare operation.
278    Value(Value<'a>),
279    /// A version compare operation.
280    Version(Version<'a>),
281    /// A lease compare operation.
282    Lease(Lease<'a>),
283}
284
285impl<'a> Visitor<'a, u8> for Compare<'a> {
286    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
287        let compare = Acceptor::new(scanner)
288            .try_or(Compare::ModRevision)?
289            .try_or(Compare::CreateRevision)?
290            .try_or(Compare::Value)?
291            .try_or(Compare::Version)?
292            .try_or(Compare::Lease)?
293            .finish()
294            .ok_or(ParseError::UnexpectedToken)?;
295
296        Ok(compare)
297    }
298}
299
300#[cfg(test)]
301mod tests {
302    use crate::compare::{Compare, CreateRevision, Lease, ModRevision, OpType, Value, Version};
303    use elyze::scanner::Scanner;
304    use elyze::visitor::Visitor;
305
306    #[test]
307    fn test_create_revision() {
308        let data = b"create(key) = 1";
309        let mut scanner = Scanner::new(data);
310        let result = Compare::accept(&mut scanner);
311        assert!(matches!(
312            result,
313            Ok(Compare::CreateRevision(CreateRevision {
314                key: b"key",
315                value: 1,
316                op: OpType::Equal
317            }))
318        ));
319
320        let data = b"create(\"key with spaces\") = 51515221";
321        let mut scanner = Scanner::new(data);
322        let result = Compare::accept(&mut scanner);
323        assert!(matches!(
324            result,
325            Ok(Compare::CreateRevision(CreateRevision {
326                key: b"key with spaces",
327                value: 51515221,
328                op: OpType::Equal
329            }))
330        ));
331
332        let data = b"c(key) = 1";
333        let mut scanner = Scanner::new(data);
334        let result = Compare::accept(&mut scanner);
335        assert!(matches!(
336            result,
337            Ok(Compare::CreateRevision(CreateRevision {
338                key: b"key",
339                value: 1,
340                op: OpType::Equal
341            }))
342        ));
343
344        let data = b"c(key) > 1";
345        let mut scanner = Scanner::new(data);
346        let result = Compare::accept(&mut scanner);
347        assert!(matches!(
348            result,
349            Ok(Compare::CreateRevision(CreateRevision {
350                key: b"key",
351                value: 1,
352                op: OpType::GreaterThan
353            }))
354        ));
355
356        let data = b"c(key) < 1";
357        let mut scanner = Scanner::new(data);
358        let result = Compare::accept(&mut scanner);
359        assert!(matches!(
360            result,
361            Ok(Compare::CreateRevision(CreateRevision {
362                key: b"key",
363                value: 1,
364                op: OpType::LessThan
365            }))
366        ));
367    }
368
369    #[test]
370    fn test_mod_revision() {
371        let data = b"mod(key) = 1";
372        let mut scanner = Scanner::new(data);
373        let result = Compare::accept(&mut scanner);
374        assert!(matches!(
375            result,
376            Ok(Compare::ModRevision(ModRevision {
377                key: b"key",
378                value: 1,
379                op: OpType::Equal
380            }))
381        ));
382
383        let data = b"mod(\"key with spaces\") = 51515221";
384        let mut scanner = Scanner::new(data);
385        let result = Compare::accept(&mut scanner);
386        assert!(matches!(
387            result,
388            Ok(Compare::ModRevision(ModRevision {
389                key: b"key with spaces",
390                value: 51515221,
391                op: OpType::Equal
392            }))
393        ));
394
395        let data = b"m(key) = 1";
396        let mut scanner = Scanner::new(data);
397        let result = Compare::accept(&mut scanner);
398        assert!(matches!(
399            result,
400            Ok(Compare::ModRevision(ModRevision {
401                key: b"key",
402                value: 1,
403                op: OpType::Equal
404            }))
405        ));
406
407        let data = b"m(key) > 1";
408        let mut scanner = Scanner::new(data);
409        let result = Compare::accept(&mut scanner);
410        assert!(matches!(
411            result,
412            Ok(Compare::ModRevision(ModRevision {
413                key: b"key",
414                value: 1,
415                op: OpType::GreaterThan
416            }))
417        ));
418
419        let data = b"m(key) < 1";
420        let mut scanner = Scanner::new(data);
421        let result = Compare::accept(&mut scanner);
422        assert!(matches!(
423            result,
424            Ok(Compare::ModRevision(ModRevision {
425                key: b"key",
426                value: 1,
427                op: OpType::LessThan
428            }))
429        ));
430    }
431
432    #[test]
433    fn test_value() {
434        let data = b"value(key) = data";
435        let mut scanner = Scanner::new(data);
436        let result = Compare::accept(&mut scanner);
437        assert!(matches!(
438            result,
439            Ok(Compare::Value(Value {
440                key: b"key",
441                value: b"data",
442                op: OpType::Equal
443            }))
444        ));
445
446        let data = b"value(\"key with spaces\") = data";
447        let mut scanner = Scanner::new(data);
448        let result = Compare::accept(&mut scanner);
449        assert!(matches!(
450            result,
451            Ok(Compare::Value(Value {
452                key: b"key with spaces",
453                value: b"data",
454                op: OpType::Equal
455            }))
456        ));
457
458        let data = b"val(key) = data";
459        let mut scanner = Scanner::new(data);
460        let result = Compare::accept(&mut scanner);
461        assert!(matches!(
462            result,
463            Ok(Compare::Value(Value {
464                key: b"key",
465                value: b"data",
466                op: OpType::Equal
467            }))
468        ));
469
470        let data = b"val(key) > data";
471        let mut scanner = Scanner::new(data);
472        let result = Compare::accept(&mut scanner);
473        assert!(matches!(
474            result,
475            Ok(Compare::Value(Value {
476                key: b"key",
477                value: b"data",
478                op: OpType::GreaterThan
479            }))
480        ));
481
482        let data = b"val(key) < data";
483        let mut scanner = Scanner::new(data);
484        let result = Compare::accept(&mut scanner);
485        assert!(matches!(
486            result,
487            Ok(Compare::Value(Value {
488                key: b"key",
489                value: b"data",
490                op: OpType::LessThan
491            }))
492        ));
493    }
494
495    #[test]
496    fn test_version() {
497        let data = b"version(key) = 1";
498        let mut scanner = Scanner::new(data);
499        let result = Compare::accept(&mut scanner);
500        assert!(matches!(
501            result,
502            Ok(Compare::Version(Version {
503                key: b"key",
504                value: 1,
505                op: OpType::Equal
506            }))
507        ));
508
509        let data = b"version(\"key with spaces\") = 51515221";
510        let mut scanner = Scanner::new(data);
511        let result = Compare::accept(&mut scanner);
512        assert!(matches!(
513            result,
514            Ok(Compare::Version(Version {
515                key: b"key with spaces",
516                value: 51515221,
517                op: OpType::Equal
518            }))
519        ));
520
521        let data = b"ver(key) = 1";
522        let mut scanner = Scanner::new(data);
523        let result = Compare::accept(&mut scanner);
524        assert!(matches!(
525            result,
526            Ok(Compare::Version(Version {
527                key: b"key",
528                value: 1,
529                op: OpType::Equal
530            }))
531        ));
532
533        let data = b"ver(key) > 1";
534        let mut scanner = Scanner::new(data);
535        let result = Compare::accept(&mut scanner);
536        assert!(matches!(
537            result,
538            Ok(Compare::Version(Version {
539                key: b"key",
540                value: 1,
541                op: OpType::GreaterThan
542            }))
543        ));
544
545        let data = b"ver(key) < 1";
546        let mut scanner = Scanner::new(data);
547        let result = Compare::accept(&mut scanner);
548        assert!(matches!(
549            result,
550            Ok(Compare::Version(Version {
551                key: b"key",
552                value: 1,
553                op: OpType::LessThan
554            }))
555        ));
556    }
557
558    #[test]
559    fn test_lease() {
560        let data = b"lease(key) = 1";
561        let mut scanner = Scanner::new(data);
562        let result = Compare::accept(&mut scanner);
563        assert!(matches!(
564            result,
565            Ok(Compare::Lease(Lease {
566                key: b"key",
567                value: 1,
568                op: OpType::Equal
569            }))
570        ));
571
572        let data = b"lease(\"key with spaces\") = 51515221";
573        let mut scanner = Scanner::new(data);
574        let result = Compare::accept(&mut scanner);
575        assert!(matches!(
576            result,
577            Ok(Compare::Lease(Lease {
578                key: b"key with spaces",
579                value: 51515221,
580                op: OpType::Equal
581            }))
582        ));
583
584        let data = b"lease(key) > 1";
585        let mut scanner = Scanner::new(data);
586        let result = Compare::accept(&mut scanner);
587        assert!(matches!(
588            result,
589            Ok(Compare::Lease(Lease {
590                key: b"key",
591                value: 1,
592                op: OpType::GreaterThan
593            }))
594        ));
595
596        let data = b"lease(key) < 1";
597        let mut scanner = Scanner::new(data);
598        let result = Compare::accept(&mut scanner);
599        assert!(matches!(
600            result,
601            Ok(Compare::Lease(Lease {
602                key: b"key",
603                value: 1,
604                op: OpType::LessThan
605            }))
606        ));
607    }
608}