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})")
}
}
}