1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use std::ops::{Deref, DerefMut};

use itertools::Itertools;
use serde::{Deserialize, Serialize};

use crate::helpers::ColumnMeta;

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Describe(pub(crate) Vec<ColumnMeta>);

impl IntoIterator for Describe {
    type Item = ColumnMeta;

    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromIterator<ColumnMeta> for Describe {
    fn from_iter<T: IntoIterator<Item = ColumnMeta>>(iter: T) -> Self {
        Describe(iter.into_iter().collect())
    }
}

impl Deref for Describe {
    type Target = Vec<ColumnMeta>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Describe {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}
impl Describe {
    #[inline]
    fn fields(&self) -> &[ColumnMeta] {
        &self.0
    }
    pub fn is_stable(&self) -> bool {
        self.fields().iter().any(|f| f.is_tag())
    }
    pub fn names(&self) -> impl Iterator<Item = &str> {
        self.fields().iter().map(|f| f.field())
    }

    pub fn split(&self) -> Option<(&[ColumnMeta], &[ColumnMeta])> {
        if let Some((at, _)) = self.deref().iter().find_position(|c| c.is_tag()) {
            Some(self.deref().split_at(at))
        } else {
            Some(self.deref().split_at(self.0.len()))
        }
    }

    pub fn tag_names(&self) -> impl Iterator<Item = &str> {
        self.fields()
            .iter()
            .filter(|f| f.is_tag())
            .map(|f| f.field())
    }
    pub fn to_create_table_sql(&self, table: &str) -> String {
        let (cols, tags): (Vec<_>, Vec<_>) = self.fields().iter().partition(|f| !f.is_tag());
        let col_sql = cols.into_iter().map(|f| f.sql_repr()).join(",");

        if tags.is_empty() {
            format!("create table if not exists {table} ({col_sql})")
        } else {
            let tags_sql = tags.into_iter().map(|f| f.sql_repr()).join(",");
            format!("create table if not exists {table} ({col_sql}) tags({tags_sql})")
        }
    }
}