toasty_sql/stmt/
alter_column.rs

1use crate::stmt::ColumnDef;
2
3use super::Statement;
4
5use toasty_core::{
6    driver::Capability,
7    schema::db::{Column, ColumnId, Type},
8};
9
10/// A statement to alter a column in a table.
11#[derive(Debug, Clone)]
12pub struct AlterColumn {
13    /// ID of the column being altered.
14    pub id: ColumnId,
15
16    /// Current column definition.
17    pub column_def: ColumnDef,
18
19    /// Changes to be made to the column.
20    pub changes: AlterColumnChanges,
21}
22
23/// A statement to alter a column in a table.
24#[derive(Debug, Clone)]
25pub struct AlterColumnChanges {
26    /// New name for the column (if renaming).
27    pub new_name: Option<String>,
28
29    /// New type information.
30    pub new_ty: Option<Type>,
31
32    /// New nullability constraint.
33    pub new_not_null: Option<bool>,
34
35    /// New auto increment behavior.
36    pub new_auto_increment: Option<bool>,
37}
38
39impl AlterColumnChanges {
40    /// Computes the set of changes between two column definitions.
41    ///
42    /// Each field is `Some` only when the corresponding property differs
43    /// between `previous` and `next`.
44    pub fn from_diff(previous: &Column, next: &Column) -> Self {
45        Self {
46            new_name: (previous.name != next.name).then(|| next.name.clone()),
47            new_ty: (previous.storage_ty != next.storage_ty).then(|| next.storage_ty.clone()),
48            new_not_null: (previous.nullable != next.nullable).then_some(!next.nullable),
49            new_auto_increment: (previous.auto_increment != next.auto_increment)
50                .then_some(next.auto_increment),
51        }
52    }
53
54    /// Splits up this set of changes into a [`Vec`] of individual changes.
55    pub fn split(self) -> Vec<Self> {
56        let Self {
57            new_name,
58            new_ty,
59            new_not_null,
60            new_auto_increment,
61        } = self;
62        let default = AlterColumnChanges {
63            new_name: None,
64            new_ty: None,
65            new_not_null: None,
66            new_auto_increment: None,
67        };
68        let mut result = vec![];
69        if new_name.is_some() {
70            result.push(Self {
71                new_name,
72                ..default.clone()
73            });
74        }
75        if new_ty.is_some() {
76            result.push(Self {
77                new_ty,
78                ..default.clone()
79            });
80        }
81        if new_not_null.is_some() {
82            result.push(Self {
83                new_not_null,
84                ..default.clone()
85            });
86        }
87        if new_auto_increment.is_some() {
88            result.push(Self {
89                new_auto_increment,
90                ..default.clone()
91            });
92        }
93        result
94    }
95
96    /// Returns `true` if any type-level property changed (type, nullability, or auto-increment).
97    pub fn has_type_change(&self) -> bool {
98        self.new_ty.is_some() || self.new_not_null.is_some() || self.new_auto_increment.is_some()
99    }
100}
101
102impl Statement {
103    /// Alters a column.
104    pub fn alter_column(
105        column: &Column,
106        changes: AlterColumnChanges,
107        capability: &Capability,
108    ) -> Self {
109        AlterColumn {
110            id: column.id,
111            column_def: ColumnDef::from_schema(column, &capability.storage_types),
112            changes,
113        }
114        .into()
115    }
116}
117
118impl From<AlterColumn> for Statement {
119    fn from(value: AlterColumn) -> Self {
120        Self::AlterColumn(value)
121    }
122}