taos_query/helpers/
database.rs

1use chrono::NaiveDateTime;
2use paste::paste;
3use serde::{Deserialize, Serialize};
4
5use std::{fmt::Display, str::FromStr};
6
7use crate::common::Precision;
8
9#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
10pub struct DatabaseProperties {
11    pub vgroups: Option<u64>,
12    pub replica: Option<u16>,
13    pub quorum: Option<u16>,
14    pub days: Option<u16>,
15    pub keep: Option<String>,
16    #[serde(rename = "cache(MB)")]
17    pub cache: Option<u32>,
18    pub blocks: Option<u32>,
19    pub minrows: Option<u32>,
20    pub maxrows: Option<u32>,
21    #[serde(rename = "wallevel")]
22    pub wal: Option<u8>,
23    pub fsync: Option<u32>,
24    pub comp: Option<u8>,
25    pub cachelast: Option<u8>,
26    pub precision: Option<Precision>,
27    pub update: Option<u8>,
28}
29
30macro_rules! _prop_builder {
31    ($($f:ident)*, $ty:ty) => {
32        $(pub fn $f(mut self, $f: $ty) -> Self {
33            self.$f = Some($f);
34            self
35        })*
36    };
37}
38impl DatabaseProperties {
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    _prop_builder!(vgroups, u64);
44    _prop_builder!(cache blocks minrows maxrows fsync, u32);
45    _prop_builder!(replica quorum days, u16);
46    _prop_builder!(wal comp cachelast update, u8);
47    _prop_builder!(precision, Precision);
48    _prop_builder!(keep, String);
49}
50
51impl Display for DatabaseProperties {
52    #[inline]
53    #[allow(unused_assignments)]
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        let mut has_wrote = false;
56
57        macro_rules! _write_if {
58            ($($f:ident) *) => {
59                $(if let Some($f) = &self.$f {
60                    if has_wrote {
61                        write!(f, " {} {}", paste!(stringify!([<$f:upper>])), $f)?;
62                    } else {
63                        write!(f, "{} {}", paste!(stringify!([<$f:upper>])), $f)?;
64                        has_wrote = true;
65                    }
66                })*
67            };
68            ('str $($s:ident) *) => {
69                $(if let Some($s) = &self.$s {
70                    if has_wrote {
71                        write!(f, " {} '{}'", paste!(stringify!([<$s:upper>])), $s)?;
72                    } else {
73                        write!(f, "{} '{}'", paste!(stringify!([<$s:upper>])), $s)?;
74                        has_wrote = true;
75                    }
76                })*
77            };
78            ($($f:ident) *; 'str $($s:ident) *) => {
79                _write_if!($($f) *);
80                _write_if!('str $($s) *)
81            };
82            ($($f:ident) *; 'str $($s:ident) *; $($f2:ident) *) => {
83                _write_if!($($f) *; 'str $($s) *);
84                _write_if!($($f2) *)
85            };
86        }
87
88        // todo: keep now may fail
89        _write_if!(vgroups replica quorum days keep cache blocks minrows
90                   maxrows wal fsync comp cachelast; 'str precision; update);
91        Ok(())
92    }
93}
94
95impl FromStr for DatabaseProperties {
96    type Err = anyhow::Error;
97
98    fn from_str(s: &str) -> Result<Self, Self::Err> {
99        // CREATE DATABASE log REPLICA 1 QUORUM 1 DAYS 10 KEEP 30 CACHE 1 BLOCKS 3 MINROWS 100 MAXROWS 4096 WAL 1 FSYNC 3000 COMP 2 CACHELAST 0 PRECISION 'us' UPDATE 0
100        use nom::branch::alt;
101        use nom::character::complete::*;
102        use nom::character::streaming;
103        use nom::multi::many0;
104        use nom::sequence::*;
105        use nom::{bytes::complete::tag, IResult};
106
107        let mut repr = Self::new();
108
109        fn parse_name(s: &str) -> IResult<&str, &str> {
110            preceded(
111                tuple((multispace0, tag("CREATE DATABASE"), multispace1)),
112                alphanumeric1,
113            )(s)
114        }
115
116        let s = parse_name(s).map(|s| s.0).unwrap_or(s);
117
118        fn parse_props(s: &str) -> IResult<&str, Vec<(&str, &str)>> {
119            many0(separated_pair(
120                preceded(multispace0, alphanumeric1),
121                streaming::char(' '),
122                alt((
123                    alphanumeric1,
124                    delimited(char('\''), alphanumeric1, char('\'')),
125                )),
126            ))(s)
127        }
128
129        if let Ok((_s, props)) = dbg!(parse_props(s)) {
130            for (prop, value) in props {
131                macro_rules! _parse {
132                    ($($($f:ident) +, $t:ident);*) => {
133                        paste::paste! {
134                            match prop.to_lowercase() {
135                                $($(s if s == stringify!($f) => {
136                                    repr = repr.$f($t::from_str(value)?);
137                                },)*)*
138                                _ => (),
139                            }
140                        }
141                    }
142                }
143                _parse!(vgroups, u64;
144                        cache blocks minrows maxrows fsync, u32;
145                        replica quorum days, u16;
146                        wal comp cachelast  update, u8;
147                        keep, String;
148                        precision, Precision);
149            }
150            Ok(repr)
151        } else {
152            Ok(repr)
153        }
154    }
155}
156
157#[test]
158fn db_prop_from_str() {
159    let s = "REPLICA 1 QUORUM 1 DAYS 10 KEEP 30 CACHE 1 BLOCKS 3 MINROWS 100 MAXROWS 4096 WAL 1 FSYNC 3000 COMP 2 CACHELAST 0 PRECISION 'us' UPDATE 0";
160
161    let db = DatabaseProperties::from_str(s).unwrap();
162
163    let t = db.to_string();
164
165    dbg!(db);
166
167    assert_eq!(s, t);
168}
169
170#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
171pub struct DatabaseRepr {
172    pub name: String,
173    #[serde(flatten)]
174    pub props: DatabaseProperties,
175}
176
177/// A show database representation struct.
178#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
179pub struct ShowDatabase {
180    pub name: String,
181    pub created_time: Option<NaiveDateTime>,
182    pub ntables: Option<usize>,
183    #[serde(flatten)]
184    pub props: DatabaseProperties,
185    pub status: Option<String>,
186}
187
188unsafe impl Send for ShowDatabase {}