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::eq::DiffMacro;
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, DiffMacro)]
12pub struct Column {
13 pub name: Identifier,
15 #[diff(via_debug)]
17 pub ty: ColumnType,
18 pub nullable: bool,
20 #[diff(via_debug)]
22 pub default: Option<DefaultExpr>,
23 #[diff(via_debug)]
25 pub identity: Option<Identity>,
26 #[diff(via_debug)]
28 pub generated: Option<Generated>,
29 #[diff(via_debug)]
31 pub collation: Option<QualifiedName>,
32 #[diff(via_debug)]
34 pub storage: Option<StorageKind>,
35 #[diff(via_debug)]
37 pub compression: Option<Compression>,
38 #[diff(via_debug)]
40 pub comment: Option<String>,
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub struct Identity {
46 pub kind: IdentityKind,
48 pub sequence: SequenceOptions,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
54#[serde(rename_all = "snake_case")]
55pub enum IdentityKind {
56 Always,
58 ByDefault,
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
64pub struct Generated {
65 pub kind: GeneratedKind,
67 pub expression: crate::ir::default_expr::NormalizedExpr,
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
73#[serde(rename_all = "snake_case")]
74pub enum GeneratedKind {
75 Stored,
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
86#[serde(rename_all = "snake_case")]
87pub enum StorageKind {
88 Plain,
90 External,
92 Extended,
94 Main,
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
102#[serde(rename_all = "snake_case")]
103pub enum Compression {
104 Pglz,
107 Lz4,
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
113pub struct SequenceOptions {
114 pub start: i64,
116 pub increment: i64,
118 pub min_value: Option<i64>,
120 pub max_value: Option<i64>,
122 pub cache: i64,
124 pub cycle: bool,
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use crate::ir::eq::Diff;
132
133 fn id(s: &str) -> Identifier {
134 Identifier::from_unquoted(s).unwrap()
135 }
136
137 fn base() -> Column {
138 Column {
139 name: id("email"),
140 ty: ColumnType::Text,
141 nullable: false,
142 default: None,
143 identity: None,
144 generated: None,
145 collation: None,
146 storage: None,
147 compression: None,
148 comment: None,
149 }
150 }
151
152 #[test]
153 fn equal_columns_have_no_diff() {
154 assert!(base().canonical_eq(&base()));
155 }
156
157 #[test]
158 fn type_change_diffs() {
159 let mut b = base();
160 b.ty = ColumnType::Varchar { len: Some(255) };
161 assert!(base().diff(&b).iter().any(|x| x.path == "ty"));
162 }
163
164 #[test]
165 fn nullability_change_diffs() {
166 let mut b = base();
167 b.nullable = true;
168 assert!(base().diff(&b).iter().any(|x| x.path == "nullable"));
169 }
170
171 #[test]
172 fn identity_change_diffs() {
173 let mut b = base();
174 b.identity = Some(Identity {
175 kind: IdentityKind::ByDefault,
176 sequence: SequenceOptions {
177 start: 1,
178 increment: 1,
179 min_value: None,
180 max_value: None,
181 cache: 1,
182 cycle: false,
183 },
184 });
185 assert!(base().diff(&b).iter().any(|x| x.path == "identity"));
186 }
187
188 #[test]
189 fn storage_change_diffs() {
190 let mut b = base();
191 b.storage = Some(StorageKind::External);
192 assert!(base().diff(&b).iter().any(|x| x.path == "storage"));
193 }
194
195 #[test]
196 fn compression_change_diffs() {
197 let mut b = base();
198 b.compression = Some(Compression::Lz4);
199 assert!(base().diff(&b).iter().any(|x| x.path == "compression"));
200 }
201}