use crate::ast::expr::Expr;
use crate::catalog::persistent::{DataSourceFormat, TableType};
use crate::planner::types::ResolvedType;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StorageType {
Row,
Columnar,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RowIdMode {
None,
Direct,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Compression {
None,
Lz4,
Zstd,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StorageOptions {
pub storage_type: StorageType,
pub compression: Compression,
pub row_group_size: u32,
pub row_id_mode: RowIdMode,
}
impl Default for StorageOptions {
fn default() -> Self {
Self {
storage_type: StorageType::Row,
compression: Compression::Lz4,
row_group_size: 100_000,
row_id_mode: RowIdMode::Direct,
}
}
}
#[derive(Debug, Clone)]
pub struct TableMetadata {
pub table_id: u32,
pub name: String,
pub catalog_name: String,
pub namespace_name: String,
pub table_type: TableType,
pub data_source_format: DataSourceFormat,
pub columns: Vec<ColumnMetadata>,
pub primary_key: Option<Vec<String>>,
pub storage_options: StorageOptions,
pub storage_location: Option<String>,
pub comment: Option<String>,
pub properties: HashMap<String, String>,
}
impl TableMetadata {
pub fn new(name: impl Into<String>, columns: Vec<ColumnMetadata>) -> Self {
Self {
table_id: 0,
name: name.into(),
catalog_name: "default".to_string(),
namespace_name: "default".to_string(),
table_type: TableType::Managed,
data_source_format: DataSourceFormat::default(),
columns,
primary_key: None,
storage_options: StorageOptions::default(),
storage_location: None,
comment: None,
properties: HashMap::new(),
}
}
pub fn with_table_id(mut self, table_id: u32) -> Self {
self.table_id = table_id;
self
}
pub fn with_primary_key(mut self, columns: Vec<String>) -> Self {
self.primary_key = Some(columns);
self
}
pub fn get_column(&self, name: &str) -> Option<&ColumnMetadata> {
self.columns.iter().find(|c| c.name == name)
}
pub fn get_column_index(&self, name: &str) -> Option<usize> {
self.columns.iter().position(|c| c.name == name)
}
pub fn column_names(&self) -> Vec<&str> {
self.columns.iter().map(|c| c.name.as_str()).collect()
}
pub fn column_count(&self) -> usize {
self.columns.len()
}
}
#[derive(Debug, Clone)]
pub struct ColumnMetadata {
pub name: String,
pub data_type: ResolvedType,
pub not_null: bool,
pub primary_key: bool,
pub unique: bool,
pub default: Option<Expr>,
}
impl ColumnMetadata {
pub fn new(name: impl Into<String>, data_type: ResolvedType) -> Self {
Self {
name: name.into(),
data_type,
not_null: false,
primary_key: false,
unique: false,
default: None,
}
}
pub fn with_not_null(mut self, not_null: bool) -> Self {
self.not_null = not_null;
self
}
pub fn with_primary_key(mut self, primary_key: bool) -> Self {
self.primary_key = primary_key;
self
}
pub fn with_unique(mut self, unique: bool) -> Self {
self.unique = unique;
self
}
pub fn with_default(mut self, default: Expr) -> Self {
self.default = Some(default);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_table_metadata_new() {
let table = TableMetadata::new("users", vec![]);
assert_eq!(table.table_id, 0);
assert_eq!(table.name, "users");
assert!(table.columns.is_empty());
assert!(table.primary_key.is_none());
}
#[test]
fn test_table_metadata_with_table_id() {
let table = TableMetadata::new("users", vec![]).with_table_id(42);
assert_eq!(table.table_id, 42);
assert_eq!(table.name, "users");
}
#[test]
fn test_table_metadata_with_columns() {
let columns = vec![
ColumnMetadata::new("id", ResolvedType::Integer),
ColumnMetadata::new("name", ResolvedType::Text),
];
let table = TableMetadata::new("users", columns);
assert_eq!(table.columns.len(), 2);
assert_eq!(table.columns[0].name, "id");
assert_eq!(table.columns[1].name, "name");
}
#[test]
fn test_table_metadata_with_primary_key() {
let table = TableMetadata::new("users", vec![])
.with_primary_key(vec!["id".to_string(), "tenant_id".to_string()]);
assert_eq!(
table.primary_key,
Some(vec!["id".to_string(), "tenant_id".to_string()])
);
}
#[test]
fn test_get_column() {
let columns = vec![
ColumnMetadata::new("id", ResolvedType::Integer),
ColumnMetadata::new("name", ResolvedType::Text),
];
let table = TableMetadata::new("users", columns);
let id_col = table.get_column("id");
assert!(id_col.is_some());
assert_eq!(id_col.unwrap().name, "id");
assert_eq!(id_col.unwrap().data_type, ResolvedType::Integer);
let name_col = table.get_column("name");
assert!(name_col.is_some());
assert_eq!(name_col.unwrap().data_type, ResolvedType::Text);
assert!(table.get_column("unknown").is_none());
}
#[test]
fn test_get_column_index() {
let columns = vec![
ColumnMetadata::new("id", ResolvedType::Integer),
ColumnMetadata::new("name", ResolvedType::Text),
ColumnMetadata::new("age", ResolvedType::Integer),
];
let table = TableMetadata::new("users", columns);
assert_eq!(table.get_column_index("id"), Some(0));
assert_eq!(table.get_column_index("name"), Some(1));
assert_eq!(table.get_column_index("age"), Some(2));
assert_eq!(table.get_column_index("unknown"), None);
}
#[test]
fn test_column_names() {
let columns = vec![
ColumnMetadata::new("id", ResolvedType::Integer),
ColumnMetadata::new("name", ResolvedType::Text),
ColumnMetadata::new("age", ResolvedType::Integer),
];
let table = TableMetadata::new("users", columns);
assert_eq!(table.column_names(), vec!["id", "name", "age"]);
}
#[test]
fn test_column_count() {
let table = TableMetadata::new(
"users",
vec![
ColumnMetadata::new("id", ResolvedType::Integer),
ColumnMetadata::new("name", ResolvedType::Text),
],
);
assert_eq!(table.column_count(), 2);
}
#[test]
fn test_column_metadata_new() {
let column = ColumnMetadata::new("id", ResolvedType::Integer);
assert_eq!(column.name, "id");
assert_eq!(column.data_type, ResolvedType::Integer);
assert!(!column.not_null);
assert!(!column.primary_key);
assert!(!column.unique);
assert!(column.default.is_none());
}
#[test]
fn test_column_metadata_constraints() {
let column = ColumnMetadata::new("id", ResolvedType::Integer)
.with_not_null(true)
.with_primary_key(true)
.with_unique(true);
assert!(column.not_null);
assert!(column.primary_key);
assert!(column.unique);
}
#[test]
fn test_storage_options_default() {
let options = StorageOptions::default();
assert_eq!(options.storage_type, StorageType::Row);
assert_eq!(options.compression, Compression::Lz4);
assert_eq!(options.row_group_size, 100_000);
assert_eq!(options.row_id_mode, RowIdMode::Direct);
}
#[test]
fn test_table_metadata_sets_default_storage_options() {
let table = TableMetadata::new("users", vec![]);
assert_eq!(table.storage_options, StorageOptions::default());
}
}