toasty_core/schema/db/
column.rs1use super::{TableId, Type, table};
2use crate::stmt;
3
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct Column {
33 pub id: ColumnId,
35
36 pub name: String,
38
39 pub ty: stmt::Type,
41
42 pub storage_ty: Type,
44
45 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
47 pub nullable: bool,
48
49 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
51 pub primary_key: bool,
52
53 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
57 pub auto_increment: bool,
58
59 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
61 pub versionable: bool,
62}
63
64#[cfg(feature = "serde")]
65fn is_false(b: &bool) -> bool {
66 !*b
67}
68
69#[derive(PartialEq, Eq, Clone, Copy, Hash)]
83#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
84pub struct ColumnId {
85 pub table: TableId,
87 pub index: usize,
89}
90
91impl ColumnId {
92 pub(crate) fn placeholder() -> Self {
93 Self {
94 table: table::TableId::placeholder(),
95 index: usize::MAX,
96 }
97 }
98}
99
100impl From<&Column> for ColumnId {
101 fn from(value: &Column) -> Self {
102 value.id
103 }
104}
105
106impl fmt::Debug for ColumnId {
107 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
108 write!(fmt, "ColumnId({}/{})", self.table.0, self.index)
109 }
110}
111
112#[cfg(all(test, feature = "serde"))]
113mod serde_tests {
114 use crate::schema::db::{Column, ColumnId, TableId, Type};
115 use crate::stmt;
116
117 fn base_column() -> Column {
118 Column {
119 id: ColumnId {
120 table: TableId(0),
121 index: 0,
122 },
123 name: "test".to_string(),
124 ty: stmt::Type::String,
125 storage_ty: Type::Text,
126 nullable: false,
127 primary_key: false,
128 auto_increment: false,
129 versionable: false,
130 }
131 }
132
133 #[test]
134 fn false_booleans_are_omitted() {
135 let toml = toml::to_string(&base_column()).unwrap();
136 assert!(!toml.contains("nullable"), "toml: {toml}");
137 assert!(!toml.contains("primary_key"), "toml: {toml}");
138 assert!(!toml.contains("auto_increment"), "toml: {toml}");
139 assert!(!toml.contains("versionable"), "toml: {toml}");
140 }
141
142 #[test]
143 fn nullable_true_is_included() {
144 let col = Column {
145 nullable: true,
146 ..base_column()
147 };
148 let toml = toml::to_string(&col).unwrap();
149 assert!(toml.contains("nullable = true"), "toml: {toml}");
150 }
151
152 #[test]
153 fn primary_key_true_is_included() {
154 let col = Column {
155 primary_key: true,
156 ..base_column()
157 };
158 let toml = toml::to_string(&col).unwrap();
159 assert!(toml.contains("primary_key = true"), "toml: {toml}");
160 }
161
162 #[test]
163 fn auto_increment_true_is_included() {
164 let col = Column {
165 auto_increment: true,
166 ..base_column()
167 };
168 let toml = toml::to_string(&col).unwrap();
169 assert!(toml.contains("auto_increment = true"), "toml: {toml}");
170 }
171
172 #[test]
173 fn missing_bool_fields_deserialize_as_false() {
174 let toml = "name = \"test\"\nty = \"String\"\nstorage_ty = \"Text\"\n\n[id]\ntable = 0\nindex = 0\n";
175 let col: Column = toml::from_str(toml).unwrap();
176 assert!(!col.nullable);
177 assert!(!col.primary_key);
178 assert!(!col.auto_increment);
179 assert!(!col.versionable);
180 }
181
182 #[test]
183 fn round_trip_all_true() {
184 let original = Column {
185 nullable: true,
186 primary_key: true,
187 auto_increment: true,
188 ..base_column()
189 };
190 let decoded: Column = toml::from_str(&toml::to_string(&original).unwrap()).unwrap();
191 assert_eq!(original, decoded);
192 }
193}