use crate::types::{ColumnSchema, ConstraintType, ForeignKeyRef, TableConstraintInfo};
use sqlparser::ast::{ColumnDef, ColumnOption, ColumnOptionDef, TableConstraint};
use std::collections::HashSet;
pub fn extract_column_constraints(
options: &[ColumnOptionDef],
) -> (Option<bool>, Option<ForeignKeyRef>) {
let mut is_pk = None;
let mut fk_ref = None;
for opt in options {
match &opt.option {
ColumnOption::PrimaryKey(_) => {
is_pk = Some(true);
}
ColumnOption::ForeignKey(fk) => {
if let Some(col) = fk.referred_columns.first() {
fk_ref = Some(ForeignKeyRef {
table: fk.foreign_table.to_string(),
column: col.value.clone(),
});
}
}
_ => {}
}
}
(is_pk, fk_ref)
}
pub fn extract_table_constraints(
constraints: &[TableConstraint],
) -> (Vec<String>, Vec<TableConstraintInfo>) {
let mut pk_columns = Vec::new();
let mut constraint_infos = Vec::new();
for constraint in constraints {
match constraint {
TableConstraint::PrimaryKey(pk) => {
let col_names: Vec<String> = pk
.columns
.iter()
.map(|c| c.column.expr.to_string())
.collect();
pk_columns.extend(col_names.clone());
constraint_infos.push(TableConstraintInfo {
constraint_type: ConstraintType::PrimaryKey,
columns: col_names,
referenced_table: None,
referenced_columns: None,
});
}
TableConstraint::ForeignKey(fk) => {
let col_names: Vec<String> = fk.columns.iter().map(|c| c.value.clone()).collect();
let ref_col_names: Vec<String> = fk
.referred_columns
.iter()
.map(|c| c.value.clone())
.collect();
constraint_infos.push(TableConstraintInfo {
constraint_type: ConstraintType::ForeignKey,
columns: col_names,
referenced_table: Some(fk.foreign_table.to_string()),
referenced_columns: Some(ref_col_names),
});
}
TableConstraint::Unique(uc) => {
let col_names: Vec<String> = uc
.columns
.iter()
.map(|c| c.column.expr.to_string())
.collect();
constraint_infos.push(TableConstraintInfo {
constraint_type: ConstraintType::Unique,
columns: col_names,
referenced_table: None,
referenced_columns: None,
});
}
_ => {}
}
}
(pk_columns, constraint_infos)
}
pub fn build_column_schemas_with_constraints(
columns: &[ColumnDef],
table_constraints: &[TableConstraint],
) -> (Vec<ColumnSchema>, Vec<TableConstraintInfo>) {
let (pk_column_names, table_constraint_infos) = extract_table_constraints(table_constraints);
let pk_columns_set: HashSet<&str> = pk_column_names.iter().map(|s| s.as_str()).collect();
let column_schemas = columns
.iter()
.map(|c| {
let (is_pk, fk_ref) = extract_column_constraints(&c.options);
let is_primary_key =
if is_pk.unwrap_or(false) || pk_columns_set.contains(c.name.value.as_str()) {
Some(true)
} else {
None
};
ColumnSchema {
name: c.name.value.clone(),
data_type: Some(c.data_type.to_string()),
is_primary_key,
foreign_key: fk_ref,
}
})
.collect();
(column_schemas, table_constraint_infos)
}