pub mod sqlite;
use std::path::Path;
use serde::{Deserialize, Serialize};
use crate::error::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ColumnDtype {
Integer,
Real,
Text,
}
impl ColumnDtype {
pub fn sqlite_decl_type(self) -> &'static str {
match self {
Self::Integer => "INTEGER",
Self::Real => "REAL",
Self::Text => "TEXT",
}
}
pub fn from_decl_type(decl: &str) -> Self {
let upper = decl.trim().to_ascii_uppercase();
if upper.starts_with("INT") {
Self::Integer
} else if upper.starts_with("REA") || upper.starts_with("FLOA") || upper.starts_with("DOUB")
{
Self::Real
} else {
Self::Text
}
}
}
impl std::fmt::Display for ColumnDtype {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.sqlite_decl_type())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ColumnInfo {
pub name: String,
pub dtype: ColumnDtype,
pub null_count: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct IngestReport {
pub table: String,
pub row_count: u64,
pub columns: Vec<ColumnInfo>,
pub source: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct QueryResult {
pub columns: Vec<String>,
pub rows: Vec<Vec<serde_json::Value>>,
pub returned: usize,
pub truncated: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct NumericDescribe {
pub count: u64,
pub mean: f64,
pub std: f64,
pub min: f64,
pub q25: f64,
pub q50: f64,
pub q75: f64,
pub max: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ColumnSummary {
pub name: String,
pub dtype: ColumnDtype,
pub null_count: u64,
pub distinct_count: u64,
pub numeric: Option<NumericDescribe>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TableSummary {
pub table: String,
pub row_count: u64,
pub columns: Vec<ColumnSummary>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TableInfo {
pub table: String,
pub row_count: u64,
pub source: Option<String>,
}
pub trait DataStore: Send {
fn ingest_csv(&self, path: &Path, table: &str) -> Result<IngestReport>;
fn query(&self, sql: &str, row_cap: usize) -> Result<QueryResult>;
fn summarize(&self, table: &str) -> Result<TableSummary>;
fn list_tables(&self) -> Result<Vec<TableInfo>>;
fn backend_name(&self) -> &'static str;
}