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, Until, UntilEnd};
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    key: &'a [u8],
77    /// The value to compare with.
78    value: u64,
79    /// The comparison operator.
80    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(Until::new(Token::OpenParen), scanner)?
87            .ok_or(ParseError::UnexpectedToken)?
88            .data();
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(Until::new(Token::OpenParen), scanner)?
126            .ok_or(ParseError::UnexpectedToken)?
127            .data();
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    key: &'a [u8],
155    /// The value to compare with.
156    value: &'a [u8],
157    /// The comparison operator.
158    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(Until::new(Token::OpenParen), scanner)?
165            .ok_or(ParseError::UnexpectedToken)?
166            .data();
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        let value = peek(UntilEnd::default(), scanner)?
180            .ok_or(ParseError::UnexpectedToken)?
181            .data;
182
183        Ok(Value { key, value, op })
184    }
185}
186
187// ----------------------------------------------------------------------------
188// Compare version
189// ----------------------------------------------------------------------------
190
191/// A version compare operation.
192#[derive(Debug, PartialEq)]
193pub struct Version<'a> {
194    /// The key to compare.
195    key: &'a [u8],
196    /// The value to compare with.
197    value: u64,
198    /// The comparison operator.
199    op: OpType,
200}
201
202impl<'a> Visitor<'a, u8> for Version<'a> {
203    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
204        OptionalWhitespaces::accept(scanner)?;
205        let prefix = peek(Until::new(Token::OpenParen), scanner)?
206            .ok_or(ParseError::UnexpectedToken)?
207            .data();
208        if prefix.trim_ascii_end() != b"ver" && prefix != b"version".trim_ascii_end() {
209            return Err(ParseError::UnexpectedToken);
210        }
211
212        // Advance the scanner by the size of the prefix
213        scanner.bump_by(prefix.len());
214
215        let key = Key::accept(scanner)?.0;
216
217        OptionalWhitespaces::accept(scanner)?;
218        let op = OpType::accept(scanner)?;
219        OptionalWhitespaces::accept(scanner)?;
220        let value = Number::accept(scanner)?.0;
221
222        Ok(Version { key, value, op })
223    }
224}
225
226// ----------------------------------------------------------------------------
227// Compare lease
228// ----------------------------------------------------------------------------
229
230/// A lease compare operation.
231#[derive(Debug, PartialEq)]
232pub struct Lease<'a> {
233    /// The key to compare.
234    key: &'a [u8],
235    /// The value to compare with.
236    value: u64,
237    /// The comparison operator.
238    op: OpType,
239}
240
241impl<'a> Visitor<'a, u8> for Lease<'a> {
242    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
243        OptionalWhitespaces::accept(scanner)?;
244        let prefix = peek(Until::new(Token::OpenParen), scanner)?
245            .ok_or(ParseError::UnexpectedToken)?
246            .data();
247        if prefix.trim_ascii_end() != b"lease" {
248            return Err(ParseError::UnexpectedToken);
249        }
250
251        // Advance the scanner by the size of the prefix
252        scanner.bump_by(prefix.len());
253
254        let key = Key::accept(scanner)?.0;
255
256        OptionalWhitespaces::accept(scanner)?;
257        let op = OpType::accept(scanner)?;
258        OptionalWhitespaces::accept(scanner)?;
259        let value = Number::accept(scanner)?.0;
260
261        Ok(Lease { key, value, op })
262    }
263}
264
265//----------------------------------------------------------------------------
266// Compare
267//----------------------------------------------------------------------------
268
269/// A compare operation.
270#[derive(Debug, PartialEq)]
271pub enum Compare<'a> {
272    /// A create revision compare operation.
273    CreateRevision(CreateRevision<'a>),
274    /// A modify revision compare operation.
275    ModRevision(ModRevision<'a>),
276    /// A value compare operation.
277    Value(Value<'a>),
278    /// A version compare operation.
279    Version(Version<'a>),
280    /// A lease compare operation.
281    Lease(Lease<'a>),
282}
283
284impl<'a> Visitor<'a, u8> for Compare<'a> {
285    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
286        let compare = Acceptor::new(scanner)
287            .try_or(Compare::ModRevision)?
288            .try_or(Compare::CreateRevision)?
289            .try_or(Compare::Value)?
290            .try_or(Compare::Version)?
291            .try_or(Compare::Lease)?
292            .finish()
293            .ok_or(ParseError::UnexpectedToken)?;
294
295        Ok(compare)
296    }
297}
298
299#[cfg(test)]
300mod tests {
301    use crate::compare::{Compare, CreateRevision, Lease, ModRevision, OpType, Value, Version};
302    use elyze::scanner::Scanner;
303    use elyze::visitor::Visitor;
304
305    #[test]
306    fn test_create_revision() {
307        let data = b"create(key) = 1";
308        let mut scanner = Scanner::new(data);
309        let result = Compare::accept(&mut scanner);
310        assert!(matches!(
311            result,
312            Ok(Compare::CreateRevision(CreateRevision {
313                key: b"key",
314                value: 1,
315                op: OpType::Equal
316            }))
317        ));
318
319        let data = b"create(\"key with spaces\") = 51515221";
320        let mut scanner = Scanner::new(data);
321        let result = Compare::accept(&mut scanner);
322        assert!(matches!(
323            result,
324            Ok(Compare::CreateRevision(CreateRevision {
325                key: b"key with spaces",
326                value: 51515221,
327                op: OpType::Equal
328            }))
329        ));
330
331        let data = b"c(key) = 1";
332        let mut scanner = Scanner::new(data);
333        let result = Compare::accept(&mut scanner);
334        assert!(matches!(
335            result,
336            Ok(Compare::CreateRevision(CreateRevision {
337                key: b"key",
338                value: 1,
339                op: OpType::Equal
340            }))
341        ));
342
343        let data = b"c(key) > 1";
344        let mut scanner = Scanner::new(data);
345        let result = Compare::accept(&mut scanner);
346        assert!(matches!(
347            result,
348            Ok(Compare::CreateRevision(CreateRevision {
349                key: b"key",
350                value: 1,
351                op: OpType::GreaterThan
352            }))
353        ));
354
355        let data = b"c(key) < 1";
356        let mut scanner = Scanner::new(data);
357        let result = Compare::accept(&mut scanner);
358        assert!(matches!(
359            result,
360            Ok(Compare::CreateRevision(CreateRevision {
361                key: b"key",
362                value: 1,
363                op: OpType::LessThan
364            }))
365        ));
366    }
367
368    #[test]
369    fn test_mod_revision() {
370        let data = b"mod(key) = 1";
371        let mut scanner = Scanner::new(data);
372        let result = Compare::accept(&mut scanner);
373        assert!(matches!(
374            result,
375            Ok(Compare::ModRevision(ModRevision {
376                key: b"key",
377                value: 1,
378                op: OpType::Equal
379            }))
380        ));
381
382        let data = b"mod(\"key with spaces\") = 51515221";
383        let mut scanner = Scanner::new(data);
384        let result = Compare::accept(&mut scanner);
385        assert!(matches!(
386            result,
387            Ok(Compare::ModRevision(ModRevision {
388                key: b"key with spaces",
389                value: 51515221,
390                op: OpType::Equal
391            }))
392        ));
393
394        let data = b"m(key) = 1";
395        let mut scanner = Scanner::new(data);
396        let result = Compare::accept(&mut scanner);
397        assert!(matches!(
398            result,
399            Ok(Compare::ModRevision(ModRevision {
400                key: b"key",
401                value: 1,
402                op: OpType::Equal
403            }))
404        ));
405
406        let data = b"m(key) > 1";
407        let mut scanner = Scanner::new(data);
408        let result = Compare::accept(&mut scanner);
409        assert!(matches!(
410            result,
411            Ok(Compare::ModRevision(ModRevision {
412                key: b"key",
413                value: 1,
414                op: OpType::GreaterThan
415            }))
416        ));
417
418        let data = b"m(key) < 1";
419        let mut scanner = Scanner::new(data);
420        let result = Compare::accept(&mut scanner);
421        assert!(matches!(
422            result,
423            Ok(Compare::ModRevision(ModRevision {
424                key: b"key",
425                value: 1,
426                op: OpType::LessThan
427            }))
428        ));
429    }
430
431    #[test]
432    fn test_value() {
433        let data = b"value(key) = data";
434        let mut scanner = Scanner::new(data);
435        let result = Compare::accept(&mut scanner);
436        assert!(matches!(
437            result,
438            Ok(Compare::Value(Value {
439                key: b"key",
440                value: b"data",
441                op: OpType::Equal
442            }))
443        ));
444
445        let data = b"value(\"key with spaces\") = data";
446        let mut scanner = Scanner::new(data);
447        let result = Compare::accept(&mut scanner);
448        assert!(matches!(
449            result,
450            Ok(Compare::Value(Value {
451                key: b"key with spaces",
452                value: b"data",
453                op: OpType::Equal
454            }))
455        ));
456
457        let data = b"val(key) = data";
458        let mut scanner = Scanner::new(data);
459        let result = Compare::accept(&mut scanner);
460        assert!(matches!(
461            result,
462            Ok(Compare::Value(Value {
463                key: b"key",
464                value: b"data",
465                op: OpType::Equal
466            }))
467        ));
468
469        let data = b"val(key) > data";
470        let mut scanner = Scanner::new(data);
471        let result = Compare::accept(&mut scanner);
472        assert!(matches!(
473            result,
474            Ok(Compare::Value(Value {
475                key: b"key",
476                value: b"data",
477                op: OpType::GreaterThan
478            }))
479        ));
480
481        let data = b"val(key) < data";
482        let mut scanner = Scanner::new(data);
483        let result = Compare::accept(&mut scanner);
484        assert!(matches!(
485            result,
486            Ok(Compare::Value(Value {
487                key: b"key",
488                value: b"data",
489                op: OpType::LessThan
490            }))
491        ));
492    }
493
494    #[test]
495    fn test_version() {
496        let data = b"version(key) = 1";
497        let mut scanner = Scanner::new(data);
498        let result = Compare::accept(&mut scanner);
499        assert!(matches!(
500            result,
501            Ok(Compare::Version(Version {
502                key: b"key",
503                value: 1,
504                op: OpType::Equal
505            }))
506        ));
507
508        let data = b"version(\"key with spaces\") = 51515221";
509        let mut scanner = Scanner::new(data);
510        let result = Compare::accept(&mut scanner);
511        assert!(matches!(
512            result,
513            Ok(Compare::Version(Version {
514                key: b"key with spaces",
515                value: 51515221,
516                op: OpType::Equal
517            }))
518        ));
519
520        let data = b"ver(key) = 1";
521        let mut scanner = Scanner::new(data);
522        let result = Compare::accept(&mut scanner);
523        assert!(matches!(
524            result,
525            Ok(Compare::Version(Version {
526                key: b"key",
527                value: 1,
528                op: OpType::Equal
529            }))
530        ));
531
532        let data = b"ver(key) > 1";
533        let mut scanner = Scanner::new(data);
534        let result = Compare::accept(&mut scanner);
535        assert!(matches!(
536            result,
537            Ok(Compare::Version(Version {
538                key: b"key",
539                value: 1,
540                op: OpType::GreaterThan
541            }))
542        ));
543
544        let data = b"ver(key) < 1";
545        let mut scanner = Scanner::new(data);
546        let result = Compare::accept(&mut scanner);
547        assert!(matches!(
548            result,
549            Ok(Compare::Version(Version {
550                key: b"key",
551                value: 1,
552                op: OpType::LessThan
553            }))
554        ));
555    }
556
557    #[test]
558    fn test_lease() {
559        let data = b"lease(key) = 1";
560        let mut scanner = Scanner::new(data);
561        let result = Compare::accept(&mut scanner);
562        assert!(matches!(
563            result,
564            Ok(Compare::Lease(Lease {
565                key: b"key",
566                value: 1,
567                op: OpType::Equal
568            }))
569        ));
570
571        let data = b"lease(\"key with spaces\") = 51515221";
572        let mut scanner = Scanner::new(data);
573        let result = Compare::accept(&mut scanner);
574        assert!(matches!(
575            result,
576            Ok(Compare::Lease(Lease {
577                key: b"key with spaces",
578                value: 51515221,
579                op: OpType::Equal
580            }))
581        ));
582
583        let data = b"lease(key) > 1";
584        let mut scanner = Scanner::new(data);
585        let result = Compare::accept(&mut scanner);
586        assert!(matches!(
587            result,
588            Ok(Compare::Lease(Lease {
589                key: b"key",
590                value: 1,
591                op: OpType::GreaterThan
592            }))
593        ));
594
595        let data = b"lease(key) < 1";
596        let mut scanner = Scanner::new(data);
597        let result = Compare::accept(&mut scanner);
598        assert!(matches!(
599            result,
600            Ok(Compare::Lease(Lease {
601                key: b"key",
602                value: 1,
603                op: OpType::LessThan
604            }))
605        ));
606    }
607}