1use super::query::QueryExt;
2use convert_case::{Case, Casing};
3use std::borrow::Cow;
4use zino_core::{
5 extension::JsonObjectExt,
6 model::{Column, Query},
7 JsonValue,
8};
9
10pub trait EncodeColumn<DB> {
12 fn column_type(&self) -> &str;
14
15 fn encode_value<'a>(&self, value: Option<&'a JsonValue>) -> Cow<'a, str>;
17
18 fn format_value<'a>(&self, value: &'a str) -> Cow<'a, str>;
20
21 fn format_filter(&self, key: &str, value: &JsonValue) -> String;
23}
24
25pub(super) trait ColumnExt {
27 fn is_compatible(&self, data_type: &str) -> bool;
29
30 fn type_annotation(&self) -> &'static str;
32
33 fn field_definition(&self, primary_key_name: &str) -> String;
35
36 fn constraints(&self) -> Vec<String>;
38}
39
40impl ColumnExt for Column<'_> {
41 fn is_compatible(&self, data_type: &str) -> bool {
42 let column_type = self.column_type();
43 if column_type.eq_ignore_ascii_case(data_type) {
44 return true;
45 }
46
47 let data_type = data_type.to_ascii_uppercase();
48 match column_type {
49 "INT" => data_type == "INTEGER",
50 "SMALLINT UNSIGNED" | "SMALLSERIAL" => data_type == "SMALLINT",
51 "INT UNSIGNED" | "SERIAL" => data_type == "INT",
52 "BIGINT UNSIGNED" | "BIGSERIAL" => data_type == "BIGINT",
53 "TEXT" => data_type == "VARCHAR",
54 _ => {
55 if cfg!(feature = "orm-postgres") && column_type.ends_with("[]") {
56 data_type == "ARRAY"
57 } else if column_type.starts_with("TIMESTAMP") {
58 data_type.starts_with("TIMESTAMP")
59 } else if column_type.starts_with("VARCHAR") {
60 matches!(
61 data_type.as_str(),
62 "TEXT" | "VARCHAR" | "CHARACTER VARYING" | "ENUM"
63 )
64 } else {
65 false
66 }
67 }
68 }
69 }
70
71 fn type_annotation(&self) -> &'static str {
72 if cfg!(feature = "orm-postgres") {
73 match self.column_type() {
74 "UUID" => "::UUID",
75 "BIGINT" | "BIGSERIAL" => "::BIGINT",
76 "INT" | "SERIAL" => "::INT",
77 "SMALLINT" | "SMALLSERIAL" => "::SMALLINT",
78 _ => "::TEXT",
79 }
80 } else {
81 ""
82 }
83 }
84
85 fn field_definition(&self, primary_key_name: &str) -> String {
86 let column_name = self
87 .extra()
88 .get_str("column_name")
89 .unwrap_or_else(|| self.name());
90 let column_field = Query::format_field(column_name);
91 let column_type = self.column_type();
92 let mut definition = format!("{column_field} {column_type}");
93 if column_name == primary_key_name {
94 definition += " PRIMARY KEY";
95 }
96 if let Some(value) = self.default_value() {
97 if self.auto_increment() {
98 definition += if cfg!(any(
99 feature = "orm-mariadb",
100 feature = "orm-mysql",
101 feature = "orm-tidb"
102 )) {
103 " AUTO_INCREMENT"
104 } else {
105 ""
107 };
108 } else if self.auto_random() {
109 definition += if cfg!(feature = "orm-tidb") {
111 " AUTO_RANDOM"
112 } else {
113 ""
114 };
115 } else {
116 let value = self.format_value(value);
117 if cfg!(feature = "orm-sqlite") && value.contains('(') {
118 definition = format!("{definition} DEFAULT ({value})");
119 } else {
120 definition = format!("{definition} DEFAULT {value}");
121 }
122 }
123 } else if self.is_not_null() {
124 definition += " NOT NULL";
125 }
126 definition
127 }
128
129 fn constraints(&self) -> Vec<String> {
130 let mut constraints = Vec::new();
131 let extra = self.extra();
132 let column_name = self
133 .extra()
134 .get_str("column_name")
135 .unwrap_or_else(|| self.name());
136 if let Some(reference) = self
137 .reference()
138 .filter(|_| extra.contains_key("foreign_key"))
139 {
140 let column_field = Query::format_field(column_name);
141 let parent_table = Query::format_field(reference.name());
142 let parent_column_field = Query::format_field(reference.column_name());
143 let mut constraint = format!(
144 "FOREIGN KEY ({column_field}) REFERENCES {parent_table}({parent_column_field})"
145 );
146 if let Some(action) = extra.get_str("on_delete") {
147 constraint.push_str(" ON DELETE ");
148 constraint.push_str(&action.to_case(Case::Upper));
149 }
150 if let Some(action) = extra.get_str("on_update") {
151 constraint.push_str(" ON UPDATE ");
152 constraint.push_str(&action.to_case(Case::Upper));
153 }
154 constraints.push(constraint);
155 }
156 constraints
157 }
158}