1use serde::Serialize;
2use yaml_rust::Yaml;
3
4use crate::loader::PgColumnDfn;
5use crate::utils::Named;
6
7impl Named for Column {
8 fn get_name(&self) -> String {
9 self.name.clone()
10 }
11}
12
13impl Named for Trig {
14 fn get_name(&self) -> String {
15 self.name.clone()
16 }
17}
18
19impl Default for Column {
20 fn default() -> Self {
21 Column {
22 name: "".to_string(),
23 column_type: "".to_string(),
24 default_value: None,
25 constraint: None,
26 description: "".to_string(),
27 sql: "".to_string(),
28 index: None,
29 }
30 }
31}
32
33#[derive(Debug, Clone, Serialize)]
34pub struct Column {
35 pub name: String,
36 #[serde(rename = "type")]
37 pub column_type: String,
38 #[serde(rename = "defaultValue", skip_serializing_if = "Option::is_none")]
39 pub default_value: Option<String>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub constraint: Option<Constr>,
43 #[serde(skip_serializing_if = "String::is_empty")]
44 pub description: String,
45 #[serde(skip_serializing_if = "String::is_empty")]
46 pub sql: String,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub index: Option<Index>,
49}
50
51#[derive(Debug, Clone, Serialize)]
52pub struct Index {
53 #[serde(skip_serializing_if = "String::is_empty")]
54 pub name: String,
55 #[serde(skip_serializing_if = "String::is_empty")]
56 pub sql: String,
57}
58
59#[derive(Debug, Clone, Serialize)]
60pub struct Constr {
61 #[serde(rename = "primaryKey", skip_serializing_if = "Option::is_none")]
62 pub primary_key: Option<bool>,
63 pub nullable: bool,
64 #[serde(rename = "foreignKey", skip_serializing_if = "Option::is_none")]
65 pub foreign_key: Option<ForeignKey>,
66}
67
68#[derive(Debug, Clone, Serialize)]
69pub struct ForeignKey {
70 pub references: String,
71 #[serde(skip_serializing_if = "String::is_empty")]
73 pub sql: String, }
75
76#[derive(Debug, Clone, Serialize)]
77pub struct Trig {
78 pub name: String,
79 pub event: String,
81 pub when: String,
83 pub proc: String, }
86
87impl Column {
88 pub(crate) fn new(input: &Yaml) -> Self {
89 let constraint = &input["constraint"];
90 let foreign_key = &constraint["foreignKey"];
91 let references = crate::utils::as_str_esc(foreign_key, "references");
92 let (foreign_key, fk_set) = if references.len() == 0 {
93 (None, false)
94 } else {
95 (
96 Some(ForeignKey {
97 references,
98 sql: crate::utils::as_str_esc(foreign_key, "sql"),
99 }),
100 true,
101 )
102 };
103 let primary_key = crate::utils::as_bool(constraint, "primaryKey", false);
104 let nullable = crate::utils::as_bool(constraint, "nullable", true);
105 let constraint = if primary_key || !nullable || fk_set {
106 Some(Constr {
107 primary_key: if primary_key { Some(true) } else { None },
108 nullable,
109 foreign_key,
110 })
111 } else {
112 None
113 };
114 let index = &input["index"];
115
116 Column {
117 name: crate::utils::safe_sql_name(crate::utils::as_str_esc(input, "name")),
118 column_type: crate::utils::as_str_esc(input, "type"),
119 default_value: input["defaultValue"].as_str().map(|s| crate::utils::as_esc(s)),
120 description: crate::utils::as_str_esc(input, "description"),
121 sql: crate::utils::as_str_esc(input, "sql"),
122 constraint,
123 index: if index.is_null() {
124 None
125 } else {
126 Some(Index::new(index))
127 },
128 }
129 }
130
131 pub fn newt(name: &str, ctype: &str, primary_key: bool, nullable: bool) -> Self {
133 let constraint = if primary_key || !nullable {
134 Some(Constr {
135 primary_key: if primary_key { Some(true) } else { None },
136 nullable,
137 foreign_key: None,
138 })
139 } else {
140 None
141 };
142 Column {
143 name: name.to_string(),
144 column_type: ctype.to_string(),
145 default_value: None,
146 description: "".to_string(),
147 sql: "".to_string(),
148 constraint,
149 index: None,
150 }
151 }
152
153 pub fn is_pk(&self) -> bool {
154 match &self.constraint {
155 None => false,
156 Some(c) => c.primary_key.unwrap_or(false),
157 }
158 }
159
160 #[inline]
161 pub(crate) fn column_def(
162 &self,
163 schema: &String,
164 table_name: &String,
165 file: &str,
166 ) -> Result<PgColumnDfn, String> {
167 if self.column_type.len() == 0 {
168 Err(format!(
169 "Error column definition on table: {}.{} column {} file {}",
170 schema, table_name, self.name, file
171 ))
172 } else {
173 let c = self.constraint.clone();
174 Ok(PgColumnDfn {
175 column_name: self.name.clone(),
176 column_type: self.column_type.clone(),
177 column_default: self.default_value.clone(),
178 sql: Some(self.sql.trim().into()),
179 pk: c.as_ref().map_or(false, |c| c.primary_key.unwrap_or(false)),
180 nullable: c.as_ref().map_or(true, |c| c.nullable),
181 fk: c.map_or(None, |cs| cs.foreign_key
182 .map_or(None, |fk| Some((fk.references.trim().into(), fk.sql.trim().into())))),
183 sort_order: 0,
184 column_comment: None,
185 })
186 }
187 }
188}
189
190impl Trig {
191 pub(crate) fn new(input: &Yaml) -> Self {
192 Trig {
193 name: crate::utils::safe_sql_name(crate::utils::as_str_esc(input, "name")),
194 event: crate::utils::as_str_esc(input, "event"),
195 when: crate::utils::as_str_esc(input, "when"),
196 proc: crate::utils::as_str_esc(input, "proc"),
197 }
198 }
199
200 #[inline]
202 pub(crate) fn trig_def(&self, schema: &String, table_name: &String) -> Option<String> {
203 if self.proc.len() > 0 {
205 Some(format!(
206 "CREATE TRIGGER {} {} ON {}.{} {} EXECUTE PROCEDURE {};",
207 self.name, self.event, schema, table_name, self.when, self.proc
208 ))
209 } else {
210 None
211 }
212 }
213}
214
215impl Index {
216 pub(crate) fn new(input: &Yaml) -> Self {
217 Index {
218 name: crate::utils::as_str_esc(input, "name"),
219 sql: crate::utils::as_str_esc(input, "sql"),
220 }
221 }
222}