1use std::{
2 fmt,
3 ops::{Deref, DerefMut},
4 str::FromStr,
5};
6
7use serde::{
8 de::{self, MapAccess, SeqAccess, Visitor},
9 Deserialize, Deserializer, Serialize,
10};
11
12use crate::common::Ty;
13
14#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
33pub struct CompressOptions {
34 pub encode: String,
35 pub compress: String,
36 pub level: String,
37}
38
39impl CompressOptions {
40 pub fn new(
41 encode: impl Into<String>,
42 compress: impl Into<String>,
43 level: impl Into<String>,
44 ) -> Self {
45 Self {
46 encode: encode.into(),
47 compress: compress.into(),
48 level: level.into(),
49 }
50 }
51}
52
53impl fmt::Display for CompressOptions {
54 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55 write!(
56 f,
57 "ENCODE '{}' COMPRESS '{}' LEVEL '{}'",
58 self.encode, self.compress, self.level
59 )
60 }
61}
62
63#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
64pub struct Described {
65 pub field: String,
66 #[serde(rename = "type")]
67 pub ty: Ty,
68 pub length: usize,
69 #[serde(default)]
70 pub note: Option<String>,
71 #[serde(flatten, default)]
72 pub compression: Option<CompressOptions>,
73}
74
75impl Described {
76 pub fn sql_repr(&self) -> String {
80 let ty = self.ty;
81 match (self.is_primary_key(), ty.is_var_type(), &self.compression) {
82 (true, true, None) => format!("`{}` {}({}) PRIMARY KEY", self.field, ty, self.length),
83 (true, false, None) => format!("`{}` {} PRIMARY KEY", self.field, self.ty),
84 (true, true, Some(t)) => {
85 format!("`{}` {}({}) {} PRIMARY KEY", self.field, ty, self.length, t)
86 }
87 (true, false, Some(t)) => {
88 format!("`{}` {} {} PRIMARY KEY", self.field, ty, t)
89 }
90
91 (false, true, None) => format!("`{}` {}({})", self.field, ty, self.length),
92 (false, false, None) => format!("`{}` {}", self.field, self.ty),
93 (false, true, Some(t)) => {
94 format!("`{}` {}({}) {}", self.field, ty, self.length, t)
95 }
96 (false, false, Some(t)) => {
97 format!("`{}` {} {}", self.field, ty, t)
98 }
99 }
100 }
101
102 pub fn new(field: impl Into<String>, ty: Ty, length: impl Into<Option<usize>>) -> Self {
104 let field = field.into();
105 let length = length.into();
106 let length = length.unwrap_or_else(|| {
107 if ty.is_var_type() {
108 32
109 } else {
110 ty.fixed_length()
111 }
112 });
113 Self {
114 field,
115 ty,
116 length,
117 note: None,
118 compression: None,
119 }
120 }
121
122 pub fn is_primary_key(&self) -> bool {
124 self.note.as_deref() == Some("PRIMARY KEY")
125 }
126
127 pub fn is_tag(&self) -> bool {
129 self.note.as_deref() == Some("TAG")
130 }
131}
132#[derive(Debug, Serialize, PartialEq, Eq, Clone)]
133#[serde(untagged)]
134pub enum ColumnMeta {
135 Column(Described),
136 Tag(Described),
137}
138
139impl Deref for ColumnMeta {
140 type Target = Described;
141
142 fn deref(&self) -> &Self::Target {
143 match self {
144 ColumnMeta::Column(v) => v,
145 ColumnMeta::Tag(v) => v,
146 }
147 }
148}
149
150impl DerefMut for ColumnMeta {
151 fn deref_mut(&mut self) -> &mut Self::Target {
152 match self {
153 ColumnMeta::Column(v) => v,
154 ColumnMeta::Tag(v) => v,
155 }
156 }
157}
158
159#[inline(always)]
160fn empty_as_none(s: &str) -> Option<String> {
161 if s.is_empty() {
162 None
163 } else {
164 Some(s.to_string())
165 }
166}
167unsafe impl Send for ColumnMeta {}
168impl<'de> Deserialize<'de> for ColumnMeta {
169 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
170 where
171 D: Deserializer<'de>,
172 {
173 enum Meta {
174 Field,
175 Type,
176 Length,
177 Note,
178 Encode,
179 Compress,
180 Level,
181 }
182
183 impl<'de> Deserialize<'de> for Meta {
184 fn deserialize<D>(deserializer: D) -> Result<Meta, D::Error>
185 where
186 D: Deserializer<'de>,
187 {
188 struct FieldVisitor;
189
190 impl<'de> Visitor<'de> for FieldVisitor {
191 type Value = Meta;
192
193 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
194 formatter.write_str(
195 "one of `field`, `type`, `length`, `note`, `encode`, `compress`, `level`",
196 )
197 }
198
199 fn visit_str<E>(self, value: &str) -> Result<Meta, E>
200 where
201 E: de::Error,
202 {
203 match value.to_lowercase().as_str() {
204 "field" => Ok(Meta::Field),
205 "type" => Ok(Meta::Type),
206 "length" => Ok(Meta::Length),
207 "note" => Ok(Meta::Note),
208 "encode" => Ok(Meta::Encode),
209 "compress" => Ok(Meta::Compress),
210 "level" => Ok(Meta::Level),
211 _ => Err(de::Error::unknown_field(value, FIELDS)),
212 }
213 }
214 }
215
216 deserializer.deserialize_identifier(FieldVisitor)
217 }
218 }
219
220 struct MetaVisitor;
221
222 impl<'de> Visitor<'de> for MetaVisitor {
223 type Value = ColumnMeta;
224
225 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
226 formatter.write_str("struct ColumnMeta")
227 }
228
229 fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
230 where
231 V: SeqAccess<'de>,
232 {
233 let field = seq
234 .next_element()?
235 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
236 let ty = seq
237 .next_element()?
238 .ok_or_else(|| de::Error::invalid_length(1, &self))
239 .and_then(|s| Ty::from_str(s).map_err(de::Error::custom))?;
240 let length = seq
241 .next_element()?
242 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
243 let note: Option<String> = seq
244 .next_element::<Option<&str>>()?
245 .and_then(|opt| opt)
246 .and_then(empty_as_none);
247
248 let encode: Option<String> = seq
251 .next_element::<Option<&str>>()?
252 .and_then(|opt| opt)
253 .and_then(empty_as_none);
254 let compress: Option<String> = seq
255 .next_element::<Option<&str>>()?
256 .and_then(|opt| opt)
257 .and_then(empty_as_none);
258 let level: Option<String> = seq
259 .next_element::<Option<&str>>()?
260 .and_then(|opt| opt)
261 .and_then(empty_as_none);
262
263 let compression = if let (Some(encode), Some(compress), Some(level)) =
264 (encode, compress, level)
265 {
266 Some(CompressOptions::new(encode, compress, level))
267 } else {
268 None
269 };
270 let desc = Described {
271 field,
272 ty,
273 length,
274 note,
275 compression,
276 };
277 if !desc.is_tag() {
278 Ok(ColumnMeta::Column(desc))
279 } else {
280 Ok(ColumnMeta::Tag(desc))
281 }
282 }
283
284 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
285 where
286 V: MapAccess<'de>,
287 {
288 let mut field = None;
289 let mut ty = None;
290 let mut length = None;
291 let mut note = None;
292 let mut encode = None;
293 let mut compress = None;
294 let mut level = None;
295 while let Some(key) = map.next_key()? {
296 match key {
297 Meta::Field => {
298 if field.is_some() {
299 return Err(de::Error::duplicate_field("field"));
300 }
301 field = Some(map.next_value()?);
302 }
303 Meta::Type => {
304 if ty.is_some() {
305 return Err(de::Error::duplicate_field("type"));
306 }
307 let t: Ty = map.next_value()?;
308 ty = Some(t);
309 }
310 Meta::Length => {
311 if length.is_some() {
312 return Err(de::Error::duplicate_field("length"));
313 }
314 length = Some(map.next_value()?);
315 }
316 Meta::Note => {
317 if note.is_some() {
318 return Err(de::Error::duplicate_field("note"));
319 }
320 note = map.next_value::<Option<&str>>()?.and_then(empty_as_none);
321 }
322 Meta::Encode => {
323 if encode.is_some() {
324 return Err(de::Error::duplicate_field("encode"));
325 }
326 encode = map.next_value::<Option<&str>>()?.and_then(empty_as_none);
327 }
328 Meta::Compress => {
329 if compress.is_some() {
330 return Err(de::Error::duplicate_field("compress"));
331 }
332 compress = map.next_value::<Option<&str>>()?.and_then(empty_as_none);
333 }
334 Meta::Level => {
335 if level.is_some() {
336 return Err(de::Error::duplicate_field("level"));
337 }
338 level = map.next_value::<Option<&str>>()?.and_then(empty_as_none);
339 }
340 }
341 }
342 let field = field.ok_or_else(|| de::Error::missing_field("field"))?;
343 let ty = ty.ok_or_else(|| de::Error::missing_field("type"))?;
344 let length = length.ok_or_else(|| de::Error::missing_field("length"))?;
345 let note = note.map(|s| s.to_string());
346 let compression = if let (Some(encode), Some(compress), Some(level)) =
347 (encode, compress, level)
348 {
349 Some(CompressOptions::new(encode, compress, level))
350 } else {
351 None
352 };
353 let desc = Described {
354 field,
355 ty,
356 length,
357 note,
358 compression,
359 };
360 if !desc.is_tag() {
361 Ok(ColumnMeta::Column(desc))
362 } else {
363 Ok(ColumnMeta::Tag(desc))
364 }
365 }
366 }
367
368 const FIELDS: &[&str] = &[
369 "field", "type", "length", "note", "encode", "compress", "level",
370 ];
371 deserializer.deserialize_struct("ColumnMeta", FIELDS, MetaVisitor)
372 }
373}
374impl ColumnMeta {
375 pub fn field(&self) -> &str {
376 match self {
377 ColumnMeta::Column(desc) | ColumnMeta::Tag(desc) => desc.field.as_str(),
378 }
379 }
380 pub fn ty(&self) -> Ty {
381 match self {
382 ColumnMeta::Column(desc) | ColumnMeta::Tag(desc) => desc.ty,
383 }
384 }
385 pub fn length(&self) -> usize {
386 match self {
387 ColumnMeta::Column(desc) | ColumnMeta::Tag(desc) => desc.length,
388 }
389 }
390 pub fn note(&self) -> &str {
391 match self {
392 ColumnMeta::Tag(_) => "TAG",
393 _ => "",
394 }
395 }
396 pub fn is_tag(&self) -> bool {
397 matches!(self, ColumnMeta::Tag(_))
398 }
399}
400
401#[test]
402fn serde_meta() {
403 let meta = ColumnMeta::Column(Described {
405 field: "name".to_string(),
406 ty: Ty::BigInt,
407 length: 8,
408 note: None,
409 compression: None,
410 });
411
412 let sql = meta.deref().sql_repr();
413
414 assert_eq!(sql, "`name` BIGINT");
415
416 let a = serde_json::to_string(&meta).unwrap();
417
418 let d: ColumnMeta = serde_json::from_str(&a).unwrap();
419
420 assert_eq!(meta, d);
421
422 let meta = ColumnMeta::Column(Described {
424 field: "name".to_string(),
425 ty: Ty::BigInt,
426 length: 8,
427 note: Some("PRIMARY KEY".to_string()),
428 compression: None,
429 });
430 let sql = meta.deref().sql_repr();
431
432 assert_eq!(sql, "`name` BIGINT PRIMARY KEY");
433
434 let a = serde_json::to_string(&meta).unwrap();
435
436 let d: ColumnMeta = serde_json::from_str(&a).unwrap();
437
438 assert_eq!(meta, d);
439
440 let meta = ColumnMeta::Column(Described {
442 field: "name".to_string(),
443 ty: Ty::BigInt,
444 length: 8,
445 note: None,
446 compression: Some(CompressOptions::new("delta-i", "lz4", "medium")),
447 });
448 let sql = meta.deref().sql_repr();
449
450 assert_eq!(
451 sql,
452 "`name` BIGINT ENCODE 'delta-i' COMPRESS 'lz4' LEVEL 'medium'"
453 );
454
455 let a = serde_json::to_string(&meta).unwrap();
456
457 let d: ColumnMeta = serde_json::from_str(&a).unwrap();
458
459 assert_eq!(meta, d);
460
461 let meta = ColumnMeta::Column(Described {
463 field: "name".to_string(),
464 ty: Ty::BigInt,
465 length: 8,
466 note: Some("PRIMARY KEY".to_string()),
467 compression: Some(CompressOptions::new("delta-i", "lz4", "medium")),
468 });
469 let sql = meta.deref().sql_repr();
470
471 assert_eq!(
472 sql,
473 "`name` BIGINT ENCODE 'delta-i' COMPRESS 'lz4' LEVEL 'medium' PRIMARY KEY"
474 );
475
476 let a = serde_json::to_string(&meta).unwrap();
477
478 let d: ColumnMeta = serde_json::from_str(&a).unwrap();
479
480 assert_eq!(meta, d);
481
482 let a = r#"["name", "BIGINT", 8, null, null, null, null]"#;
484 let d: ColumnMeta = serde_json::from_str(a).unwrap();
485 assert_eq!(
486 d,
487 ColumnMeta::Column(Described {
488 field: "name".to_string(),
489 ty: Ty::BigInt,
490 length: 8,
491 note: None,
492 compression: None,
493 })
494 );
495}