1use serde::{Deserialize, Serialize};
6
7use crate::identifier::Identifier;
8use crate::ir::column::{Column, Compression, Generated, Identity, StorageKind};
9use crate::ir::column_type::ColumnType;
10use crate::ir::constraint::Constraint;
11use crate::ir::default_expr::{DefaultExpr, NormalizedExpr};
12
13use super::destructiveness::Destructiveness;
14
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct TableOpEntry {
18 pub op: TableOp,
20 pub destructiveness: Destructiveness,
22}
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26#[serde(tag = "kind", content = "value", rename_all = "snake_case")]
27pub enum TableOp {
28 AddColumn(Column),
30 DropColumn {
32 name: Identifier,
34 is_populated: bool,
37 },
38 AlterColumnType {
41 name: Identifier,
43 from: ColumnType,
45 to: ColumnType,
47 using: Option<NormalizedExpr>,
49 },
50 SetColumnNullable {
52 name: Identifier,
54 nullable: bool,
56 },
57 SetColumnDefault {
59 name: Identifier,
61 default: Option<DefaultExpr>,
63 },
64 SetColumnIdentity {
66 name: Identifier,
68 identity: Option<Identity>,
70 },
71 SetColumnGenerated {
73 name: Identifier,
75 generated: Option<Generated>,
77 },
78 SetColumnComment {
80 name: Identifier,
82 comment: Option<String>,
84 },
85 SetColumnStorage {
87 name: Identifier,
89 from: StorageKind,
94 to: StorageKind,
96 },
97 SetColumnCompression {
99 name: Identifier,
101 compression: Option<Compression>,
104 },
105
106 AddConstraint(Constraint),
108 DropConstraint {
110 name: Identifier,
112 },
113 SetConstraintComment {
115 name: Identifier,
117 comment: Option<String>,
119 },
120
121 SetTableComment {
123 comment: Option<String>,
125 },
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 fn id(s: &str) -> Identifier {
133 Identifier::from_unquoted(s).unwrap()
134 }
135
136 #[test]
137 fn add_column_serde_round_trip() {
138 let op = TableOp::AddColumn(Column {
139 name: id("email"),
140 ty: ColumnType::Text,
141 nullable: true,
142 default: None,
143 identity: None,
144 generated: None,
145 collation: None,
146 storage: None,
147 compression: None,
148 comment: None,
149 });
150 let entry = TableOpEntry {
151 op,
152 destructiveness: Destructiveness::Safe,
153 };
154 let json = serde_json::to_string(&entry).unwrap();
155 let back: TableOpEntry = serde_json::from_str(&json).unwrap();
156 assert_eq!(entry, back);
157 }
158
159 #[test]
160 fn drop_column_serde_round_trip() {
161 let entry = TableOpEntry {
162 op: TableOp::DropColumn {
163 name: id("email"),
164 is_populated: false,
165 },
166 destructiveness: Destructiveness::RequiresApprovalAndDataLossWarning {
167 reason: "drops column email".into(),
168 },
169 };
170 let json = serde_json::to_string(&entry).unwrap();
171 let back: TableOpEntry = serde_json::from_str(&json).unwrap();
172 assert_eq!(entry, back);
173 }
174
175 #[test]
176 fn alter_column_type_serde_round_trip() {
177 let entry = TableOpEntry {
178 op: TableOp::AlterColumnType {
179 name: id("count"),
180 from: ColumnType::Integer,
181 to: ColumnType::BigInt,
182 using: None,
183 },
184 destructiveness: Destructiveness::Safe,
185 };
186 let json = serde_json::to_string(&entry).unwrap();
187 let back: TableOpEntry = serde_json::from_str(&json).unwrap();
188 assert_eq!(entry, back);
189 }
190
191 #[test]
192 fn set_table_comment_serde_round_trip() {
193 let entry = TableOpEntry {
194 op: TableOp::SetTableComment {
195 comment: Some("the users table".into()),
196 },
197 destructiveness: Destructiveness::Safe,
198 };
199 let json = serde_json::to_string(&entry).unwrap();
200 let back: TableOpEntry = serde_json::from_str(&json).unwrap();
201 assert_eq!(entry, back);
202 }
203}