scylladb_parse/
lib.rs

1use anymap::{
2    AnyMap,
3    Map,
4};
5use derive_builder::Builder;
6use derive_more::{
7    From,
8    TryInto,
9};
10use quote::{
11    quote,
12    ToTokens,
13    __private::TokenStream,
14};
15use scylladb_parse_macros::{
16    ParseFromStr,
17    ToTokens,
18};
19use std::{
20    cell::RefCell,
21    collections::{
22        BTreeMap,
23        BTreeSet,
24        HashMap,
25    },
26    convert::{
27        TryFrom,
28        TryInto,
29    },
30    fmt::{
31        Display,
32        Formatter,
33    },
34    marker::PhantomData,
35    rc::Rc,
36    str::FromStr,
37};
38use uuid::Uuid;
39
40mod statements;
41pub use statements::*;
42
43pub mod keywords;
44use keywords::*;
45
46mod data_types;
47pub use data_types::*;
48
49pub struct StreamInfo {
50    pub next_token: String,
51    pub pos: usize,
52    pub rem: usize,
53    pub ordered_tags: Vec<String>,
54    pub keyed_tags: HashMap<String, String>,
55}
56
57impl Display for StreamInfo {
58    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59        write!(
60            f,
61            "{{ next token: '{}', pos: {}, remaining: {}, ordered args: {:?}, keyed args: {:?} }}",
62            self.next_token, self.pos, self.rem, self.ordered_tags, self.keyed_tags
63        )
64    }
65}
66
67#[derive(Debug)]
68pub struct Cached<T: Parse> {
69    pub value: T::Output,
70    pub len: usize,
71}
72
73impl<T: Parse> Clone for Cached<T>
74where
75    T::Output: Clone,
76{
77    fn clone(&self) -> Self {
78        Self {
79            value: self.value.clone(),
80            len: self.len,
81        }
82    }
83}
84
85impl<T: Parse> Cached<T> {
86    pub fn new(value: T::Output, len: usize) -> Self {
87        Self { value, len }
88    }
89}
90
91#[derive(Clone)]
92pub struct StatementStream<'a> {
93    cursor: std::iter::Peekable<std::str::Chars<'a>>,
94    pos: usize,
95    rem: usize,
96    cache: Rc<RefCell<HashMap<usize, AnyMap>>>,
97    ordered_tags: Rc<RefCell<Vec<TokenStream>>>,
98    curr_ordered_tag: usize,
99    keyed_tags: Rc<RefCell<HashMap<String, TokenStream>>>,
100}
101
102impl<'a> StatementStream<'a> {
103    pub fn new(statement: &'a str) -> Self {
104        Self {
105            cursor: statement.chars().peekable(),
106            pos: 0,
107            rem: statement.chars().count(),
108            cache: Default::default(),
109            ordered_tags: Default::default(),
110            curr_ordered_tag: Default::default(),
111            keyed_tags: Default::default(),
112        }
113    }
114
115    pub fn push_ordered_tag(&mut self, tag: TokenStream) {
116        self.ordered_tags.borrow_mut().push(tag);
117    }
118
119    pub fn insert_keyed_tag(&mut self, key: String, tag: TokenStream) {
120        self.keyed_tags.borrow_mut().insert(key, tag);
121    }
122
123    pub fn info(&self) -> StreamInfo {
124        self.info_with_token(self.clone().parse_from::<Token>().unwrap_or_default())
125    }
126
127    fn info_with_token(&self, next_token: String) -> StreamInfo {
128        StreamInfo {
129            next_token,
130            pos: self.pos,
131            rem: self.rem,
132            ordered_tags: self.ordered_tags.borrow().iter().map(|t| t.to_string()).collect(),
133            keyed_tags: self
134                .keyed_tags
135                .borrow()
136                .iter()
137                .map(|(k, t)| (k.clone(), t.to_string()))
138                .collect(),
139        }
140    }
141
142    pub fn current_pos(&self) -> usize {
143        self.pos
144    }
145
146    pub fn remaining(&self) -> usize {
147        self.rem
148    }
149
150    pub fn nremaining(&self, n: usize) -> bool {
151        self.rem >= n
152    }
153
154    pub fn peek(&mut self) -> Option<char> {
155        if self.rem == 0 {
156            return None;
157        }
158        self.cursor.peek().map(|c| *c)
159    }
160
161    pub fn peekn(&mut self, n: usize) -> Option<String> {
162        if self.rem < n {
163            return None;
164        }
165        let mut cursor = self.cursor.clone();
166        let mut res = String::new();
167        for _ in 0..n {
168            if let Some(next) = cursor.next() {
169                res.push(next);
170            } else {
171                return None;
172            }
173        }
174        Some(res)
175    }
176
177    pub(crate) fn next(&mut self) -> Option<char> {
178        if self.rem == 0 {
179            return None;
180        }
181        let res = self.cursor.next();
182        if res.is_some() {
183            self.pos += 1;
184            self.rem -= 1;
185        }
186        res
187    }
188
189    pub(crate) fn nextn(&mut self, n: usize) -> Option<String> {
190        if self.nremaining(n) {
191            let mut res = String::new();
192            for _ in 0..n {
193                res.push(self.next().unwrap());
194            }
195            Some(res)
196        } else {
197            None
198        }
199    }
200
201    fn skip_whitespace(&mut self) {
202        while let Some(c) = self.peek() {
203            if c.is_whitespace() {
204                self.next();
205                continue;
206            } else {
207                break;
208            };
209        }
210    }
211
212    fn check_cache<P: 'static + Parse>(&self) -> bool {
213        self.cache
214            .borrow()
215            .get(&self.pos)
216            .and_then(|m| m.get::<Cached<P>>())
217            .is_some()
218    }
219
220    fn retrieve_cache<P: 'static + Parse>(&self) -> Option<Cached<P>>
221    where
222        P::Output: Clone,
223    {
224        self.cache
225            .borrow()
226            .get(&self.pos)
227            .and_then(|m| m.get::<Cached<P>>().cloned())
228    }
229
230    fn set_cache<P: 'static + Parse>(&self, value: P::Output, prev_pos: usize) {
231        let mut cache = self.cache.borrow_mut();
232        let map = cache.entry(prev_pos).or_insert_with(Map::new);
233        map.insert(Cached::<P>::new(value, self.pos - prev_pos));
234    }
235
236    fn set_and_retrieve_cache<P: 'static + Parse>(&self, value: P::Output, prev_pos: usize) -> P::Output
237    where
238        P::Output: Clone,
239    {
240        let mut cache = self.cache.borrow_mut();
241        let map = cache.entry(prev_pos).or_insert_with(Map::new);
242        map.entry::<Cached<P>>()
243            .or_insert(Cached::new(value, self.pos - prev_pos))
244            .value
245            .clone()
246    }
247
248    fn next_ordered_tag(&mut self) -> Option<TokenStream> {
249        let c = self.curr_ordered_tag;
250        self.curr_ordered_tag += 1;
251        self.ordered_tags.borrow().get(c).cloned()
252    }
253
254    fn ordered_tag(&self, n: usize) -> Option<TokenStream> {
255        self.ordered_tags.borrow().get(n).cloned()
256    }
257
258    fn mapped_tag(&self, key: &String) -> Option<TokenStream> {
259        self.keyed_tags.borrow_mut().get(key).cloned()
260    }
261
262    pub fn check<P: 'static + Parse>(&self) -> bool
263    where
264        P::Output: 'static + Clone,
265    {
266        if self.check_cache::<P>() {
267            return true;
268        }
269        let mut this = self.clone();
270        this.skip_whitespace();
271        P::parse(&mut this).map(|p| this.set_cache::<P>(p, self.pos)).is_ok()
272    }
273
274    pub fn find<P: 'static + Parse<Output = P> + Clone>(&self) -> Option<P> {
275        if let Some(cached) = self.retrieve_cache::<P>() {
276            return Some(cached.value);
277        }
278        let mut this = self.clone();
279        this.skip_whitespace();
280        P::parse(&mut this)
281            .ok()
282            .map(|p| this.set_and_retrieve_cache::<P>(p, self.pos))
283    }
284
285    pub fn find_from<P: 'static + Parse>(&self) -> Option<P::Output>
286    where
287        P::Output: 'static + Clone,
288    {
289        if let Some(cached) = self.retrieve_cache::<P>() {
290            return Some(cached.value);
291        }
292        let mut this = self.clone();
293        this.skip_whitespace();
294        P::parse(&mut this)
295            .ok()
296            .map(|p| this.set_and_retrieve_cache::<P>(p, self.pos))
297    }
298
299    pub fn parse<P: 'static + Parse<Output = P> + Clone>(&mut self) -> anyhow::Result<P> {
300        let pos = self.pos;
301        if let Some(cached) = self.retrieve_cache::<P>() {
302            self.nextn(cached.len);
303            return Ok(cached.value);
304        }
305        self.skip_whitespace();
306        P::parse(self).map(|p| self.set_and_retrieve_cache::<P>(p, pos))
307    }
308
309    pub fn parse_from<P: 'static + Parse>(&mut self) -> anyhow::Result<P::Output>
310    where
311        P::Output: 'static + Clone,
312    {
313        let pos = self.pos;
314        if let Some(cached) = self.retrieve_cache::<P>() {
315            self.nextn(cached.len);
316            return Ok(cached.value);
317        }
318        self.skip_whitespace();
319        P::parse(self).map(|p| self.set_and_retrieve_cache::<P>(p, pos))
320    }
321}
322
323pub trait Parse {
324    type Output;
325    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output>;
326}
327
328macro_rules! parse_tuple {
329    ($($t:ident),+) => {
330        impl<$($t: Parse),+> Parse for ($($t),+,)
331        where
332            $($t: 'static  + Clone),+,
333            $($t::Output: 'static + Clone),+
334        {
335            type Output = ($($t::Output),+,);
336            fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
337                Ok(($(
338                    s.parse_from::<$t>()?,
339                )+))
340            }
341        }
342    };
343}
344
345parse_tuple!(T0);
346parse_tuple!(T0, T1);
347parse_tuple!(T0, T1, T2);
348parse_tuple!(T0, T1, T2, T3);
349parse_tuple!(T0, T1, T2, T3, T4);
350parse_tuple!(T0, T1, T2, T3, T4, T5);
351parse_tuple!(T0, T1, T2, T3, T4, T5, T6);
352parse_tuple!(T0, T1, T2, T3, T4, T5, T6, T7);
353parse_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
354parse_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
355
356impl Parse for char {
357    type Output = Self;
358    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
359        match s.next() {
360            Some(c) => Ok(c),
361            None => Err(anyhow::anyhow!("End of statement!")),
362        }
363    }
364}
365
366impl Parse for bool {
367    type Output = Self;
368    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
369        Ok(if s.parse::<Option<TRUE>>()?.is_some() {
370            true
371        } else if s.parse::<Option<FALSE>>()?.is_some() {
372            false
373        } else {
374            anyhow::bail!("Expected boolean, found {}", s.info())
375        })
376    }
377}
378
379macro_rules! parse_number {
380    ($n:ident, $t:ident) => {
381        impl Parse for $n {
382            type Output = Self;
383            fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
384                s.parse_from::<$t>()?
385                    .parse()
386                    .map_err(|_| anyhow::anyhow!("Invalid {}! {}", std::any::type_name::<$n>(), s.info()))
387            }
388        }
389    };
390}
391
392parse_number!(i8, SignedNumber);
393parse_number!(i16, SignedNumber);
394parse_number!(i32, SignedNumber);
395parse_number!(i64, SignedNumber);
396parse_number!(u8, Number);
397parse_number!(u16, Number);
398parse_number!(u32, Number);
399parse_number!(u64, Number);
400parse_number!(f32, Float);
401parse_number!(f64, Float);
402
403#[derive(Debug)]
404pub struct If<Cond, Res>(PhantomData<fn(Cond, Res) -> (Cond, Res)>);
405impl<Cond: Parse, Res: 'static + Parse> Parse for If<Cond, Res>
406where
407    Cond: 'static + Clone,
408    Cond::Output: 'static + Clone,
409    Res::Output: 'static + Clone,
410{
411    type Output = Option<Res::Output>;
412    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
413        match s.parse_from::<Option<Cond>>()? {
414            Some(_) => Ok(Some(s.parse_from::<Res>()?)),
415            None => Ok(None),
416        }
417    }
418}
419
420impl<T: 'static + Parse + Clone> Parse for Option<T>
421where
422    T::Output: 'static + Clone,
423{
424    type Output = Option<T::Output>;
425    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
426        Ok(if s.check::<T>() {
427            Some(s.parse_from::<T>()?)
428        } else {
429            None
430        })
431    }
432}
433
434pub struct Not<T>(PhantomData<fn(T) -> T>);
435impl<T: 'static + Parse> Parse for Not<T>
436where
437    T::Output: 'static + Clone,
438{
439    type Output = bool;
440    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
441        Ok(!s.check::<T>())
442    }
443}
444
445pub type List<T, Delim> = TerminatingList<T, Delim, EmptyPeek>;
446
447#[derive(Debug)]
448pub struct TerminatingList<T, Delim, End>(PhantomData<fn(T, Delim, End) -> (T, Delim, End)>);
449impl<T: 'static + Parse, Delim: 'static + Parse + Clone, End: 'static + Parse> Parse for TerminatingList<T, Delim, End>
450where
451    Delim::Output: 'static + Clone,
452    T::Output: 'static + Clone,
453    End::Output: 'static + Clone,
454{
455    type Output = Vec<T::Output>;
456    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
457        let mut res = vec![s.parse_from::<T>()?];
458        if s.remaining() == 0 || s.check::<End>() {
459            return Ok(res);
460        }
461        while s.parse_from::<Option<Delim>>()?.is_some() {
462            if s.check::<End>() {
463                return Ok(res);
464            }
465            res.push(s.parse_from::<T>()?);
466            if s.remaining() == 0 {
467                return Ok(res);
468            }
469        }
470        Ok(res)
471    }
472}
473
474impl<T, Delim, End> Clone for TerminatingList<T, Delim, End> {
475    fn clone(&self) -> Self {
476        Self(PhantomData)
477    }
478}
479
480#[derive(Copy, Clone, Debug)]
481pub struct Nothing;
482impl Parse for Nothing {
483    type Output = Self;
484    fn parse(_: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
485        Ok(Self)
486    }
487}
488
489#[derive(Copy, Clone, Debug)]
490pub struct EmptyPeek;
491impl Parse for EmptyPeek {
492    type Output = Self;
493    fn parse(_: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
494        anyhow::bail!("Empty peek!")
495    }
496}
497
498#[derive(Copy, Clone, Debug)]
499pub struct Whitespace;
500impl Parse for Whitespace {
501    type Output = Self;
502    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
503        while let Some(c) = s.peek() {
504            if c.is_whitespace() {
505                s.next();
506            } else {
507                break;
508            }
509        }
510        Ok(Whitespace)
511    }
512}
513
514#[derive(Copy, Clone, Debug)]
515pub struct Token;
516impl Parse for Token {
517    type Output = String;
518    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
519        let mut res = String::new();
520        while let Some(c) = s.next() {
521            if c.is_whitespace() {
522                break;
523            } else {
524                res.push(c);
525            }
526        }
527        if res.is_empty() {
528            anyhow::bail!("End of statement!")
529        }
530        Ok(res)
531    }
532}
533
534#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
535pub enum Tag<T> {
536    Tag(String),
537    Value(T),
538}
539impl<T> Tag<T> {
540    pub(crate) fn into_value(self) -> anyhow::Result<T> {
541        match self {
542            Tag::Value(v) => Ok(v),
543            _ => anyhow::bail!("Expected value!"),
544        }
545    }
546}
547impl<T: 'static + Parse + Clone> Parse for Tag<T>
548where
549    T::Output: 'static + Clone,
550{
551    type Output = Tag<T::Output>;
552    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
553        Ok(if s.check::<HashTag>() {
554            let tag = s.parse_from::<HashTag>()?;
555            let tag = match tag {
556                HashTag::Keyed(key) => s
557                    .mapped_tag(&key)
558                    .ok_or_else(|| anyhow::anyhow!("No argument found for key {}: {}", key, s.info()))?,
559                HashTag::Ordered(n) => s
560                    .ordered_tag(n)
561                    .ok_or_else(|| anyhow::anyhow!("No argument found for index {}: {}", n, s.info()))?,
562                HashTag::Next => s
563                    .next_ordered_tag()
564                    .ok_or_else(|| anyhow::anyhow!("Insufficient unkeyed arguments: {}", s.info()))?,
565            };
566            Tag::Tag(tag.to_string())
567        } else {
568            Tag::Value(s.parse_from::<T>()?)
569        })
570    }
571}
572impl<T> From<T> for Tag<T> {
573    fn from(t: T) -> Self {
574        Tag::Value(t)
575    }
576}
577impl<T: Display> Display for Tag<T> {
578    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
579        match self {
580            Tag::Tag(t) => t.fmt(f),
581            Tag::Value(v) => v.fmt(f),
582        }
583    }
584}
585impl<T: Default> Default for Tag<T> {
586    fn default() -> Self {
587        Tag::Value(T::default())
588    }
589}
590
591impl<'a, T: 'a> CustomToTokens<'a> for Tag<T>
592where
593    TokenWrapper<'a, T>: ToTokens,
594{
595    fn to_tokens(&'a self, tokens: &mut TokenStream) {
596        tokens.extend(match self {
597            Tag::Tag(t) => {
598                let t = TokenStream::from_str(t).unwrap();
599                quote!(#t.into())
600            }
601            Tag::Value(v) => {
602                let v = TokenWrapper(v);
603                quote! {#v}
604            }
605        });
606    }
607}
608
609impl<T> ToTokens for Tag<T>
610where
611    for<'a> TokenWrapper<'a, T>: ToTokens,
612{
613    fn to_tokens(&self, tokens: &mut TokenStream) {
614        CustomToTokens::to_tokens(self, tokens);
615    }
616}
617#[derive(Clone, Debug)]
618pub enum HashTag {
619    Next,
620    Ordered(usize),
621    Keyed(String),
622}
623impl Parse for HashTag {
624    type Output = Self;
625    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
626        if let Some(c) = s.next() {
627            let mut res = String::new();
628            if c == '#' {
629                while let Some(c) = s.peek() {
630                    if c.is_alphanumeric() || c == '_' {
631                        s.next();
632                        res.push(c);
633                    } else {
634                        break;
635                    }
636                }
637                Ok(if res.is_empty() {
638                    Self::Next
639                } else if res.chars().all(|c| c.is_numeric()) {
640                    Self::Ordered(res.parse().unwrap())
641                } else {
642                    Self::Keyed(res)
643                })
644            } else {
645                anyhow::bail!("Expected #")
646            }
647        } else {
648            anyhow::bail!("End of statement!")
649        }
650    }
651}
652
653#[derive(Copy, Clone, Debug)]
654pub struct Alpha;
655impl Parse for Alpha {
656    type Output = String;
657    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
658        let mut res = String::new();
659        while let Some(c) = s.peek() {
660            if c.is_alphabetic() {
661                res.push(c);
662                s.next();
663            } else {
664                if res.is_empty() {
665                    anyhow::bail!("Expected text, found: {}", s.info())
666                }
667                break;
668            }
669        }
670        if res.is_empty() {
671            anyhow::bail!("End of statement!")
672        }
673        Ok(res)
674    }
675}
676
677#[derive(Copy, Clone, Debug)]
678pub struct Hex;
679impl Parse for Hex {
680    type Output = Vec<u8>;
681    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
682        let mut res = String::new();
683        while let Some(c) = s.peek() {
684            if c.is_alphanumeric() {
685                res.push(c);
686                s.next();
687            } else {
688                if res.is_empty() {
689                    anyhow::bail!("Expected hex, found: {}", s.info())
690                }
691                break;
692            }
693        }
694        if res.is_empty() {
695            anyhow::bail!("End of statement!")
696        }
697        Ok(hex::decode(res)?)
698    }
699}
700
701#[derive(Copy, Clone, Debug)]
702pub struct Alphanumeric;
703impl Parse for Alphanumeric {
704    type Output = String;
705    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
706        let mut res = String::new();
707        while let Some(c) = s.peek() {
708            if c.is_alphanumeric() {
709                res.push(c);
710                s.next();
711            } else {
712                break;
713            }
714        }
715        if res.is_empty() {
716            anyhow::bail!("End of statement!")
717        }
718        Ok(res)
719    }
720}
721
722#[derive(Copy, Clone, Debug)]
723pub struct Number;
724impl Parse for Number {
725    type Output = String;
726    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
727        let mut res = String::new();
728        while let Some(c) = s.peek() {
729            if c.is_numeric() {
730                res.push(c);
731                s.next();
732            } else {
733                if res.is_empty() {
734                    anyhow::bail!("Expected number, found: {}", s.info())
735                }
736                break;
737            }
738        }
739        if res.is_empty() {
740            anyhow::bail!("End of statement!")
741        }
742        Ok(res)
743    }
744}
745
746#[derive(Copy, Clone, Debug)]
747pub struct SignedNumber;
748impl Parse for SignedNumber {
749    type Output = String;
750    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
751        let mut res = String::new();
752        let mut has_numerals = false;
753        let mut has_negative = false;
754        while let Some(c) = s.peek() {
755            if c.is_numeric() {
756                has_numerals = true;
757                res.push(c);
758                s.next();
759            } else if c == '-' {
760                if has_negative || !res.is_empty() {
761                    anyhow::bail!("Invalid number: Improper negative sign")
762                } else {
763                    has_negative = true;
764                    res.push(c);
765                    s.next();
766                }
767            } else {
768                if res.is_empty() {
769                    anyhow::bail!("Expected signed number, found: {}", s.info())
770                }
771                break;
772            }
773        }
774        if has_negative && !has_numerals {
775            anyhow::bail!("Invalid number: Negative sign without number")
776        }
777        if res.is_empty() {
778            anyhow::bail!("End of statement!")
779        }
780        Ok(res)
781    }
782}
783
784#[derive(Copy, Clone, Debug)]
785pub struct Float;
786impl Parse for Float {
787    type Output = String;
788    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
789        let mut res = String::new();
790        let mut has_numerals = false;
791        let mut has_dot = false;
792        let mut has_negative = false;
793        let mut has_e = false;
794        while let Some(c) = s.peek() {
795            if c.is_numeric() {
796                has_numerals = true;
797                res.push(c);
798                s.next();
799            } else if c == '-' {
800                if has_negative || !res.is_empty() {
801                    anyhow::bail!("Invalid float: Improper negative sign")
802                } else {
803                    has_negative = true;
804                    res.push(c);
805                    s.next();
806                }
807            } else if c == '.' {
808                if has_dot {
809                    anyhow::bail!("Invalid float: Too many decimal points")
810                } else {
811                    has_dot = true;
812                    res.push(c);
813                    s.next();
814                }
815            } else if c == 'e' || c == 'E' {
816                if has_e {
817                    anyhow::bail!("Invalid float: Too many scientific notations")
818                } else {
819                    if res.is_empty() {
820                        anyhow::bail!("Invalid float: Missing number before scientific notation")
821                    }
822                    res.push(c);
823                    s.next();
824                    has_e = true;
825                    if let Some(next) = s.next() {
826                        if next == '-' || next == '+' || next.is_numeric() {
827                            res.push(next);
828                        } else {
829                            anyhow::bail!("Invalid float: Invalid scientific notation")
830                        }
831                    } else {
832                        anyhow::bail!("Invalid float: Missing scientific notation value")
833                    }
834                }
835            } else {
836                if res.is_empty() {
837                    anyhow::bail!("Expected float, found: {}", s.info())
838                }
839                break;
840            }
841        }
842        if has_negative && !has_numerals {
843            anyhow::bail!("Invalid float: Negative sign without number")
844        }
845        if has_dot && !has_numerals {
846            anyhow::bail!("Invalid float: Decimal point without number")
847        }
848        if !has_dot {
849            anyhow::bail!("Invalid float: Missing decimal point")
850        }
851        if res.is_empty() {
852            anyhow::bail!("End of statement!")
853        }
854        Ok(res)
855    }
856}
857
858macro_rules! parse_peek_group {
859    ($g:ident, $l:ident, $r:ident) => {
860        #[derive(Clone, Debug)]
861        pub struct $g<T>(T);
862        impl<T: 'static + Parse> Parse for $g<T>
863        where
864            T::Output: 'static + Clone,
865        {
866            type Output = T::Output;
867            fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
868                s.parse_from::<$l>()?;
869                let res = s.parse_from::<T>()?;
870                s.parse_from::<$r>()?;
871                Ok(res)
872            }
873        }
874    };
875}
876
877parse_peek_group!(Parens, LeftParen, RightParen);
878parse_peek_group!(Brackets, LeftBracket, RightBracket);
879parse_peek_group!(Braces, LeftBrace, RightBrace);
880parse_peek_group!(Angles, LeftAngle, RightAngle);
881parse_peek_group!(SingleQuoted, SingleQuote, SingleQuote);
882parse_peek_group!(DoubleQuoted, DoubleQuote, DoubleQuote);
883
884#[derive(ParseFromStr, Clone, Debug, TryInto, PartialEq, Eq, Hash, Ord, PartialOrd, ToTokens)]
885pub enum BindMarker {
886    #[try_into(ignore)]
887    Anonymous,
888    Named(Name),
889}
890
891impl Parse for BindMarker {
892    type Output = Self;
893    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
894        Ok(if s.parse::<Option<Question>>()?.is_some() {
895            BindMarker::Anonymous
896        } else if let Some((_, id)) = s.parse::<Option<(Colon, Name)>>()? {
897            BindMarker::Named(id)
898        } else {
899            anyhow::bail!("Expected bind marker, found: {}", s.info())
900        })
901    }
902}
903
904impl Display for BindMarker {
905    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
906        match self {
907            BindMarker::Anonymous => write!(f, "?"),
908            BindMarker::Named(id) => write!(f, ":{}", id),
909        }
910    }
911}
912
913impl<T: Into<Name>> From<T> for BindMarker {
914    fn from(id: T) -> Self {
915        BindMarker::Named(id.into())
916    }
917}
918
919impl Parse for Uuid {
920    type Output = Self;
921    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
922        if let Some(u) = s.nextn(36) {
923            Ok(uuid::Uuid::parse_str(&u)?)
924        } else {
925            anyhow::bail!("Expected UUID, found {}", s.info())
926        }
927    }
928}
929
930impl<'a> CustomToTokens<'a> for Uuid {
931    fn to_tokens(&'a self, tokens: &mut TokenStream) {
932        let u = self.to_string();
933        tokens.extend(quote!(Uuid::parse_str(#u).unwrap()));
934    }
935}
936
937#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd, ToTokens)]
938pub enum LitStrKind {
939    Quoted,
940    Escaped,
941}
942
943#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd, ToTokens)]
944pub struct LitStr {
945    pub kind: LitStrKind,
946    pub value: String,
947}
948
949impl LitStr {
950    pub fn quoted(value: &str) -> Self {
951        Self {
952            kind: LitStrKind::Quoted,
953            value: value.to_string(),
954        }
955    }
956
957    pub fn escaped(value: &str) -> Self {
958        Self {
959            kind: LitStrKind::Escaped,
960            value: value.to_string(),
961        }
962    }
963}
964
965impl Parse for LitStr {
966    type Output = Self;
967    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
968        let mut res = String::new();
969        let mut kind = LitStrKind::Quoted;
970        if s.peek() == Some('\'') {
971            s.next();
972        } else if s.peekn(2).map(|s| s.as_str() == "$$").unwrap_or(false) {
973            kind = LitStrKind::Escaped;
974            s.nextn(2);
975        } else {
976            return Err(anyhow::anyhow!(
977                "Expected opening quote for LitStr, found: {}",
978                s.info()
979            ));
980        }
981        while let Some(c) = s.next() {
982            if kind == LitStrKind::Escaped && c == '$' && s.peek().map(|c| c == '$').unwrap_or(false) {
983                s.next();
984                return Ok(LitStr { kind, value: res });
985            } else if kind == LitStrKind::Quoted && c == '\'' {
986                return Ok(LitStr { kind, value: res });
987            } else {
988                res.push(c);
989            }
990        }
991        anyhow::bail!("End of statement!")
992    }
993}
994
995impl Display for LitStr {
996    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
997        match self.kind {
998            LitStrKind::Quoted => write!(f, "'{}'", self.value),
999            LitStrKind::Escaped => write!(f, "$${}$$", self.value),
1000        }
1001    }
1002}
1003
1004impl From<String> for LitStr {
1005    fn from(s: String) -> Self {
1006        if s.contains('\'') {
1007            LitStr {
1008                kind: LitStrKind::Escaped,
1009                value: s,
1010            }
1011        } else {
1012            LitStr {
1013                kind: LitStrKind::Quoted,
1014                value: s,
1015            }
1016        }
1017    }
1018}
1019
1020impl From<&str> for LitStr {
1021    fn from(s: &str) -> Self {
1022        s.to_string().into()
1023    }
1024}
1025
1026#[derive(ParseFromStr, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, ToTokens)]
1027pub enum Name {
1028    Quoted(String),
1029    Unquoted(String),
1030}
1031
1032impl Name {
1033    pub fn quoted(s: &str) -> Self {
1034        Name::Quoted(s.to_string())
1035    }
1036
1037    pub fn unquoted(s: &str) -> Self {
1038        Name::Unquoted(s.to_string())
1039    }
1040
1041    pub fn term(self, term: impl Into<Term>) -> SimpleSelection {
1042        SimpleSelection::Term(self, term.into())
1043    }
1044
1045    pub fn field(self, field: impl Into<Name>) -> SimpleSelection {
1046        SimpleSelection::Field(self, field.into())
1047    }
1048}
1049
1050impl Parse for Name {
1051    type Output = Self;
1052    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1053        let mut res = String::new();
1054        if s.peek().map(|c| c == '\"').unwrap_or(false) {
1055            s.next();
1056            while let Some(c) = s.next() {
1057                if c == '\"' {
1058                    return Ok(Self::Quoted(res));
1059                } else {
1060                    res.push(c);
1061                }
1062            }
1063            anyhow::bail!("End of statement!")
1064        } else {
1065            while let Some(c) = s.peek() {
1066                if c.is_alphanumeric() || c == '_' {
1067                    s.next();
1068                    res.push(c);
1069                } else {
1070                    break;
1071                }
1072            }
1073            if res.is_empty() {
1074                anyhow::bail!("End of statement!")
1075            } else if ReservedKeyword::from_str(&res).is_ok() {
1076                anyhow::bail!("Invalid name: {} is a reserved keyword", res)
1077            }
1078            return Ok(Self::Unquoted(res));
1079        }
1080    }
1081}
1082
1083impl Display for Name {
1084    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1085        match self {
1086            Self::Quoted(s) => write!(f, "\"{}\"", s),
1087            Self::Unquoted(s) => s.fmt(f),
1088        }
1089    }
1090}
1091
1092impl From<String> for Name {
1093    fn from(s: String) -> Self {
1094        if s.contains(char::is_whitespace) {
1095            Self::Quoted(s)
1096        } else {
1097            Self::Unquoted(s)
1098        }
1099    }
1100}
1101
1102impl From<&str> for Name {
1103    fn from(s: &str) -> Self {
1104        s.to_string().into()
1105    }
1106}
1107
1108pub trait KeyspaceQualifyExt {
1109    fn dot(self, other: impl Into<Name>) -> KeyspaceQualifiedName;
1110
1111    fn with_keyspace(self, keyspace: impl Into<Name>) -> KeyspaceQualifiedName;
1112}
1113
1114impl<N: Into<Name>> KeyspaceQualifyExt for N {
1115    fn dot(self, other: impl Into<Name>) -> KeyspaceQualifiedName {
1116        KeyspaceQualifiedName {
1117            keyspace: Some(self.into()),
1118            name: other.into(),
1119        }
1120    }
1121
1122    fn with_keyspace(self, keyspace: impl Into<Name>) -> KeyspaceQualifiedName {
1123        KeyspaceQualifiedName {
1124            keyspace: Some(keyspace.into()),
1125            name: self.into(),
1126        }
1127    }
1128}
1129
1130#[derive(ParseFromStr, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd, ToTokens)]
1131#[parse_via(TaggedKeyspaceQualifiedName)]
1132pub struct KeyspaceQualifiedName {
1133    pub keyspace: Option<Name>,
1134    pub name: Name,
1135}
1136
1137impl TryFrom<TaggedKeyspaceQualifiedName> for KeyspaceQualifiedName {
1138    type Error = anyhow::Error;
1139    fn try_from(t: TaggedKeyspaceQualifiedName) -> anyhow::Result<Self> {
1140        Ok(KeyspaceQualifiedName {
1141            keyspace: t.keyspace.map(|s| s.into_value()).transpose()?,
1142            name: t.name.into_value()?,
1143        })
1144    }
1145}
1146
1147#[derive(ParseFromStr, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd, ToTokens)]
1148#[tokenize_as(KeyspaceQualifiedName)]
1149pub struct TaggedKeyspaceQualifiedName {
1150    pub keyspace: Option<Tag<Name>>,
1151    pub name: Tag<Name>,
1152}
1153
1154impl Parse for TaggedKeyspaceQualifiedName {
1155    type Output = Self;
1156    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1157        let (keyspace, name) = s.parse::<(Option<(Tag<Name>, Dot)>, Tag<Name>)>()?;
1158        Ok(Self {
1159            keyspace: keyspace.map(|(i, _)| i),
1160            name,
1161        })
1162    }
1163}
1164
1165impl Display for KeyspaceQualifiedName {
1166    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1167        if let Some(keyspace) = &self.keyspace {
1168            write!(f, "{}.{}", keyspace, self.name)?;
1169        } else {
1170            self.name.fmt(f)?;
1171        }
1172        Ok(())
1173    }
1174}
1175
1176impl From<String> for KeyspaceQualifiedName {
1177    fn from(s: String) -> Self {
1178        Self {
1179            keyspace: None,
1180            name: s.into(),
1181        }
1182    }
1183}
1184
1185impl From<&str> for KeyspaceQualifiedName {
1186    fn from(s: &str) -> Self {
1187        Self {
1188            keyspace: None,
1189            name: s.into(),
1190        }
1191    }
1192}
1193
1194#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
1195#[parse_via(TaggedStatementOpt)]
1196pub struct StatementOpt {
1197    pub name: Name,
1198    pub value: StatementOptValue,
1199}
1200
1201impl StatementOpt {
1202    pub fn new<N: Into<Name>>(name: N, value: StatementOptValue) -> Self {
1203        Self {
1204            name: name.into(),
1205            value,
1206        }
1207    }
1208}
1209
1210impl TryFrom<TaggedStatementOpt> for StatementOpt {
1211    type Error = anyhow::Error;
1212    fn try_from(t: TaggedStatementOpt) -> anyhow::Result<Self> {
1213        Ok(Self {
1214            name: t.name,
1215            value: t.value.try_into()?,
1216        })
1217    }
1218}
1219
1220#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
1221#[tokenize_as(StatementOpt)]
1222pub struct TaggedStatementOpt {
1223    pub name: Name,
1224    pub value: TaggedStatementOptValue,
1225}
1226
1227impl Parse for TaggedStatementOpt {
1228    type Output = Self;
1229    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1230        let (name, _, value) = s.parse::<(Name, Equals, TaggedStatementOptValue)>()?;
1231        Ok(Self { name, value })
1232    }
1233}
1234
1235impl Display for StatementOpt {
1236    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1237        write!(f, "{} = {}", self.name, self.value)
1238    }
1239}
1240
1241#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq, From)]
1242#[parse_via(TaggedStatementOptValue)]
1243pub enum StatementOptValue {
1244    Identifier(Name),
1245    Constant(Constant),
1246    Map(MapLiteral),
1247}
1248
1249impl TryFrom<TaggedStatementOptValue> for StatementOptValue {
1250    type Error = anyhow::Error;
1251    fn try_from(t: TaggedStatementOptValue) -> anyhow::Result<Self> {
1252        Ok(match t {
1253            TaggedStatementOptValue::Identifier(i) => Self::Identifier(i.into_value()?),
1254            TaggedStatementOptValue::Constant(c) => Self::Constant(c.into_value()?),
1255            TaggedStatementOptValue::Map(m) => Self::Map(m.into_value()?.try_into()?),
1256        })
1257    }
1258}
1259
1260#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq, From)]
1261#[tokenize_as(StatementOptValue)]
1262pub enum TaggedStatementOptValue {
1263    Identifier(Tag<Name>),
1264    Constant(Tag<Constant>),
1265    Map(Tag<TaggedMapLiteral>),
1266}
1267
1268impl Parse for TaggedStatementOptValue {
1269    type Output = Self;
1270    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1271        if let Some(map) = s.parse::<Option<Tag<TaggedMapLiteral>>>()? {
1272            Ok(Self::Map(map))
1273        } else if let Some(constant) = s.parse::<Option<Tag<Constant>>>()? {
1274            Ok(Self::Constant(constant))
1275        } else if let Some(identifier) = s.parse::<Option<Tag<Name>>>()? {
1276            Ok(Self::Identifier(identifier))
1277        } else {
1278            anyhow::bail!("Expected statement option value, found {}", s.info())
1279        }
1280    }
1281}
1282
1283impl Display for StatementOptValue {
1284    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1285        match self {
1286            Self::Identifier(identifier) => identifier.fmt(f),
1287            Self::Constant(constant) => constant.fmt(f),
1288            Self::Map(map) => map.fmt(f),
1289        }
1290    }
1291}
1292
1293impl Display for TaggedStatementOptValue {
1294    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1295        match self {
1296            Self::Identifier(identifier) => identifier.fmt(f),
1297            Self::Constant(constant) => constant.fmt(f),
1298            Self::Map(map) => map.fmt(f),
1299        }
1300    }
1301}
1302
1303#[derive(Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
1304pub struct ColumnDefinition {
1305    #[builder(setter(into))]
1306    pub name: Name,
1307    #[builder(setter(into))]
1308    pub data_type: CqlType,
1309    #[builder(default)]
1310    pub static_column: bool,
1311    #[builder(default)]
1312    pub primary_key: bool,
1313}
1314
1315impl ColumnDefinition {
1316    pub fn build() -> ColumnDefinitionBuilder {
1317        ColumnDefinitionBuilder::default()
1318    }
1319}
1320
1321impl Parse for ColumnDefinition {
1322    type Output = Self;
1323    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1324        Ok(Self {
1325            name: s.parse()?,
1326            data_type: s.parse()?,
1327            static_column: s.parse::<Option<STATIC>>()?.is_some(),
1328            primary_key: s.parse::<Option<(PRIMARY, KEY)>>()?.is_some(),
1329        })
1330    }
1331}
1332
1333impl Display for ColumnDefinition {
1334    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1335        write!(f, "{} {}", self.name, self.data_type)?;
1336        if self.static_column {
1337            write!(f, " STATIC")?;
1338        }
1339        if self.primary_key {
1340            write!(f, " PRIMARY KEY")?;
1341        }
1342        Ok(())
1343    }
1344}
1345
1346impl<T: Into<Name>> From<(T, NativeType)> for ColumnDefinition {
1347    fn from((name, data_type): (T, NativeType)) -> Self {
1348        Self {
1349            name: name.into(),
1350            data_type: CqlType::Native(data_type),
1351            static_column: false,
1352            primary_key: false,
1353        }
1354    }
1355}
1356
1357#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
1358pub struct PrimaryKey {
1359    pub partition_key: PartitionKey,
1360    pub clustering_columns: Option<Vec<Name>>,
1361}
1362
1363impl PrimaryKey {
1364    pub fn partition_key(partition_key: impl Into<PartitionKey>) -> Self {
1365        PrimaryKey {
1366            partition_key: partition_key.into(),
1367            clustering_columns: None,
1368        }
1369    }
1370
1371    pub fn clustering_columns(self, clustering_columns: Vec<impl Into<Name>>) -> Self {
1372        PrimaryKey {
1373            partition_key: self.partition_key,
1374            clustering_columns: if clustering_columns.is_empty() {
1375                self.clustering_columns
1376            } else {
1377                Some(clustering_columns.into_iter().map(Into::into).collect())
1378            },
1379        }
1380    }
1381}
1382
1383impl Parse for PrimaryKey {
1384    type Output = Self;
1385    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1386        let (partition_key, clustering_columns) =
1387            s.parse_from::<(PartitionKey, Option<(Comma, List<Name, Comma>)>)>()?;
1388        Ok(PrimaryKey {
1389            partition_key,
1390            clustering_columns: clustering_columns.map(|i| i.1),
1391        })
1392    }
1393}
1394
1395impl Display for PrimaryKey {
1396    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1397        self.partition_key.fmt(f)?;
1398        if let Some(clustering_columns) = &self.clustering_columns {
1399            if !clustering_columns.is_empty() {
1400                write!(
1401                    f,
1402                    ", {}",
1403                    clustering_columns
1404                        .iter()
1405                        .map(|i| i.to_string())
1406                        .collect::<Vec<_>>()
1407                        .join(", ")
1408                )?;
1409            }
1410        }
1411        Ok(())
1412    }
1413}
1414
1415impl<N: Into<Name>> From<Vec<N>> for PrimaryKey {
1416    fn from(names: Vec<N>) -> Self {
1417        let mut names = names.into_iter().map(Into::into);
1418        let partition_key = names.next().unwrap().into();
1419        PrimaryKey {
1420            partition_key,
1421            clustering_columns: Some(names.collect()),
1422        }
1423    }
1424}
1425
1426#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
1427pub struct PartitionKey {
1428    pub columns: Vec<Name>,
1429}
1430
1431impl Parse for PartitionKey {
1432    type Output = Self;
1433    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1434        Ok(
1435            if let Some(columns) = s.parse_from::<Option<Parens<List<Name, Comma>>>>()? {
1436                Self { columns }
1437            } else {
1438                Self {
1439                    columns: vec![s.parse::<Name>()?],
1440                }
1441            },
1442        )
1443    }
1444}
1445
1446impl Display for PartitionKey {
1447    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1448        match self.columns.len() {
1449            0 => {
1450                panic!("No partition key columns specified!");
1451            }
1452            1 => self.columns[0].fmt(f),
1453            _ => write!(
1454                f,
1455                "({})",
1456                self.columns
1457                    .iter()
1458                    .map(|i| i.to_string())
1459                    .collect::<Vec<_>>()
1460                    .join(", ")
1461            ),
1462        }
1463    }
1464}
1465
1466impl<N: Into<Name>> From<Vec<N>> for PartitionKey {
1467    fn from(columns: Vec<N>) -> Self {
1468        Self {
1469            columns: columns.into_iter().map(Into::into).collect(),
1470        }
1471    }
1472}
1473
1474impl<N: Into<Name>> From<N> for PartitionKey {
1475    fn from(column: N) -> Self {
1476        Self {
1477            columns: vec![column.into()],
1478        }
1479    }
1480}
1481
1482// TODO: Scylla encryption opts and caching?
1483#[derive(Builder, Clone, Debug, Default, ToTokens, PartialEq)]
1484#[builder(setter(strip_option), default, build_fn(validate = "Self::validate"))]
1485pub struct TableOpts {
1486    pub compact_storage: bool,
1487    pub clustering_order: Option<Vec<ColumnOrder>>,
1488    #[builder(setter(into))]
1489    pub comment: Option<LitStr>,
1490    pub speculative_retry: Option<SpeculativeRetry>,
1491    pub change_data_capture: Option<bool>,
1492    pub gc_grace_seconds: Option<i32>,
1493    pub bloom_filter_fp_chance: Option<f32>,
1494    pub default_time_to_live: Option<i32>,
1495    pub compaction: Option<Compaction>,
1496    pub compression: Option<Compression>,
1497    pub caching: Option<Caching>,
1498    pub memtable_flush_period_in_ms: Option<i32>,
1499    pub read_repair: Option<bool>,
1500}
1501
1502impl Parse for TableOpts {
1503    type Output = Self;
1504    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1505        let mut res = TableOptsBuilder::default();
1506        loop {
1507            if s.parse::<Option<(COMPACT, STORAGE)>>()?.is_some() {
1508                if res.compact_storage.is_some() {
1509                    anyhow::bail!("Duplicate compact storage option");
1510                }
1511                res.compact_storage(true);
1512                if s.parse::<Option<AND>>()?.is_none() {
1513                    break;
1514                }
1515            } else if s.parse::<Option<(CLUSTERING, ORDER, BY)>>()?.is_some() {
1516                if res.clustering_order.is_some() {
1517                    anyhow::bail!("Duplicate clustering order option");
1518                }
1519                res.clustering_order(s.parse_from::<Parens<List<ColumnOrder, Comma>>>()?);
1520                if s.parse::<Option<AND>>()?.is_none() {
1521                    break;
1522                }
1523            } else {
1524                if let Some(v) = s.parse_from::<Option<List<StatementOpt, AND>>>()? {
1525                    for StatementOpt { name, value } in v {
1526                        let (Name::Quoted(n) | Name::Unquoted(n)) = &name;
1527                        match n.as_str() {
1528                            "comment" => {
1529                                if res.comment.is_some() {
1530                                    anyhow::bail!("Duplicate comment option");
1531                                } else if let StatementOptValue::Constant(Constant::String(s)) = value {
1532                                    res.comment(s);
1533                                } else {
1534                                    anyhow::bail!("Invalid comment value: {}", value);
1535                                }
1536                            }
1537                            "speculative_retry" => {
1538                                if res.speculative_retry.is_some() {
1539                                    anyhow::bail!("Duplicate speculative retry option");
1540                                } else if let StatementOptValue::Constant(Constant::String(s)) = value {
1541                                    res.speculative_retry(s.to_string().parse()?);
1542                                } else {
1543                                    anyhow::bail!("Invalid speculative retry value: {}", value);
1544                                }
1545                            }
1546                            "cdc" => {
1547                                if res.change_data_capture.is_some() {
1548                                    anyhow::bail!("Duplicate change data capture option");
1549                                } else if let StatementOptValue::Constant(Constant::Boolean(b)) = value {
1550                                    res.change_data_capture(b);
1551                                } else {
1552                                    anyhow::bail!("Invalid change data capture value: {}", value);
1553                                }
1554                            }
1555                            "gc_grace_seconds" => {
1556                                if res.gc_grace_seconds.is_some() {
1557                                    anyhow::bail!("Duplicate gc_grace_seconds option");
1558                                } else if let StatementOptValue::Constant(Constant::Integer(i)) = value {
1559                                    res.gc_grace_seconds(i.parse()?);
1560                                } else {
1561                                    anyhow::bail!("Invalid gc_grace_seconds value: {}", value);
1562                                }
1563                            }
1564                            "bloom_filter_fp_chance" => {
1565                                if res.bloom_filter_fp_chance.is_some() {
1566                                    anyhow::bail!("Duplicate bloom_filter_fp_chance option");
1567                                } else if let StatementOptValue::Constant(Constant::Float(f)) = value {
1568                                    res.bloom_filter_fp_chance(f.parse()?);
1569                                } else {
1570                                    anyhow::bail!("Invalid bloom_filter_fp_chance value: {}", value);
1571                                }
1572                            }
1573                            "default_time_to_live" => {
1574                                if res.default_time_to_live.is_some() {
1575                                    anyhow::bail!("Duplicate default_time_to_live option");
1576                                } else if let StatementOptValue::Constant(Constant::Integer(i)) = value {
1577                                    res.default_time_to_live(i.parse()?);
1578                                } else {
1579                                    anyhow::bail!("Invalid default_time_to_live value: {}", value);
1580                                }
1581                            }
1582                            "compaction" => {
1583                                if res.compaction.is_some() {
1584                                    anyhow::bail!("Duplicate compaction option");
1585                                } else if let StatementOptValue::Map(m) = value {
1586                                    res.compaction(m.try_into()?);
1587                                } else {
1588                                    anyhow::bail!("Invalid compaction value: {}", value);
1589                                }
1590                            }
1591                            "compression" => {
1592                                if res.compression.is_some() {
1593                                    anyhow::bail!("Duplicate compression option");
1594                                } else if let StatementOptValue::Map(m) = value {
1595                                    res.compression(m.try_into()?);
1596                                } else {
1597                                    anyhow::bail!("Invalid compression value: {}", value);
1598                                }
1599                            }
1600                            "caching" => {
1601                                if res.caching.is_some() {
1602                                    anyhow::bail!("Duplicate caching option");
1603                                } else if let StatementOptValue::Map(m) = value {
1604                                    res.caching(m.try_into()?);
1605                                } else {
1606                                    anyhow::bail!("Invalid caching value: {}", value);
1607                                }
1608                            }
1609                            "memtable_flush_period_in_ms" => {
1610                                if res.memtable_flush_period_in_ms.is_some() {
1611                                    anyhow::bail!("Duplicate memtable_flush_period_in_ms option");
1612                                } else if let StatementOptValue::Constant(Constant::Integer(i)) = value {
1613                                    res.memtable_flush_period_in_ms(i.parse()?);
1614                                } else {
1615                                    anyhow::bail!("Invalid memtable_flush_period_in_ms value: {}", value);
1616                                }
1617                            }
1618                            "read_repair" => {
1619                                if res.read_repair.is_some() {
1620                                    anyhow::bail!("Duplicate read_repair option");
1621                                } else if let StatementOptValue::Constant(Constant::String(s)) = value {
1622                                    res.read_repair(match s.value.to_uppercase().as_str() {
1623                                        "BLOCKING" => true,
1624                                        "NONE" => false,
1625                                        _ => anyhow::bail!("Invalid read_repair value: {}", s),
1626                                    });
1627                                } else {
1628                                    anyhow::bail!("Invalid read_repair value: {}", value);
1629                                }
1630                            }
1631                            _ => anyhow::bail!("Invalid table option: {}", name),
1632                        }
1633                    }
1634                }
1635                break;
1636            }
1637        }
1638        Ok(res
1639            .build()
1640            .map_err(|e| anyhow::anyhow!("Invalid Table Options: {}", e))?)
1641    }
1642}
1643
1644impl Display for TableOpts {
1645    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1646        let mut res = Vec::new();
1647        if self.compact_storage {
1648            res.push("COMPACT STORAGE".to_string());
1649        }
1650        if let Some(ref c) = self.clustering_order {
1651            res.push(format!(
1652                "CLUSTERING ORDER BY ({})",
1653                c.iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
1654            ));
1655        }
1656        if let Some(ref c) = self.comment {
1657            res.push(format!("comment = {}", c));
1658        }
1659        if let Some(ref c) = self.speculative_retry {
1660            res.push(format!("speculative_retry = {}", c));
1661        }
1662        if let Some(c) = self.change_data_capture {
1663            res.push(format!("cdc = {}", c));
1664        }
1665        if let Some(c) = self.gc_grace_seconds {
1666            res.push(format!("gc_grace_seconds = {}", c));
1667        }
1668        if let Some(c) = self.bloom_filter_fp_chance {
1669            res.push(format!("bloom_filter_fp_chance = {}", format_cql_f32(c)));
1670        }
1671        if let Some(c) = self.default_time_to_live {
1672            res.push(format!("default_time_to_live = {}", c));
1673        }
1674        if let Some(ref c) = self.compaction {
1675            res.push(format!("compaction = {}", c));
1676        }
1677        if let Some(ref c) = self.compression {
1678            res.push(format!("compression = {}", c));
1679        }
1680        if let Some(ref c) = self.caching {
1681            res.push(format!("caching = {}", c));
1682        }
1683        if let Some(c) = self.memtable_flush_period_in_ms {
1684            res.push(format!("memtable_flush_period_in_ms = {}", c));
1685        }
1686        if let Some(c) = self.read_repair {
1687            res.push(
1688                match c {
1689                    true => "read_repair = 'BLOCKING'",
1690                    false => "read_repair = 'NONE'",
1691                }
1692                .to_string(),
1693            );
1694        }
1695        write!(f, "{}", res.join(" AND "))
1696    }
1697}
1698
1699impl TableOptsBuilder {
1700    fn validate(&self) -> Result<(), String> {
1701        if self.compact_storage.is_some()
1702            || self.clustering_order.as_ref().map(|v| v.is_some()).unwrap_or_default()
1703            || self.comment.as_ref().map(|v| v.is_some()).unwrap_or_default()
1704            || self.speculative_retry.as_ref().map(|v| v.is_some()).unwrap_or_default()
1705            || self
1706                .change_data_capture
1707                .as_ref()
1708                .map(|v| v.is_some())
1709                .unwrap_or_default()
1710            || self.gc_grace_seconds.as_ref().map(|v| v.is_some()).unwrap_or_default()
1711            || self
1712                .bloom_filter_fp_chance
1713                .as_ref()
1714                .map(|v| v.is_some())
1715                .unwrap_or_default()
1716            || self
1717                .default_time_to_live
1718                .as_ref()
1719                .map(|v| v.is_some())
1720                .unwrap_or_default()
1721            || self.compaction.as_ref().map(|v| v.is_some()).unwrap_or_default()
1722            || self.compression.as_ref().map(|v| v.is_some()).unwrap_or_default()
1723            || self.caching.as_ref().map(|v| v.is_some()).unwrap_or_default()
1724            || self
1725                .memtable_flush_period_in_ms
1726                .as_ref()
1727                .map(|v| v.is_some())
1728                .unwrap_or_default()
1729            || self.read_repair.as_ref().map(|v| v.is_some()).unwrap_or_default()
1730        {
1731            Ok(())
1732        } else {
1733            Err("No table options specified".to_string())
1734        }
1735    }
1736}
1737
1738#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
1739pub struct ColumnOrder {
1740    pub column: Name,
1741    pub order: Order,
1742}
1743
1744impl Parse for ColumnOrder {
1745    type Output = Self;
1746    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
1747        let (column, order) = s.parse::<(Name, Order)>()?;
1748        Ok(ColumnOrder { column, order })
1749    }
1750}
1751
1752impl Display for ColumnOrder {
1753    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1754        write!(f, "{} {}", self.column, self.order)
1755    }
1756}
1757
1758impl<T: Into<Name>> From<(T, Order)> for ColumnOrder {
1759    fn from((t, order): (T, Order)) -> Self {
1760        ColumnOrder {
1761            column: t.into(),
1762            order,
1763        }
1764    }
1765}
1766
1767#[derive(Copy, Clone, Debug, ToTokens, PartialEq, Eq)]
1768pub enum Order {
1769    Ascending,
1770    Descending,
1771}
1772
1773impl Parse for Order {
1774    type Output = Self;
1775    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
1776        if s.parse::<Option<ASC>>()?.is_some() {
1777            Ok(Order::Ascending)
1778        } else if s.parse::<Option<DESC>>()?.is_some() {
1779            Ok(Order::Descending)
1780        } else {
1781            anyhow::bail!("Expected sort order (ASC/DESC), found {}", s.info())
1782        }
1783    }
1784}
1785
1786impl Default for Order {
1787    fn default() -> Self {
1788        Self::Ascending
1789    }
1790}
1791
1792impl Display for Order {
1793    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1794        match self {
1795            Self::Ascending => write!(f, "ASC"),
1796            Self::Descending => write!(f, "DESC"),
1797        }
1798    }
1799}
1800
1801#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
1802pub enum Relation {
1803    Normal {
1804        column: Name,
1805        operator: Operator,
1806        term: Term,
1807    },
1808    Tuple {
1809        columns: Vec<Name>,
1810        operator: Operator,
1811        tuple_literal: TupleLiteral,
1812    },
1813    Token {
1814        columns: Vec<Name>,
1815        operator: Operator,
1816        term: Term,
1817    },
1818    MVExclusion {
1819        column: Name,
1820    },
1821}
1822
1823impl Relation {
1824    pub fn normal(column: impl Into<Name>, operator: Operator, term: impl Into<Term>) -> Self {
1825        Self::Normal {
1826            column: column.into(),
1827            operator,
1828            term: term.into(),
1829        }
1830    }
1831
1832    pub fn tuple(columns: Vec<impl Into<Name>>, operator: Operator, tuple_literal: Vec<impl Into<Term>>) -> Self {
1833        Self::Tuple {
1834            columns: columns.into_iter().map(Into::into).collect(),
1835            operator,
1836            tuple_literal: tuple_literal.into_iter().map(Into::into).collect::<Vec<_>>().into(),
1837        }
1838    }
1839
1840    pub fn token(columns: Vec<impl Into<Name>>, operator: Operator, term: impl Into<Term>) -> Self {
1841        Self::Token {
1842            columns: columns.into_iter().map(Into::into).collect(),
1843            operator,
1844            term: term.into(),
1845        }
1846    }
1847
1848    pub fn is_not_null(column: impl Into<Name>) -> Self {
1849        Self::MVExclusion { column: column.into() }
1850    }
1851}
1852
1853impl Parse for Relation {
1854    type Output = Self;
1855    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self> {
1856        Ok(
1857            if let Some((column, _, _, _)) = s.parse::<Option<(Name, IS, NOT, NULL)>>()? {
1858                Relation::MVExclusion { column }
1859            } else if s.parse::<Option<TOKEN>>()?.is_some() {
1860                let (columns, operator, term) = s.parse_from::<(Parens<List<Name, Comma>>, Operator, Term)>()?;
1861                Relation::Token {
1862                    columns,
1863                    operator,
1864                    term,
1865                }
1866            } else if s.check::<LeftParen>() {
1867                let (columns, operator, tuple_literal) =
1868                    s.parse_from::<(Parens<List<Name, Comma>>, Operator, TupleLiteral)>()?;
1869                Relation::Tuple {
1870                    columns,
1871                    operator,
1872                    tuple_literal,
1873                }
1874            } else if let Some((column, operator, term)) = s.parse::<Option<(Name, Operator, Term)>>()? {
1875                Relation::Normal { column, operator, term }
1876            } else {
1877                anyhow::bail!("Expected relation, found {}", s.info())
1878            },
1879        )
1880    }
1881}
1882
1883impl Display for Relation {
1884    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1885        match self {
1886            Relation::Normal { column, operator, term } => write!(f, "{} {} {}", column, operator, term),
1887            Relation::Tuple {
1888                columns,
1889                operator,
1890                tuple_literal,
1891            } => write!(
1892                f,
1893                "({}) {} {}",
1894                columns.iter().map(|c| c.to_string()).collect::<Vec<_>>().join(", "),
1895                operator,
1896                tuple_literal
1897            ),
1898            Relation::Token {
1899                columns,
1900                operator,
1901                term,
1902            } => write!(
1903                f,
1904                "TOKEN ({}) {} {}",
1905                columns.iter().map(|c| c.to_string()).collect::<Vec<_>>().join(", "),
1906                operator,
1907                term
1908            ),
1909            Relation::MVExclusion { column } => write!(f, "{} IS NOT NULL", column),
1910        }
1911    }
1912}
1913
1914#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
1915#[parse_via(TaggedReplication)]
1916pub struct Replication {
1917    pub class: LitStr,
1918    pub replication_factor: Option<i32>,
1919    pub datacenters: BTreeMap<LitStr, i32>,
1920}
1921
1922impl Replication {
1923    pub fn simple(replication_factor: i32) -> Self {
1924        Self {
1925            class: "SimpleStrategy".into(),
1926            replication_factor: Some(replication_factor),
1927            datacenters: BTreeMap::new(),
1928        }
1929    }
1930
1931    pub fn network_topology<S: Into<String>>(replication_map: BTreeMap<S, i32>) -> Self {
1932        let mut map: BTreeMap<String, _> = replication_map.into_iter().map(|(k, v)| (k.into(), v)).collect();
1933        Self {
1934            class: "NetworkTopologyStrategy".into(),
1935            replication_factor: map.remove("replication_factor"),
1936            datacenters: map.into_iter().map(|(dc, rf)| (dc.into(), rf)).collect(),
1937        }
1938    }
1939}
1940
1941impl From<i32> for Replication {
1942    fn from(replication_factor: i32) -> Self {
1943        Self::simple(replication_factor)
1944    }
1945}
1946
1947impl Default for Replication {
1948    fn default() -> Self {
1949        Self::simple(1)
1950    }
1951}
1952
1953impl Display for Replication {
1954    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1955        let mut opts = vec![("'class'".to_string(), self.class.to_string())];
1956        if let Some(replication_factor) = self.replication_factor {
1957            opts.push(("'replication_factor'".to_string(), format!("{}", replication_factor)));
1958        }
1959        for (dc, rf) in self.datacenters.iter() {
1960            opts.push((dc.to_string(), format!("{}", rf)));
1961        }
1962        write!(
1963            f,
1964            "{{{}}}",
1965            opts.iter()
1966                .map(|(k, v)| format!("{}: {}", k, v))
1967                .collect::<Vec<_>>()
1968                .join(", ")
1969        )
1970    }
1971}
1972
1973impl TryFrom<TaggedReplication> for Replication {
1974    type Error = anyhow::Error;
1975    fn try_from(value: TaggedReplication) -> Result<Self, Self::Error> {
1976        let mut datacenters = BTreeMap::new();
1977        for (k, v) in value.datacenters {
1978            if datacenters.insert(k.into_value()?, v.into_value()?).is_some() {
1979                anyhow::bail!("Duplicate key in replication map");
1980            }
1981        }
1982        Ok(Self {
1983            class: value.class.into_value()?,
1984            replication_factor: value.replication_factor.map(|v| v.into_value()).transpose()?,
1985            datacenters,
1986        })
1987    }
1988}
1989
1990#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq, Eq)]
1991#[tokenize_as(Replication)]
1992pub struct TaggedReplication {
1993    pub class: Tag<LitStr>,
1994    pub replication_factor: Option<Tag<i32>>,
1995    pub datacenters: BTreeMap<Tag<LitStr>, Tag<i32>>,
1996}
1997
1998impl Default for TaggedReplication {
1999    fn default() -> Self {
2000        Self {
2001            class: Tag::Value("SimpleStrategy".into()),
2002            replication_factor: Some(Tag::Value(1)),
2003            datacenters: BTreeMap::new(),
2004        }
2005    }
2006}
2007
2008impl TryFrom<TaggedMapLiteral> for TaggedReplication {
2009    type Error = anyhow::Error;
2010    fn try_from(value: TaggedMapLiteral) -> Result<Self, Self::Error> {
2011        let mut class = None;
2012        let v = value
2013            .elements
2014            .into_iter()
2015            .filter(|(k, v)| {
2016                if let Tag::Value(Term::Constant(Constant::String(s))) = k {
2017                    if s.value.to_lowercase().as_str() == "class" {
2018                        class = Some(v.clone());
2019                        return false;
2020                    }
2021                }
2022                true
2023            })
2024            .collect::<Vec<_>>();
2025        let class = match class.ok_or_else(|| anyhow::anyhow!("No class in replication map literal!"))? {
2026            Tag::Value(Term::Constant(Constant::String(s))) => Tag::Value(s),
2027            Tag::Tag(t) => Tag::Tag(t),
2028            c @ _ => anyhow::bail!("Invalid class: {:?}", c),
2029        };
2030        let mut replication_factor = None;
2031        let mut datacenters = BTreeMap::new();
2032        match class {
2033            Tag::Tag(_) => (),
2034            Tag::Value(ref class) => {
2035                if class.value.ends_with("SimpleStrategy") {
2036                    if v.len() > 1 {
2037                        anyhow::bail!(
2038                            "SimpleStrategy map literal should only contain a single 'replication_factor' key!"
2039                        )
2040                    } else if v.is_empty() {
2041                        anyhow::bail!("SimpleStrategy map literal should contain a 'replication_factor' key!")
2042                    }
2043                    let (k, v) = v.into_iter().next().unwrap();
2044                    if let Tag::Value(Term::Constant(Constant::String(s))) = k {
2045                        if s.value.to_lowercase().as_str() == "replication_factor" {
2046                            match v {
2047                                Tag::Value(Term::Constant(Constant::Integer(i))) => {
2048                                    replication_factor = Some(Tag::Value(i.parse()?));
2049                                }
2050                                Tag::Tag(t) => replication_factor = Some(Tag::Tag(t)),
2051                                _ => anyhow::bail!("Invalid replication factor value: {}", v),
2052                            }
2053                        } else {
2054                            anyhow::bail!("SimpleStrategy map literal should only contain a 'class' and 'replication_factor' key!")
2055                        }
2056                    } else {
2057                        anyhow::bail!("Invalid key: {}", k)
2058                    }
2059                } else {
2060                    for (k, v) in v {
2061                        if let Tag::Value(Term::Constant(Constant::String(ref s))) = k {
2062                            if s.value.to_lowercase().as_str() == "replication_factor" {
2063                                match v {
2064                                    Tag::Value(Term::Constant(Constant::Integer(i))) => {
2065                                        replication_factor = Some(Tag::Value(i.parse()?));
2066                                    }
2067                                    Tag::Tag(t) => replication_factor = Some(Tag::Tag(t)),
2068                                    _ => anyhow::bail!("Invalid replication factor value: {}", v),
2069                                }
2070                                continue;
2071                            }
2072                        }
2073                        datacenters.insert(
2074                            match k {
2075                                Tag::Tag(t) => Tag::Tag(t),
2076                                Tag::Value(Term::Constant(Constant::String(s))) => Tag::Value(s),
2077                                _ => anyhow::bail!("Invalid key in replication map literal!"),
2078                            },
2079                            match v {
2080                                Tag::Tag(t) => Tag::Tag(t),
2081                                Tag::Value(Term::Constant(Constant::Integer(i))) => Tag::Value(i.parse()?),
2082                                _ => anyhow::bail!("Invalid replication factor value: {}", v),
2083                            },
2084                        );
2085                    }
2086                }
2087            }
2088        }
2089        Ok(Self {
2090            class,
2091            replication_factor,
2092            datacenters,
2093        })
2094    }
2095}
2096
2097impl Parse for TaggedReplication {
2098    type Output = Self;
2099    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
2100        s.parse::<TaggedMapLiteral>()?.try_into()
2101    }
2102}
2103
2104#[derive(ParseFromStr, Clone, Debug, ToTokens, PartialEq)]
2105pub enum SpeculativeRetry {
2106    None,
2107    Always,
2108    Percentile(f32),
2109    Custom(LitStr),
2110}
2111
2112impl SpeculativeRetry {
2113    pub fn custom<S: Into<LitStr>>(s: S) -> Self {
2114        SpeculativeRetry::Custom(s.into())
2115    }
2116}
2117
2118impl Default for SpeculativeRetry {
2119    fn default() -> Self {
2120        SpeculativeRetry::Percentile(99.0)
2121    }
2122}
2123
2124impl Parse for SpeculativeRetry {
2125    type Output = Self;
2126    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
2127        let token = s.parse::<LitStr>()?;
2128        Ok(match token.value.to_uppercase().as_str() {
2129            "NONE" => SpeculativeRetry::None,
2130            "ALWAYS" => SpeculativeRetry::Always,
2131            _ => {
2132                if let Ok(res) = StatementStream::new(&token.value).parse_from::<(Float, PERCENTILE)>() {
2133                    SpeculativeRetry::Percentile(res.0.parse()?)
2134                } else if let Ok(res) = StatementStream::new(&token.value).parse_from::<(Number, PERCENTILE)>() {
2135                    SpeculativeRetry::Percentile(res.0.parse()?)
2136                } else {
2137                    SpeculativeRetry::Custom(token)
2138                }
2139            }
2140        })
2141    }
2142}
2143
2144impl Display for SpeculativeRetry {
2145    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2146        match self {
2147            SpeculativeRetry::None => write!(f, "'NONE'"),
2148            SpeculativeRetry::Always => write!(f, "'ALWAYS'"),
2149            SpeculativeRetry::Percentile(p) => write!(f, "'{}PERCENTILE'", format_cql_f32(*p)),
2150            SpeculativeRetry::Custom(s) => s.fmt(f),
2151        }
2152    }
2153}
2154
2155#[derive(Builder, Copy, Clone, Debug, Default, ToTokens, PartialEq)]
2156#[builder(setter(strip_option), default, build_fn(validate = "Self::validate"))]
2157pub struct SizeTieredCompactionStrategy {
2158    enabled: Option<bool>,
2159    tombstone_threshold: Option<f32>,
2160    tombstone_compaction_interval: Option<i32>,
2161    log_all: Option<bool>,
2162    unchecked_tombstone_compaction: Option<bool>,
2163    only_purge_repaired_tombstone: Option<bool>,
2164    min_threshold: Option<i32>,
2165    max_threshold: Option<i32>,
2166    min_sstable_size: Option<i32>,
2167    bucket_low: Option<f32>,
2168    bucket_high: Option<f32>,
2169}
2170
2171impl SizeTieredCompactionStrategyBuilder {
2172    fn validate(&self) -> Result<(), String> {
2173        if let Some(v) = self.tombstone_threshold.flatten() {
2174            if v < 0.0 || v > 1.0 {
2175                return Err(format!("tombstone_threshold must be between 0.0 and 1.0, found {}", v));
2176            }
2177        }
2178        if let Some(v) = self.tombstone_compaction_interval.flatten() {
2179            if v < 0 {
2180                return Err(format!(
2181                    "tombstone_compaction_interval must be a positive integer, found {}",
2182                    v
2183                ));
2184            }
2185        }
2186        if let Some(v) = self.min_sstable_size.flatten() {
2187            if v < 0 {
2188                return Err(format!("min_sstable_size must be a positive integer, found {}", v));
2189            }
2190        }
2191        if let Some(v) = self.bucket_high.flatten() {
2192            if v < 0.0 {
2193                return Err(format!("bucket_high must be a positive float, found {}", v));
2194            }
2195        }
2196        if let Some(v) = self.bucket_low.flatten() {
2197            if v < 0.0 {
2198                return Err(format!("bucket_low must be a positive float, found {}", v));
2199            }
2200        }
2201        if let Some(v) = self.min_threshold.flatten() {
2202            if v < 0 {
2203                return Err(format!("min_threshold must be a positive integer, found {}", v));
2204            }
2205        }
2206        if let Some(v) = self.max_threshold.flatten() {
2207            if v < 0 {
2208                return Err(format!("max_threshold must be a positive integer, found {}", v));
2209            }
2210        }
2211        Ok(())
2212    }
2213}
2214
2215impl CompactionType for SizeTieredCompactionStrategy {}
2216
2217impl Display for SizeTieredCompactionStrategy {
2218    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2219        let mut res = vec![format!("'class': 'SizeTieredCompactionStrategy'")];
2220        if let Some(enabled) = self.enabled {
2221            res.push(format!("'enabled': {}", enabled));
2222        }
2223        if let Some(tombstone_threshold) = self.tombstone_threshold {
2224            res.push(format!(
2225                "'tombstone_threshold': {}",
2226                format_cql_f32(tombstone_threshold)
2227            ));
2228        }
2229        if let Some(tombstone_compaction_interval) = self.tombstone_compaction_interval {
2230            res.push(format!(
2231                "'tombstone_compaction_interval': {}",
2232                tombstone_compaction_interval
2233            ));
2234        }
2235        if let Some(log_all) = self.log_all {
2236            res.push(format!("'log_all': {}", log_all));
2237        }
2238        if let Some(unchecked_tombstone_compaction) = self.unchecked_tombstone_compaction {
2239            res.push(format!(
2240                "'unchecked_tombstone_compaction': {}",
2241                unchecked_tombstone_compaction
2242            ));
2243        }
2244        if let Some(only_purge_repaired_tombstone) = self.only_purge_repaired_tombstone {
2245            res.push(format!(
2246                "'only_purge_repaired_tombstone': {}",
2247                only_purge_repaired_tombstone
2248            ));
2249        }
2250        if let Some(min_threshold) = self.min_threshold {
2251            res.push(format!("'min_threshold': {}", min_threshold));
2252        }
2253        if let Some(max_threshold) = self.max_threshold {
2254            res.push(format!("'max_threshold': {}", max_threshold));
2255        }
2256        if let Some(min_sstable_size) = self.min_sstable_size {
2257            res.push(format!("'min_sstable_size': {}", min_sstable_size));
2258        }
2259        if let Some(bucket_low) = self.bucket_low {
2260            res.push(format!("'bucket_low': {}", format_cql_f32(bucket_low)));
2261        }
2262        if let Some(bucket_high) = self.bucket_high {
2263            res.push(format!("'bucket_high': {}", format_cql_f32(bucket_high)));
2264        }
2265        write!(f, "{{{}}}", res.join(", "))
2266    }
2267}
2268
2269#[derive(Builder, Copy, Clone, Debug, Default, ToTokens, PartialEq)]
2270#[builder(setter(strip_option), default, build_fn(validate = "Self::validate"))]
2271pub struct LeveledCompactionStrategy {
2272    enabled: Option<bool>,
2273    tombstone_threshold: Option<f32>,
2274    tombstone_compaction_interval: Option<i32>,
2275    log_all: Option<bool>,
2276    unchecked_tombstone_compaction: Option<bool>,
2277    only_purge_repaired_tombstone: Option<bool>,
2278    min_threshold: Option<i32>,
2279    max_threshold: Option<i32>,
2280    sstable_size_in_mb: Option<i32>,
2281    fanout_size: Option<i32>,
2282}
2283
2284impl LeveledCompactionStrategyBuilder {
2285    fn validate(&self) -> Result<(), String> {
2286        if let Some(v) = self.tombstone_threshold.flatten() {
2287            if v < 0.0 || v > 1.0 {
2288                return Err(format!("tombstone_threshold must be between 0.0 and 1.0, found {}", v));
2289            }
2290        }
2291        if let Some(v) = self.tombstone_compaction_interval.flatten() {
2292            if v < 0 {
2293                return Err(format!(
2294                    "tombstone_compaction_interval must be a positive integer, found {}",
2295                    v
2296                ));
2297            }
2298        }
2299        if let Some(v) = self.sstable_size_in_mb.flatten() {
2300            if v < 0 {
2301                return Err(format!("sstable_size_in_mb must be a positive integer, found {}", v));
2302            }
2303        }
2304        if let Some(v) = self.fanout_size.flatten() {
2305            if v < 0 {
2306                return Err(format!("fanout_size must be a positive integer, found {}", v));
2307            }
2308        }
2309        if let Some(v) = self.min_threshold.flatten() {
2310            if v < 0 {
2311                return Err(format!("min_threshold must be a positive integer, found {}", v));
2312            }
2313        }
2314        if let Some(v) = self.max_threshold.flatten() {
2315            if v < 0 {
2316                return Err(format!("max_threshold must be a positive integer, found {}", v));
2317            }
2318        }
2319        Ok(())
2320    }
2321}
2322
2323impl CompactionType for LeveledCompactionStrategy {}
2324
2325impl Display for LeveledCompactionStrategy {
2326    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2327        let mut res = vec![format!("'class': 'LeveledCompactionStrategy'")];
2328        if let Some(enabled) = self.enabled {
2329            res.push(format!("'enabled': {}", enabled));
2330        }
2331        if let Some(tombstone_threshold) = self.tombstone_threshold {
2332            res.push(format!(
2333                "'tombstone_threshold': {}",
2334                format_cql_f32(tombstone_threshold)
2335            ));
2336        }
2337        if let Some(tombstone_compaction_interval) = self.tombstone_compaction_interval {
2338            res.push(format!(
2339                "'tombstone_compaction_interval': {}",
2340                tombstone_compaction_interval
2341            ));
2342        }
2343        if let Some(log_all) = self.log_all {
2344            res.push(format!("'log_all': {}", log_all));
2345        }
2346        if let Some(unchecked_tombstone_compaction) = self.unchecked_tombstone_compaction {
2347            res.push(format!(
2348                "'unchecked_tombstone_compaction': {}",
2349                unchecked_tombstone_compaction
2350            ));
2351        }
2352        if let Some(only_purge_repaired_tombstone) = self.only_purge_repaired_tombstone {
2353            res.push(format!(
2354                "'only_purge_repaired_tombstone': {}",
2355                only_purge_repaired_tombstone
2356            ));
2357        }
2358        if let Some(min_threshold) = self.min_threshold {
2359            res.push(format!("'min_threshold': {}", min_threshold));
2360        }
2361        if let Some(max_threshold) = self.max_threshold {
2362            res.push(format!("'max_threshold': {}", max_threshold));
2363        }
2364        if let Some(sstable_size_in_mb) = self.sstable_size_in_mb {
2365            res.push(format!("'sstable_size_in_mb': {}", sstable_size_in_mb));
2366        }
2367        if let Some(fanout_size) = self.fanout_size {
2368            res.push(format!("'fanout_size': {}", fanout_size));
2369        }
2370        write!(f, "{{{}}}", res.join(", "))
2371    }
2372}
2373
2374#[derive(Builder, Copy, Clone, Debug, Default, ToTokens, PartialEq)]
2375#[builder(setter(strip_option), default, build_fn(validate = "Self::validate"))]
2376pub struct TimeWindowCompactionStrategy {
2377    enabled: Option<bool>,
2378    tombstone_threshold: Option<f32>,
2379    tombstone_compaction_interval: Option<i32>,
2380    log_all: Option<bool>,
2381    unchecked_tombstone_compaction: Option<bool>,
2382    only_purge_repaired_tombstone: Option<bool>,
2383    min_threshold: Option<i32>,
2384    max_threshold: Option<i32>,
2385    compaction_window_unit: Option<JavaTimeUnit>,
2386    compaction_window_size: Option<i32>,
2387    unsafe_aggressive_sstable_expiration: Option<bool>,
2388}
2389
2390impl TimeWindowCompactionStrategyBuilder {
2391    fn validate(&self) -> Result<(), String> {
2392        if let Some(v) = self.tombstone_threshold.flatten() {
2393            if v < 0.0 || v > 1.0 {
2394                return Err(format!("tombstone_threshold must be between 0.0 and 1.0, found {}", v));
2395            }
2396        }
2397        if let Some(v) = self.tombstone_compaction_interval.flatten() {
2398            if v < 0 {
2399                return Err(format!(
2400                    "tombstone_compaction_interval must be a positive integer, found {}",
2401                    v
2402                ));
2403            }
2404        }
2405        if let Some(v) = self.compaction_window_size.flatten() {
2406            if v < 0 {
2407                return Err(format!(
2408                    "compaction_window_size must be a positive integer, found {}",
2409                    v
2410                ));
2411            }
2412        }
2413        if let Some(v) = self.min_threshold.flatten() {
2414            if v < 0 {
2415                return Err(format!("min_threshold must be a positive integer, found {}", v));
2416            }
2417        }
2418        if let Some(v) = self.max_threshold.flatten() {
2419            if v < 0 {
2420                return Err(format!("max_threshold must be a positive integer, found {}", v));
2421            }
2422        }
2423        Ok(())
2424    }
2425}
2426
2427impl CompactionType for TimeWindowCompactionStrategy {}
2428
2429impl Display for TimeWindowCompactionStrategy {
2430    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2431        let mut res = vec![format!("'class': 'TimeWindowCompactionStrategy'")];
2432        if let Some(enabled) = self.enabled {
2433            res.push(format!("'enabled': {}", enabled));
2434        }
2435        if let Some(tombstone_threshold) = self.tombstone_threshold {
2436            res.push(format!(
2437                "'tombstone_threshold': {}",
2438                format_cql_f32(tombstone_threshold)
2439            ));
2440        }
2441        if let Some(tombstone_compaction_interval) = self.tombstone_compaction_interval {
2442            res.push(format!(
2443                "'tombstone_compaction_interval': {}",
2444                tombstone_compaction_interval
2445            ));
2446        }
2447        if let Some(log_all) = self.log_all {
2448            res.push(format!("'log_all': {}", log_all));
2449        }
2450        if let Some(unchecked_tombstone_compaction) = self.unchecked_tombstone_compaction {
2451            res.push(format!(
2452                "'unchecked_tombstone_compaction': {}",
2453                unchecked_tombstone_compaction
2454            ));
2455        }
2456        if let Some(only_purge_repaired_tombstone) = self.only_purge_repaired_tombstone {
2457            res.push(format!(
2458                "'only_purge_repaired_tombstone': {}",
2459                only_purge_repaired_tombstone
2460            ));
2461        }
2462        if let Some(min_threshold) = self.min_threshold {
2463            res.push(format!("'min_threshold': {}", min_threshold));
2464        }
2465        if let Some(max_threshold) = self.max_threshold {
2466            res.push(format!("'max_threshold': {}", max_threshold));
2467        }
2468        if let Some(compaction_window_unit) = self.compaction_window_unit {
2469            res.push(format!("'compaction_window_unit': {}", compaction_window_unit));
2470        }
2471        if let Some(compaction_window_size) = self.compaction_window_size {
2472            res.push(format!("'compaction_window_size': {}", compaction_window_size));
2473        }
2474        if let Some(unsafe_aggressive_sstable_expiration) = self.unsafe_aggressive_sstable_expiration {
2475            res.push(format!(
2476                "'unsafe_aggressive_sstable_expiration': {}",
2477                unsafe_aggressive_sstable_expiration
2478            ));
2479        }
2480        write!(f, "{{{}}}", res.join(", "))
2481    }
2482}
2483
2484pub trait CompactionType: Display + Into<Compaction> {}
2485
2486#[derive(Clone, Debug, From, TryInto, ToTokens, PartialEq)]
2487pub enum Compaction {
2488    SizeTiered(SizeTieredCompactionStrategy),
2489    Leveled(LeveledCompactionStrategy),
2490    TimeWindow(TimeWindowCompactionStrategy),
2491}
2492
2493impl Compaction {
2494    pub fn size_tiered() -> SizeTieredCompactionStrategyBuilder
2495    where
2496        Self: Sized,
2497    {
2498        SizeTieredCompactionStrategyBuilder::default()
2499    }
2500
2501    pub fn leveled() -> LeveledCompactionStrategyBuilder
2502    where
2503        Self: Sized,
2504    {
2505        LeveledCompactionStrategyBuilder::default()
2506    }
2507
2508    pub fn time_window() -> TimeWindowCompactionStrategyBuilder
2509    where
2510        Self: Sized,
2511    {
2512        TimeWindowCompactionStrategyBuilder::default()
2513    }
2514}
2515
2516impl TryFrom<MapLiteral> for Compaction {
2517    type Error = anyhow::Error;
2518
2519    fn try_from(value: MapLiteral) -> Result<Self, Self::Error> {
2520        let mut class = None;
2521        let v = value
2522            .elements
2523            .into_iter()
2524            .filter(|(k, v)| {
2525                if let Term::Constant(Constant::String(s)) = k {
2526                    if s.value.to_lowercase().as_str() == "class" {
2527                        class = Some(v.clone());
2528                        return false;
2529                    }
2530                }
2531                true
2532            })
2533            .collect::<Vec<_>>();
2534        let class = class.ok_or_else(|| anyhow::anyhow!("No class in compaction map literal!"))?;
2535        Ok(match class {
2536            Term::Constant(Constant::String(s)) => {
2537                let mut map = HashMap::new();
2538                for (k, v) in v {
2539                    if let Term::Constant(Constant::String(s)) = k {
2540                        map.insert(s.value.to_lowercase(), v);
2541                    } else {
2542                        anyhow::bail!("Invalid key in compaction map literal!");
2543                    }
2544                }
2545                if s.value.ends_with("SizeTieredCompactionStrategy") {
2546                    let mut builder = Self::size_tiered();
2547                    if let Some(t) = map.remove("enabled") {
2548                        builder.enabled(t.try_into()?);
2549                    }
2550                    if let Some(t) = map.remove("tombstone_threshold") {
2551                        builder.tombstone_threshold(t.try_into()?);
2552                    }
2553                    if let Some(t) = map.remove("tombstone_compaction_interval") {
2554                        builder.tombstone_compaction_interval(t.try_into()?);
2555                    }
2556                    if let Some(t) = map.remove("log_all") {
2557                        builder.log_all(t.try_into()?);
2558                    }
2559                    if let Some(t) = map.remove("unchecked_tombstone_compaction") {
2560                        builder.unchecked_tombstone_compaction(t.try_into()?);
2561                    }
2562                    if let Some(t) = map.remove("only_purge_repaired_tombstone") {
2563                        builder.only_purge_repaired_tombstone(t.try_into()?);
2564                    }
2565                    if let Some(t) = map.remove("min_threshold") {
2566                        builder.min_threshold(t.try_into()?);
2567                    }
2568                    if let Some(t) = map.remove("max_threshold") {
2569                        builder.max_threshold(t.try_into()?);
2570                    }
2571                    if let Some(t) = map.remove("min_sstable_size") {
2572                        builder.min_sstable_size(t.try_into()?);
2573                    }
2574                    if let Some(t) = map.remove("bucket_low") {
2575                        builder.bucket_low(t.try_into()?);
2576                    }
2577                    if let Some(t) = map.remove("bucket_high") {
2578                        builder.bucket_high(t.try_into()?);
2579                    }
2580                    Compaction::SizeTiered(builder.build()?)
2581                } else if s.value.ends_with("LeveledCompactionStrategy") {
2582                    let mut builder = Self::leveled();
2583                    if let Some(t) = map.remove("enabled") {
2584                        builder.enabled(t.try_into()?);
2585                    }
2586                    if let Some(t) = map.remove("tombstone_threshold") {
2587                        builder.tombstone_threshold(t.try_into()?);
2588                    }
2589                    if let Some(t) = map.remove("tombstone_compaction_interval") {
2590                        builder.tombstone_compaction_interval(t.try_into()?);
2591                    }
2592                    if let Some(t) = map.remove("log_all") {
2593                        builder.log_all(t.try_into()?);
2594                    }
2595                    if let Some(t) = map.remove("unchecked_tombstone_compaction") {
2596                        builder.unchecked_tombstone_compaction(t.try_into()?);
2597                    }
2598                    if let Some(t) = map.remove("only_purge_repaired_tombstone") {
2599                        builder.only_purge_repaired_tombstone(t.try_into()?);
2600                    }
2601                    if let Some(t) = map.remove("min_threshold") {
2602                        builder.min_threshold(t.try_into()?);
2603                    }
2604                    if let Some(t) = map.remove("max_threshold") {
2605                        builder.max_threshold(t.try_into()?);
2606                    }
2607                    if let Some(t) = map.remove("sstable_size_in_mb") {
2608                        builder.sstable_size_in_mb(t.try_into()?);
2609                    }
2610                    if let Some(t) = map.remove("fanout_size") {
2611                        builder.fanout_size(t.try_into()?);
2612                    }
2613                    Compaction::Leveled(builder.build()?)
2614                } else if s.value.ends_with("TimeWindowCompactionStrategy") {
2615                    let mut builder = Self::time_window();
2616                    if let Some(t) = map.remove("enabled") {
2617                        builder.enabled(t.try_into()?);
2618                    }
2619                    if let Some(t) = map.remove("tombstone_threshold") {
2620                        builder.tombstone_threshold(t.try_into()?);
2621                    }
2622                    if let Some(t) = map.remove("tombstone_compaction_interval") {
2623                        builder.tombstone_compaction_interval(t.try_into()?);
2624                    }
2625                    if let Some(t) = map.remove("log_all") {
2626                        builder.log_all(t.try_into()?);
2627                    }
2628                    if let Some(t) = map.remove("unchecked_tombstone_compaction") {
2629                        builder.unchecked_tombstone_compaction(t.try_into()?);
2630                    }
2631                    if let Some(t) = map.remove("only_purge_repaired_tombstone") {
2632                        builder.only_purge_repaired_tombstone(t.try_into()?);
2633                    }
2634                    if let Some(t) = map.remove("min_threshold") {
2635                        builder.min_threshold(t.try_into()?);
2636                    }
2637                    if let Some(t) = map.remove("max_threshold") {
2638                        builder.max_threshold(t.try_into()?);
2639                    }
2640                    if let Some(t) = map.remove("compaction_window_unit") {
2641                        builder.compaction_window_unit(TryInto::<LitStr>::try_into(t)?.value.parse()?);
2642                    }
2643                    if let Some(t) = map.remove("compaction_window_size") {
2644                        builder.compaction_window_size(t.try_into()?);
2645                    }
2646                    if let Some(t) = map.remove("unsafe_aggressive_sstable_expiration") {
2647                        builder.unsafe_aggressive_sstable_expiration(t.try_into()?);
2648                    }
2649                    Compaction::TimeWindow(builder.build()?)
2650                } else {
2651                    return Err(anyhow::anyhow!("Unknown compaction class: {}", s));
2652                }
2653            }
2654            _ => anyhow::bail!("Invalid class: {}", class),
2655        })
2656    }
2657}
2658
2659impl Display for Compaction {
2660    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2661        match self {
2662            Compaction::SizeTiered(s) => s.fmt(f),
2663            Compaction::Leveled(s) => s.fmt(f),
2664            Compaction::TimeWindow(s) => s.fmt(f),
2665        }
2666    }
2667}
2668
2669#[derive(Copy, Clone, Debug, ToTokens, PartialEq, Eq)]
2670pub enum JavaTimeUnit {
2671    Minutes,
2672    Hours,
2673    Days,
2674}
2675
2676impl FromStr for JavaTimeUnit {
2677    type Err = anyhow::Error;
2678
2679    fn from_str(s: &str) -> Result<Self, Self::Err> {
2680        match s {
2681            "MINUTES" => Ok(JavaTimeUnit::Minutes),
2682            "HOURS" => Ok(JavaTimeUnit::Hours),
2683            "DAYS" => Ok(JavaTimeUnit::Days),
2684            _ => Err(anyhow::anyhow!("Invalid time unit: {}", s)),
2685        }
2686    }
2687}
2688
2689impl Parse for JavaTimeUnit {
2690    type Output = Self;
2691
2692    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
2693        s.parse::<LitStr>()?.value.parse()
2694    }
2695}
2696
2697impl Display for JavaTimeUnit {
2698    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2699        match self {
2700            JavaTimeUnit::Minutes => write!(f, "'MINUTES'"),
2701            JavaTimeUnit::Hours => write!(f, "'HOURS'"),
2702            JavaTimeUnit::Days => write!(f, "'DAYS'"),
2703        }
2704    }
2705}
2706
2707#[derive(Builder, Clone, Debug, Default, ToTokens, PartialEq)]
2708#[builder(setter(strip_option), default)]
2709pub struct Compression {
2710    #[builder(setter(into))]
2711    class: Option<LitStr>,
2712    enabled: Option<bool>,
2713    chunk_length_in_kb: Option<i32>,
2714    crc_check_chance: Option<f32>,
2715    compression_level: Option<i32>,
2716}
2717
2718impl Compression {
2719    pub fn build() -> CompressionBuilder {
2720        CompressionBuilder::default()
2721    }
2722}
2723
2724impl Display for Compression {
2725    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2726        let mut res = Vec::new();
2727        if let Some(ref class) = self.class {
2728            res.push(format!("'class': {}", class));
2729        }
2730        if let Some(enabled) = self.enabled {
2731            res.push(format!("'enabled': {}", enabled));
2732        }
2733        if let Some(chunk_length_in_kb) = self.chunk_length_in_kb {
2734            res.push(format!("'chunk_length_in_kb': {}", chunk_length_in_kb));
2735        }
2736        if let Some(crc_check_chance) = self.crc_check_chance {
2737            res.push(format!("'crc_check_chance': {}", format_cql_f32(crc_check_chance)));
2738        }
2739        if let Some(compression_level) = self.compression_level {
2740            res.push(format!("'compression_level': {}", compression_level));
2741        }
2742        write!(f, "{{{}}}", res.join(", "))
2743    }
2744}
2745
2746impl TryFrom<MapLiteral> for Compression {
2747    type Error = anyhow::Error;
2748
2749    fn try_from(value: MapLiteral) -> Result<Self, Self::Error> {
2750        let mut map = HashMap::new();
2751        for (k, v) in value.elements {
2752            if let Term::Constant(Constant::String(s)) = k {
2753                map.insert(s.value.to_lowercase(), v);
2754            } else {
2755                anyhow::bail!("Invalid key in compaction map literal!");
2756            }
2757        }
2758        let mut builder = Self::build();
2759        if let Some(t) = map.remove("class") {
2760            builder.class(TryInto::<LitStr>::try_into(t)?);
2761        }
2762        if let Some(t) = map.remove("enabled") {
2763            builder.enabled(t.try_into()?);
2764        }
2765        if let Some(t) = map.remove("chunk_length_in_kb") {
2766            builder.chunk_length_in_kb(t.try_into()?);
2767        }
2768        if let Some(t) = map.remove("crc_check_chance") {
2769            builder.crc_check_chance(t.try_into()?);
2770        }
2771        if let Some(t) = map.remove("compression_level") {
2772            builder.compression_level(t.try_into()?);
2773        }
2774        Ok(builder.build()?)
2775    }
2776}
2777
2778#[derive(Builder, Clone, Debug, Default, ToTokens, PartialEq, Eq)]
2779#[builder(setter(strip_option), default)]
2780pub struct Caching {
2781    keys: Option<Keys>,
2782    rows_per_partition: Option<RowsPerPartition>,
2783}
2784
2785impl Caching {
2786    pub fn build() -> CachingBuilder {
2787        CachingBuilder::default()
2788    }
2789}
2790
2791impl Display for Caching {
2792    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2793        let mut res = Vec::new();
2794        if let Some(keys) = &self.keys {
2795            res.push(format!("'keys': {}", keys));
2796        }
2797        if let Some(rows_per_partition) = &self.rows_per_partition {
2798            res.push(format!("'rows_per_partition': {}", rows_per_partition));
2799        }
2800        write!(f, "{{{}}}", res.join(", "))
2801    }
2802}
2803
2804impl TryFrom<MapLiteral> for Caching {
2805    type Error = anyhow::Error;
2806
2807    fn try_from(value: MapLiteral) -> Result<Self, Self::Error> {
2808        let mut map = HashMap::new();
2809        for (k, v) in value.elements {
2810            if let Term::Constant(Constant::String(s)) = k {
2811                map.insert(s.value.to_lowercase(), v);
2812            } else {
2813                anyhow::bail!("Invalid key in compaction map literal!");
2814            }
2815        }
2816        let mut builder = Self::build();
2817        if let Some(t) = map.remove("keys") {
2818            builder.keys(TryInto::<LitStr>::try_into(t)?.value.parse()?);
2819        }
2820        if let Some(t) = map.remove("rows_per_partition") {
2821            builder.rows_per_partition(t.to_string().parse()?);
2822        }
2823        Ok(builder.build()?)
2824    }
2825}
2826
2827#[derive(Copy, Clone, Debug, ToTokens, PartialEq, Eq)]
2828pub enum Keys {
2829    All,
2830    None,
2831}
2832
2833impl FromStr for Keys {
2834    type Err = anyhow::Error;
2835
2836    fn from_str(s: &str) -> Result<Self, Self::Err> {
2837        match s.to_uppercase().as_str() {
2838            "ALL" => Ok(Keys::All),
2839            "NONE" => Ok(Keys::None),
2840            _ => Err(anyhow::anyhow!("Invalid keys: {}", s)),
2841        }
2842    }
2843}
2844
2845impl Parse for Keys {
2846    type Output = Self;
2847    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
2848        s.parse::<LitStr>()?.value.parse()
2849    }
2850}
2851
2852impl Display for Keys {
2853    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2854        match self {
2855            Keys::All => write!(f, "'ALL'"),
2856            Keys::None => write!(f, "'NONE'"),
2857        }
2858    }
2859}
2860
2861#[derive(ParseFromStr, Copy, Clone, Debug, ToTokens, PartialEq, Eq)]
2862pub enum RowsPerPartition {
2863    All,
2864    None,
2865    Count(i32),
2866}
2867
2868impl Parse for RowsPerPartition {
2869    type Output = Self;
2870    fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
2871        Ok(if let Some(ss) = s.parse::<Option<LitStr>>()? {
2872            match ss.value.to_uppercase().as_str() {
2873                "ALL" => RowsPerPartition::All,
2874                "NONE" => RowsPerPartition::None,
2875                _ => anyhow::bail!("Invalid rows_per_partition: {}", ss),
2876            }
2877        } else if let Some(c) = s.parse::<Option<i32>>()? {
2878            Self::Count(c)
2879        } else {
2880            anyhow::bail!("Expected ROWS PER PARTITION value, found {}", s.info())
2881        })
2882    }
2883}
2884
2885impl Display for RowsPerPartition {
2886    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2887        match self {
2888            RowsPerPartition::All => write!(f, "'ALL'"),
2889            RowsPerPartition::None => write!(f, "'NONE'"),
2890            RowsPerPartition::Count(count) => count.fmt(f),
2891        }
2892    }
2893}
2894
2895pub fn format_cql_f32(f: f32) -> String {
2896    let s = f.to_string();
2897    if let Ok(res) = StatementStream::new(&s).parse_from::<Float>() {
2898        res
2899    } else {
2900        format!("{}.0", s)
2901    }
2902}
2903
2904pub fn format_cql_f64(f: f64) -> String {
2905    let s = f.to_string();
2906    if let Ok(res) = StatementStream::new(&s).parse_from::<Float>() {
2907        res
2908    } else {
2909        format!("{}.0", s)
2910    }
2911}
2912
2913pub trait CustomToTokens<'a> {
2914    fn to_tokens(&'a self, tokens: &mut TokenStream);
2915}
2916
2917pub struct TokenWrapper<'a, T>(pub &'a T);
2918
2919impl<'a, T> ToTokens for TokenWrapper<'a, T>
2920where
2921    T: CustomToTokens<'a>,
2922{
2923    fn to_tokens(&self, tokens: &mut TokenStream) {
2924        self.0.to_tokens(tokens);
2925    }
2926}
2927
2928impl<'a, T: 'a> CustomToTokens<'a> for Option<T>
2929where
2930    TokenWrapper<'a, T>: ToTokens,
2931{
2932    fn to_tokens(&'a self, tokens: &mut TokenStream) {
2933        tokens.extend(match self {
2934            Some(t) => {
2935                let t = TokenWrapper(t);
2936                quote! {Some(#t)}
2937            }
2938            None => quote! {None},
2939        });
2940    }
2941}
2942
2943impl<'a, T: 'a> CustomToTokens<'a> for Box<T>
2944where
2945    T: ToTokens,
2946{
2947    fn to_tokens(&'a self, tokens: &mut TokenStream) {
2948        let i = self;
2949        tokens.extend(quote! {Box::new(#i)});
2950    }
2951}
2952
2953impl<'a, T: 'a> CustomToTokens<'a> for Vec<T>
2954where
2955    TokenWrapper<'a, T>: ToTokens,
2956{
2957    fn to_tokens(&'a self, tokens: &mut TokenStream) {
2958        let t = self.iter().map(|t| TokenWrapper(t));
2959        tokens.extend(quote! { vec![#(#t),*]});
2960    }
2961}
2962
2963impl<'a, K: 'static, V: 'static> CustomToTokens<'a> for HashMap<K, V>
2964where
2965    TokenWrapper<'a, K>: ToTokens,
2966    TokenWrapper<'a, V>: ToTokens,
2967{
2968    fn to_tokens(&'a self, tokens: &mut TokenStream) {
2969        let t = self.iter().map(|(k, v)| {
2970            let (k, v) = (TokenWrapper(k), TokenWrapper(v));
2971            quote! {#k => #v}
2972        });
2973        tokens.extend(quote! { maplit::hashmap![#(#t),*]});
2974    }
2975}
2976
2977impl<'a, K: 'static, V: 'static> CustomToTokens<'a> for BTreeMap<K, V>
2978where
2979    TokenWrapper<'a, K>: ToTokens,
2980    TokenWrapper<'a, V>: ToTokens,
2981{
2982    fn to_tokens(&'a self, tokens: &mut TokenStream) {
2983        let t = self.iter().map(|(k, v)| {
2984            let (k, v) = (TokenWrapper(k), TokenWrapper(v));
2985            quote! {#k => #v}
2986        });
2987        tokens.extend(quote! { maplit::btreemap![#(#t),*]});
2988    }
2989}
2990
2991impl<'a, K: 'static> CustomToTokens<'a> for BTreeSet<K>
2992where
2993    TokenWrapper<'a, K>: ToTokens,
2994{
2995    fn to_tokens(&'a self, tokens: &mut TokenStream) {
2996        let t = self.iter().map(|k| TokenWrapper(k));
2997        tokens.extend(quote! { maplit::btreeset![#(#t),*]});
2998    }
2999}
3000impl<'a> CustomToTokens<'a> for &str {
3001    fn to_tokens(&'a self, tokens: &mut TokenStream) {
3002        let s = self;
3003        tokens.extend(quote! { #s });
3004    }
3005}
3006
3007impl<'a> CustomToTokens<'a> for String {
3008    fn to_tokens(&'a self, tokens: &mut TokenStream) {
3009        let s = self;
3010        tokens.extend(quote! { #s.to_string() });
3011    }
3012}
3013
3014macro_rules! impl_custom_to_tokens {
3015    ($($t:ty),*) => {
3016        $(
3017            impl<'a> CustomToTokens<'a> for $t {
3018                fn to_tokens(&'a self, tokens: &mut quote::__private::TokenStream) {
3019                    ToTokens::to_tokens(self, tokens);
3020                }
3021            }
3022        )*
3023    };
3024}
3025
3026impl_custom_to_tokens!(i8, i32, i64, u8, u32, u64, f32, f64, bool, char);
3027
3028macro_rules! impl_custom_to_tokens_tuple {
3029    ($(($t:ident, $v:ident)),+) => {
3030        impl<'a, $($t: ToTokens),+> CustomToTokens<'a> for ($($t),+,) {
3031            fn to_tokens(&'a self, tokens: &mut quote::__private::TokenStream) {
3032                let ( $($v),*, ) = self;
3033                tokens.extend(quote! { ($(#$v),*) });
3034            }
3035        }
3036    };
3037}
3038
3039impl_custom_to_tokens_tuple!((T0, t0));
3040impl_custom_to_tokens_tuple!((T0, t0), (T1, t1));
3041impl_custom_to_tokens_tuple!((T0, t0), (T1, t1), (T2, t2));
3042impl_custom_to_tokens_tuple!((T0, t0), (T1, t1), (T2, t2), (T3, t3));
3043impl_custom_to_tokens_tuple!((T0, t0), (T1, t1), (T2, t2), (T3, t3), (T4, t4));
3044impl_custom_to_tokens_tuple!((T0, t0), (T1, t1), (T2, t2), (T3, t3), (T4, t4), (T5, t5));
3045impl_custom_to_tokens_tuple!((T0, t0), (T1, t1), (T2, t2), (T3, t3), (T4, t4), (T5, t5), (T6, t6));
3046impl_custom_to_tokens_tuple!(
3047    (T0, t0),
3048    (T1, t1),
3049    (T2, t2),
3050    (T3, t3),
3051    (T4, t4),
3052    (T5, t5),
3053    (T6, t6),
3054    (T7, t7)
3055);
3056impl_custom_to_tokens_tuple!(
3057    (T0, t0),
3058    (T1, t1),
3059    (T2, t2),
3060    (T3, t3),
3061    (T4, t4),
3062    (T5, t5),
3063    (T6, t6),
3064    (T7, t7),
3065    (T8, t8)
3066);
3067impl_custom_to_tokens_tuple!(
3068    (T0, t0),
3069    (T1, t1),
3070    (T2, t2),
3071    (T3, t3),
3072    (T4, t4),
3073    (T5, t5),
3074    (T6, t6),
3075    (T7, t7),
3076    (T8, t8),
3077    (T9, t9)
3078);