Skip to main content

vespertide_core/schema/table/
mod.rs

1mod normalize;
2#[cfg(all(test, feature = "arbitrary"))]
3mod normalize_proptest;
4#[cfg(test)]
5mod tests;
6mod validation;
7
8use serde::{Deserialize, Serialize};
9
10use crate::schema::{column::ColumnDef, constraint::TableConstraint, names::TableName};
11
12pub use validation::TableValidationError;
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
16#[serde(rename_all = "snake_case")]
17pub struct TableDef {
18    pub name: TableName,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub description: Option<String>,
21    pub columns: Vec<ColumnDef>,
22    #[serde(default, skip_serializing_if = "Vec::is_empty")]
23    pub constraints: Vec<TableConstraint>,
24}
25
26impl TableDef {
27    /// Normalizes inline column constraints (`primary_key`, unique, index, `foreign_key`)
28    /// into table-level constraints.
29    /// Returns a new `TableDef` with all inline constraints converted to table-level.
30    ///
31    /// # Errors
32    ///
33    /// Returns an error if the same index name is applied to the same column multiple times.
34    pub fn normalize(&self) -> Result<Self, TableValidationError> {
35        normalize::normalize(self)
36    }
37
38    /// Validate that no two columns share a name within this table.
39    ///
40    /// # Errors
41    /// Returns `TableValidationError::DuplicateColumnName { table, column }`
42    /// if the same column name appears more than once.
43    pub fn validate_unique_column_names(&self) -> Result<(), TableValidationError> {
44        let mut seen: std::collections::BTreeSet<&str> = std::collections::BTreeSet::new();
45        for col in &self.columns {
46            if !seen.insert(col.name.as_str()) {
47                return Err(TableValidationError::DuplicateColumnName {
48                    table: self.name.clone(),
49                    column: col.name.clone(),
50                });
51            }
52        }
53        Ok(())
54    }
55}