1use super::{MssqlColumn, TableName};
4
5#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
7pub struct CreateTableOptions;
8
9pub fn create_table_sql(
11 table: &TableName,
12 columns: &[MssqlColumn],
13 _options: CreateTableOptions,
14) -> String {
15 let mut sql = format!("CREATE TABLE {} (", table.quoted_sql());
16
17 if columns.is_empty() {
18 sql.push_str("\n);");
19 return sql;
20 }
21
22 for (index, column) in columns.iter().enumerate() {
23 let suffix = if index + 1 == columns.len() { "" } else { "," };
24 sql.push_str("\n ");
25 sql.push_str(&column.to_sql());
26 sql.push_str(suffix);
27 }
28
29 sql.push_str("\n);");
30 sql
31}
32
33#[cfg(test)]
34mod tests {
35 use crate::{
36 CreateTableOptions, Identifier, MssqlColumn, MssqlTimePrecision, MssqlType,
37 MssqlTypeLength, TableName, create_table_sql,
38 };
39
40 #[test]
41 fn renders_create_table_with_deterministic_formatting() {
42 let table = TableName::new("dbo", "target").unwrap();
43 let columns = vec![
44 MssqlColumn::new(Identifier::new("id").unwrap(), MssqlType::Int, false),
45 MssqlColumn::new(
46 Identifier::new("name").unwrap(),
47 MssqlType::NVarChar(MssqlTypeLength::Max),
48 true,
49 ),
50 ];
51
52 let sql = create_table_sql(&table, &columns, CreateTableOptions);
53
54 assert_eq!(
55 sql,
56 "CREATE TABLE [dbo].[target] (\n [id] int NOT NULL,\n [name] nvarchar(max) NULL\n);"
57 );
58 }
59
60 #[test]
61 fn quotes_table_and_column_identifiers() {
62 let table = TableName::new("dbo.part", "target]part").unwrap();
63 let columns = vec![MssqlColumn::new(
64 Identifier::new("select]from").unwrap(),
65 MssqlType::Bit,
66 false,
67 )];
68
69 let sql = create_table_sql(&table, &columns, CreateTableOptions);
70
71 assert_eq!(
72 sql,
73 "CREATE TABLE [dbo.part].[target]]part] (\n [select]]from] bit NOT NULL\n);"
74 );
75 }
76
77 #[test]
78 fn renders_empty_column_list_without_panicking() {
79 let table = TableName::unqualified("empty").unwrap();
80
81 let sql = create_table_sql(&table, &[], CreateTableOptions);
82
83 assert_eq!(sql, "CREATE TABLE [empty] (\n);");
84 }
85
86 #[test]
87 fn renders_decimal_and_temporal_columns() {
88 let table = TableName::new("dbo", "events").unwrap();
89 let columns = vec![
90 MssqlColumn::new(
91 Identifier::new("amount").unwrap(),
92 MssqlType::Decimal {
93 precision: 38,
94 scale: 9,
95 },
96 false,
97 ),
98 MssqlColumn::new(
99 Identifier::new("event_date").unwrap(),
100 MssqlType::Date,
101 true,
102 ),
103 MssqlColumn::new(
104 Identifier::new("event_time").unwrap(),
105 MssqlType::Time(MssqlTimePrecision::SEVEN),
106 true,
107 ),
108 MssqlColumn::new(
109 Identifier::new("created_at").unwrap(),
110 MssqlType::DateTime,
111 false,
112 ),
113 MssqlColumn::new(
114 Identifier::new("updated_at").unwrap(),
115 MssqlType::DateTime2 { precision: 7 },
116 false,
117 ),
118 MssqlColumn::new(
119 Identifier::new("source_offset").unwrap(),
120 MssqlType::DateTimeOffset { precision: 7 },
121 true,
122 ),
123 ];
124
125 let sql = create_table_sql(&table, &columns, CreateTableOptions);
126
127 assert_eq!(
128 sql,
129 "CREATE TABLE [dbo].[events] (\n [amount] decimal(38,9) NOT NULL,\n [event_date] date NULL,\n [event_time] time(7) NULL,\n [created_at] datetime NOT NULL,\n [updated_at] datetime2(7) NOT NULL,\n [source_offset] datetimeoffset(7) NULL\n);"
130 );
131 }
132
133 #[test]
134 fn renders_fixed_binary_columns() {
135 let table = TableName::new("dbo", "binary_values").unwrap();
136 let columns = vec![MssqlColumn::new(
137 Identifier::new("digest").unwrap(),
138 MssqlType::Binary(32),
139 false,
140 )];
141
142 let sql = create_table_sql(&table, &columns, CreateTableOptions);
143
144 assert_eq!(
145 sql,
146 "CREATE TABLE [dbo].[binary_values] (\n [digest] binary(32) NOT NULL\n);"
147 );
148 }
149}