use crate::api_request::QualifiedIdentifier;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Table {
pub schema: String,
pub name: String,
pub description: Option<String>,
pub is_view: bool,
pub insertable: bool,
pub updatable: bool,
pub deletable: bool,
pub pk_cols: Vec<String>,
pub columns: ColumnMap,
}
impl Table {
pub fn get_column(&self, name: &str) -> Option<&Column> {
self.columns.get(name)
}
pub fn has_column(&self, name: &str) -> bool {
self.columns.contains_key(name)
}
pub fn qualified_identifier(&self) -> QualifiedIdentifier {
QualifiedIdentifier::new(&self.schema, &self.name)
}
pub fn column_names(&self) -> impl Iterator<Item = &str> {
self.columns.keys().map(|s| s.as_str())
}
pub fn is_readonly(&self) -> bool {
!self.insertable && !self.updatable && !self.deletable
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Column {
pub name: String,
pub description: Option<String>,
pub nullable: bool,
pub data_type: String,
pub nominal_type: String,
pub max_len: Option<i32>,
pub default: Option<String>,
pub enum_values: Vec<String>,
pub is_pk: bool,
pub position: i32,
}
impl Column {
pub fn has_default(&self) -> bool {
self.default.is_some()
}
pub fn is_auto(&self) -> bool {
self.default
.as_ref()
.map(|d| d.contains("nextval(") || d.contains("gen_random_uuid()"))
.unwrap_or(false)
}
pub fn is_json(&self) -> bool {
self.data_type == "json" || self.data_type == "jsonb"
}
pub fn is_array(&self) -> bool {
self.data_type.starts_with('_') || self.data_type.ends_with("[]")
}
pub fn is_range(&self) -> bool {
self.data_type.ends_with("range")
}
}
pub type ColumnMap = IndexMap<String, Column>;
pub type TablesMap = HashMap<QualifiedIdentifier, Table>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_table_qualified_identifier() {
let table = Table {
schema: "public".into(),
name: "users".into(),
description: None,
is_view: false,
insertable: true,
updatable: true,
deletable: true,
pk_cols: vec!["id".into()],
columns: IndexMap::new(),
};
let qi = table.qualified_identifier();
assert_eq!(qi.schema, "public");
assert_eq!(qi.name, "users");
}
#[test]
fn test_column_is_auto() {
let col1 = Column {
name: "id".into(),
description: None,
nullable: false,
data_type: "integer".into(),
nominal_type: "integer".into(),
max_len: None,
default: Some("nextval('users_id_seq'::regclass)".into()),
enum_values: vec![],
is_pk: true,
position: 1,
};
assert!(col1.is_auto());
let col2 = Column {
name: "uuid".into(),
description: None,
nullable: false,
data_type: "uuid".into(),
nominal_type: "uuid".into(),
max_len: None,
default: Some("gen_random_uuid()".into()),
enum_values: vec![],
is_pk: false,
position: 2,
};
assert!(col2.is_auto());
let col3 = Column {
name: "name".into(),
description: None,
nullable: false,
data_type: "text".into(),
nominal_type: "text".into(),
max_len: None,
default: None,
enum_values: vec![],
is_pk: false,
position: 3,
};
assert!(!col3.is_auto());
}
}