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 _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 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#[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 {}