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 SetTableSpace {
129 name: Option<Identifier>,
131 },
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 fn id(s: &str) -> Identifier {
139 Identifier::from_unquoted(s).unwrap()
140 }
141
142 #[test]
143 fn add_column_serde_round_trip() {
144 let op = TableOp::AddColumn(Column {
145 name: id("email"),
146 ty: ColumnType::Text,
147 nullable: true,
148 default: None,
149 identity: None,
150 generated: None,
151 collation: None,
152 storage: None,
153 compression: None,
154 comment: None,
155 });
156 let entry = TableOpEntry {
157 op,
158 destructiveness: Destructiveness::Safe,
159 };
160 let json = serde_json::to_string(&entry).unwrap();
161 let back: TableOpEntry = serde_json::from_str(&json).unwrap();
162 assert_eq!(entry, back);
163 }
164
165 #[test]
166 fn drop_column_serde_round_trip() {
167 let entry = TableOpEntry {
168 op: TableOp::DropColumn {
169 name: id("email"),
170 is_populated: false,
171 },
172 destructiveness: Destructiveness::RequiresApprovalAndDataLossWarning {
173 reason: "drops column email".into(),
174 },
175 };
176 let json = serde_json::to_string(&entry).unwrap();
177 let back: TableOpEntry = serde_json::from_str(&json).unwrap();
178 assert_eq!(entry, back);
179 }
180
181 #[test]
182 fn alter_column_type_serde_round_trip() {
183 let entry = TableOpEntry {
184 op: TableOp::AlterColumnType {
185 name: id("count"),
186 from: ColumnType::Integer,
187 to: ColumnType::BigInt,
188 using: None,
189 },
190 destructiveness: Destructiveness::Safe,
191 };
192 let json = serde_json::to_string(&entry).unwrap();
193 let back: TableOpEntry = serde_json::from_str(&json).unwrap();
194 assert_eq!(entry, back);
195 }
196
197 #[test]
198 fn set_table_comment_serde_round_trip() {
199 let entry = TableOpEntry {
200 op: TableOp::SetTableComment {
201 comment: Some("the users table".into()),
202 },
203 destructiveness: Destructiveness::Safe,
204 };
205 let json = serde_json::to_string(&entry).unwrap();
206 let back: TableOpEntry = serde_json::from_str(&json).unwrap();
207 assert_eq!(entry, back);
208 }
209}