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#[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);