Skip to main content

wae_database/
schema.rs

1//! Schema 定义模块
2//!
3//! 提供数据库表结构的元信息定义,用于自动迁移。
4
5use serde::{Deserialize, Serialize};
6
7/// 列类型
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9pub enum ColumnType {
10    /// 整数类型
11    Integer,
12    /// 浮点类型
13    Real,
14    /// 文本类型
15    Text,
16    /// 二进制类型
17    Blob,
18}
19
20impl ColumnType {
21    /// 转换为 SQL 类型字符串
22    pub fn to_sql(&self) -> &'static str {
23        match self {
24            ColumnType::Integer => "INTEGER",
25            ColumnType::Real => "REAL",
26            ColumnType::Text => "TEXT",
27            ColumnType::Blob => "BLOB",
28        }
29    }
30
31    /// 转换为 MySQL SQL 类型字符串
32    #[cfg(feature = "mysql")]
33    pub fn to_mysql_sql(&self) -> &'static str {
34        match self {
35            ColumnType::Integer => "BIGINT",
36            ColumnType::Real => "DOUBLE",
37            ColumnType::Text => "VARCHAR(255)",
38            ColumnType::Blob => "BLOB",
39        }
40    }
41
42    /// 从 SQL 类型字符串解析
43    pub fn from_sql(sql: &str) -> Self {
44        match sql.to_uppercase().as_str() {
45            "INTEGER" | "INT" | "BIGINT" | "SMALLINT" | "TINYINT" => ColumnType::Integer,
46            "REAL" | "FLOAT" | "DOUBLE" | "NUMERIC" | "DECIMAL" => ColumnType::Real,
47            "TEXT" | "VARCHAR" | "CHAR" | "STRING" => ColumnType::Text,
48            "BLOB" | "BINARY" => ColumnType::Blob,
49            _ => ColumnType::Text,
50        }
51    }
52}
53
54/// 列定义
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct ColumnDef {
57    /// 列名
58    pub name: String,
59    /// 列类型
60    pub col_type: ColumnType,
61    /// 是否可空
62    pub nullable: bool,
63    /// 是否主键
64    pub primary_key: bool,
65    /// 是否自增
66    pub auto_increment: bool,
67    /// 默认值
68    pub default_value: Option<String>,
69    /// 是否唯一
70    pub unique: bool,
71}
72
73impl ColumnDef {
74    /// 创建新的列定义
75    pub fn new(name: impl Into<String>, col_type: ColumnType) -> Self {
76        Self {
77            name: name.into(),
78            col_type,
79            nullable: true,
80            primary_key: false,
81            auto_increment: false,
82            default_value: None,
83            unique: false,
84        }
85    }
86
87    /// 设置为不可空
88    pub fn not_null(mut self) -> Self {
89        self.nullable = false;
90        self
91    }
92
93    /// 设置为主键
94    pub fn primary_key(mut self) -> Self {
95        self.primary_key = true;
96        self.nullable = false;
97        self
98    }
99
100    /// 设置为自增
101    pub fn auto_increment(mut self) -> Self {
102        self.auto_increment = true;
103        self
104    }
105
106    /// 设置默认值
107    pub fn default(mut self, value: impl Into<String>) -> Self {
108        self.default_value = Some(value.into());
109        self
110    }
111
112    /// 设置为唯一
113    pub fn unique(mut self) -> Self {
114        self.unique = true;
115        self
116    }
117
118    /// 生成建表 SQL 片段
119    pub fn to_sql(&self) -> String {
120        let mut sql = format!("{} {}", self.name, self.col_type.to_sql());
121
122        if self.primary_key {
123            sql.push_str(" PRIMARY KEY");
124        }
125
126        if self.auto_increment {
127            sql.push_str(" AUTOINCREMENT");
128        }
129
130        if !self.nullable && !self.primary_key {
131            sql.push_str(" NOT NULL");
132        }
133
134        if let Some(ref default) = self.default_value {
135            sql.push_str(&format!(" DEFAULT {}", default));
136        }
137
138        if self.unique && !self.primary_key {
139            sql.push_str(" UNIQUE");
140        }
141
142        sql
143    }
144
145    /// 生成 MySQL 建表 SQL 片段
146    #[cfg(feature = "mysql")]
147    pub fn to_mysql_sql(&self) -> String {
148        let mut sql = format!("{} {}", self.name, self.col_type.to_mysql_sql());
149
150        if self.primary_key {
151            sql.push_str(" PRIMARY KEY");
152        }
153
154        if self.auto_increment {
155            sql.push_str(" AUTO_INCREMENT");
156        }
157
158        if !self.nullable && !self.primary_key {
159            sql.push_str(" NOT NULL");
160        }
161
162        if let Some(ref default) = self.default_value {
163            sql.push_str(&format!(" DEFAULT {}", default));
164        }
165
166        if self.unique && !self.primary_key {
167            sql.push_str(" UNIQUE");
168        }
169
170        sql
171    }
172}
173
174/// 索引定义
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct IndexDef {
177    /// 索引名称
178    pub name: String,
179    /// 表名
180    pub table_name: String,
181    /// 列名列表
182    pub columns: Vec<String>,
183    /// 是否唯一索引
184    pub unique: bool,
185}
186
187impl IndexDef {
188    /// 创建新的索引定义
189    pub fn new(name: impl Into<String>, table_name: impl Into<String>, columns: Vec<String>) -> Self {
190        Self { name: name.into(), table_name: table_name.into(), columns, unique: false }
191    }
192
193    /// 设置为唯一索引
194    pub fn unique(mut self) -> Self {
195        self.unique = true;
196        self
197    }
198
199    /// 生成创建索引 SQL
200    pub fn to_create_sql(&self) -> String {
201        let unique_str = if self.unique { "UNIQUE " } else { "" };
202        let columns = self.columns.join(", ");
203        format!("CREATE {}INDEX {} ON {} ({})", unique_str, self.name, self.table_name, columns)
204    }
205
206    /// 生成删除索引 SQL
207    pub fn to_drop_sql(&self) -> String {
208        format!("DROP INDEX IF EXISTS {}", self.name)
209    }
210}
211
212/// 表结构定义
213#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct TableSchema {
215    /// 表名
216    pub name: String,
217    /// 列定义列表
218    pub columns: Vec<ColumnDef>,
219    /// 索引定义列表
220    pub indexes: Vec<IndexDef>,
221}
222
223impl TableSchema {
224    /// 创建新的表结构
225    pub fn new(name: impl Into<String>) -> Self {
226        Self { name: name.into(), columns: Vec::new(), indexes: Vec::new() }
227    }
228
229    /// 添加列
230    pub fn column(mut self, col: ColumnDef) -> Self {
231        self.columns.push(col);
232        self
233    }
234
235    /// 添加索引
236    pub fn index(mut self, idx: IndexDef) -> Self {
237        self.indexes.push(idx);
238        self
239    }
240
241    /// 生成建表 SQL
242    pub fn to_create_sql(&self) -> String {
243        let columns: Vec<String> = self.columns.iter().map(|c| c.to_sql()).collect();
244        format!("CREATE TABLE {} ({})", self.name, columns.join(", "))
245    }
246
247    /// 生成 MySQL 建表 SQL
248    #[cfg(feature = "mysql")]
249    pub fn to_mysql_create_sql(&self) -> String {
250        let columns: Vec<String> = self.columns.iter().map(|c| c.to_mysql_sql()).collect();
251        format!("CREATE TABLE {} ({}) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", self.name, columns.join(", "))
252    }
253
254    /// 生成删表 SQL
255    pub fn to_drop_sql(&self) -> String {
256        format!("DROP TABLE IF EXISTS {}", self.name)
257    }
258
259    /// 获取主键列
260    pub fn primary_key(&self) -> Option<&ColumnDef> {
261        self.columns.iter().find(|c| c.primary_key)
262    }
263
264    /// 根据名称获取列
265    pub fn get_column(&self, name: &str) -> Option<&ColumnDef> {
266        self.columns.iter().find(|c| c.name == name)
267    }
268}
269
270/// 外键定义
271#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct ForeignKeyDef {
273    /// 外键名称
274    pub name: String,
275    /// 本表列名
276    pub column: String,
277    /// 引用表名
278    pub ref_table: String,
279    /// 引用列名
280    pub ref_column: String,
281    /// 更新行为
282    pub on_update: ReferentialAction,
283    /// 删除行为
284    pub on_delete: ReferentialAction,
285}
286
287/// 外键引用行为
288#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
289pub enum ReferentialAction {
290    /// 无操作
291    NoAction,
292    /// 限制
293    Restrict,
294    /// 级联
295    Cascade,
296    /// 设为空
297    SetNull,
298    /// 设为默认值
299    SetDefault,
300}
301
302impl ReferentialAction {
303    /// 转换为 SQL
304    pub fn to_sql(&self) -> &'static str {
305        match self {
306            ReferentialAction::NoAction => "NO ACTION",
307            ReferentialAction::Restrict => "RESTRICT",
308            ReferentialAction::Cascade => "CASCADE",
309            ReferentialAction::SetNull => "SET NULL",
310            ReferentialAction::SetDefault => "SET DEFAULT",
311        }
312    }
313}
314
315/// 列类型快捷构造函数
316pub mod col {
317    use super::{ColumnDef, ColumnType};
318
319    /// 创建整数列
320    pub fn integer(name: &str) -> ColumnDef {
321        ColumnDef::new(name, ColumnType::Integer)
322    }
323
324    /// 创建浮点列
325    pub fn real(name: &str) -> ColumnDef {
326        ColumnDef::new(name, ColumnType::Real)
327    }
328
329    /// 创建文本列
330    pub fn text(name: &str) -> ColumnDef {
331        ColumnDef::new(name, ColumnType::Text)
332    }
333
334    /// 创建二进制列
335    pub fn blob(name: &str) -> ColumnDef {
336        ColumnDef::new(name, ColumnType::Blob)
337    }
338
339    /// 创建主键列 (自增整数)
340    pub fn id(name: &str) -> ColumnDef {
341        ColumnDef::new(name, ColumnType::Integer).primary_key().auto_increment()
342    }
343
344    /// 创建布尔列
345    pub fn boolean(name: &str) -> ColumnDef {
346        ColumnDef::new(name, ColumnType::Integer).default("0")
347    }
348
349    /// 创建时间戳列
350    pub fn timestamp(name: &str) -> ColumnDef {
351        ColumnDef::new(name, ColumnType::Text)
352    }
353
354    /// 创建 JSON 列
355    pub fn json(name: &str) -> ColumnDef {
356        ColumnDef::new(name, ColumnType::Text)
357    }
358}