use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
pub struct Schema {
pub tables: Vec<TableDef>,
pub enums: Vec<EnumDef>,
}
impl Schema {
pub fn table(&self, name: &str) -> Option<&TableDef> {
self.tables.iter().find(|t| t.name == name)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EnumDef {
pub rust_name: String,
pub values: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TableDef {
pub name: String,
pub struct_name: String,
pub columns: Vec<ColumnDef>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub relations: Vec<RelationDef>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub composite_uniques: Vec<Vec<String>>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub composite_indexes: Vec<Vec<String>>,
}
impl TableDef {
pub fn column(&self, name: &str) -> Option<&ColumnDef> {
self.columns.iter().find(|c| c.name == name)
}
pub fn relation(&self, field: &str) -> Option<&RelationDef> {
self.relations.iter().find(|r| r.field == field)
}
pub fn primary_key(&self) -> Vec<&ColumnDef> {
self.columns.iter().filter(|c| c.primary_key).collect()
}
pub fn auto_id(&self) -> bool {
let pk = self.primary_key();
pk.len() == 1 && pk[0].name == "id" && pk[0].ty == SqlType::Integer
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RelationDef {
pub field: String,
pub target_struct: String,
pub target_table: String,
pub local_column: String,
pub nullable: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ColumnDef {
pub name: String,
pub rust_type: String,
pub ty: SqlType,
pub nullable: bool,
pub primary_key: bool,
pub unique: bool,
pub json: bool,
pub is_enum: bool,
#[serde(default)]
pub index: bool,
pub default: Option<DefaultValue>,
pub references: Option<ForeignKey>,
pub check_in: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub renamed_from: Option<String>,
}
impl ColumnDef {
pub fn signature(&self) -> ColumnDef {
ColumnDef {
renamed_from: None,
index: false,
..self.clone()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SqlType {
Integer,
Real,
Text,
Blob,
Boolean,
Timestamp,
}
impl SqlType {
pub fn sql(self) -> &'static str {
match self {
SqlType::Integer => "INTEGER",
SqlType::Real => "REAL",
SqlType::Text => "TEXT",
SqlType::Blob => "BLOB",
SqlType::Boolean => "BOOLEAN",
SqlType::Timestamp => "TIMESTAMP",
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum DefaultValue {
Now,
Int(i64),
Float(f64),
Text(String),
Bool(bool),
}
impl DefaultValue {
pub fn sql(&self) -> String {
match self {
DefaultValue::Now => "CURRENT_TIMESTAMP".into(),
DefaultValue::Int(i) => i.to_string(),
DefaultValue::Float(f) => f.to_string(),
DefaultValue::Text(s) => format!("'{}'", s.replace('\'', "''")),
DefaultValue::Bool(b) => if *b { "1" } else { "0" }.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ForeignKey {
pub table: String,
pub column: String,
pub on_delete: Option<OnDelete>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum OnDelete {
Cascade,
SetNull,
Restrict,
}
impl OnDelete {
pub fn sql(self) -> &'static str {
match self {
OnDelete::Cascade => "CASCADE",
OnDelete::SetNull => "SET NULL",
OnDelete::Restrict => "RESTRICT",
}
}
}