1use serde::{Deserialize, Serialize};
4
5use crate::identifier::{Identifier, QualifiedName};
6use crate::ir::column_type::ColumnType;
7use crate::ir::default_expr::DefaultExpr;
8use crate::ir::difference::Difference;
9use crate::ir::eq::{Equiv, field_difference};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub struct Column {
14 pub name: Identifier,
16 pub ty: ColumnType,
18 pub nullable: bool,
20 pub default: Option<DefaultExpr>,
22 pub identity: Option<Identity>,
24 pub generated: Option<Generated>,
26 pub collation: Option<QualifiedName>,
28 pub storage: Option<StorageKind>,
30 pub compression: Option<Compression>,
32 pub comment: Option<String>,
34}
35
36impl Equiv for Column {
37 fn differences(&self, other: &Self) -> Vec<Difference> {
38 let Self {
39 name: _,
40 ty: _,
41 nullable: _,
42 default: _,
43 identity: _,
44 generated: _,
45 collation: _,
46 storage: _,
47 compression: _,
48 comment: _,
49 } = self;
50 let mut out = Vec::new();
51 out.extend(field_difference("name", &self.name, &other.name));
52 out.extend(field_difference(
53 "ty",
54 &format!("{:?}", self.ty),
55 &format!("{:?}", other.ty),
56 ));
57 out.extend(field_difference(
58 "nullable",
59 &self.nullable,
60 &other.nullable,
61 ));
62 out.extend(field_difference(
63 "default",
64 &format!("{:?}", self.default),
65 &format!("{:?}", other.default),
66 ));
67 out.extend(field_difference(
68 "identity",
69 &format!("{:?}", self.identity),
70 &format!("{:?}", other.identity),
71 ));
72 out.extend(field_difference(
73 "generated",
74 &format!("{:?}", self.generated),
75 &format!("{:?}", other.generated),
76 ));
77 out.extend(field_difference(
78 "collation",
79 &format!("{:?}", self.collation),
80 &format!("{:?}", other.collation),
81 ));
82 out.extend(field_difference(
83 "storage",
84 &format!("{:?}", self.storage),
85 &format!("{:?}", other.storage),
86 ));
87 out.extend(field_difference(
88 "compression",
89 &format!("{:?}", self.compression),
90 &format!("{:?}", other.compression),
91 ));
92 out.extend(field_difference(
93 "comment",
94 &format!("{:?}", self.comment),
95 &format!("{:?}", other.comment),
96 ));
97 out
98 }
99}
100
101#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
103pub struct Identity {
104 pub kind: IdentityKind,
106 pub sequence: SequenceOptions,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
112#[serde(rename_all = "snake_case")]
113pub enum IdentityKind {
114 Always,
116 ByDefault,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
122pub struct Generated {
123 pub kind: GeneratedKind,
125 pub expression: crate::ir::default_expr::NormalizedExpr,
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
131#[serde(rename_all = "snake_case")]
132pub enum GeneratedKind {
133 Stored,
135}
136
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
144#[serde(rename_all = "snake_case")]
145pub enum StorageKind {
146 Plain,
148 External,
150 Extended,
152 Main,
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
160#[serde(rename_all = "snake_case")]
161pub enum Compression {
162 Pglz,
165 Lz4,
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
171pub struct SequenceOptions {
172 pub start: i64,
174 pub increment: i64,
176 pub min_value: Option<i64>,
178 pub max_value: Option<i64>,
180 pub cache: i64,
182 pub cycle: bool,
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189 use crate::ir::eq::Equiv;
190
191 fn id(s: &str) -> Identifier {
192 Identifier::from_unquoted(s).unwrap()
193 }
194
195 fn base() -> Column {
196 Column {
197 name: id("email"),
198 ty: ColumnType::Text,
199 nullable: false,
200 default: None,
201 identity: None,
202 generated: None,
203 collation: None,
204 storage: None,
205 compression: None,
206 comment: None,
207 }
208 }
209
210 #[test]
211 fn equal_columns_have_no_diff() {
212 assert!(base().canonical_eq(&base()));
213 }
214
215 #[test]
216 fn type_change_diffs() {
217 let mut b = base();
218 b.ty = ColumnType::Varchar { len: Some(255) };
219 assert!(base().differences(&b).iter().any(|x| x.path == "ty"));
220 }
221
222 #[test]
223 fn nullability_change_diffs() {
224 let mut b = base();
225 b.nullable = true;
226 assert!(base().differences(&b).iter().any(|x| x.path == "nullable"));
227 }
228
229 #[test]
230 fn identity_change_diffs() {
231 let mut b = base();
232 b.identity = Some(Identity {
233 kind: IdentityKind::ByDefault,
234 sequence: SequenceOptions {
235 start: 1,
236 increment: 1,
237 min_value: None,
238 max_value: None,
239 cache: 1,
240 cycle: false,
241 },
242 });
243 assert!(base().differences(&b).iter().any(|x| x.path == "identity"));
244 }
245
246 #[test]
247 fn storage_change_diffs() {
248 let mut b = base();
249 b.storage = Some(StorageKind::External);
250 assert!(base().differences(&b).iter().any(|x| x.path == "storage"));
251 }
252
253 #[test]
254 fn compression_change_diffs() {
255 let mut b = base();
256 b.compression = Some(Compression::Lz4);
257 assert!(
258 base()
259 .differences(&b)
260 .iter()
261 .any(|x| x.path == "compression")
262 );
263 }
264}