Skip to main content

wae_database/
schema.rs

1//! Schema 定义模块
2//!
3//! 提供数据库表结构的元信息定义,用于自动迁移。
4
5use once_cell::sync::Lazy;
6use serde::{Deserialize, Serialize};
7use std::{collections::HashMap, fs, path::Path, sync::Mutex};
8
9/// 数据库类型
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11pub enum DatabaseType {
12    /// Turso/SQLite
13    Turso,
14    /// PostgreSQL
15    Postgres,
16    /// MySQL
17    MySql,
18}
19
20impl DatabaseType {
21    /// 获取当前数据库类型(根据 feature flag)
22    pub fn current() -> Self {
23        #[cfg(feature = "postgres")]
24        {
25            return DatabaseType::Postgres;
26        }
27        #[cfg(feature = "mysql")]
28        {
29            return DatabaseType::MySql;
30        }
31        #[cfg(all(not(feature = "postgres"), not(feature = "mysql")))]
32        {
33            return DatabaseType::Turso;
34        }
35    }
36}
37
38/// 列类型
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
40pub enum ColumnType {
41    /// 整数类型
42    Integer,
43    /// 浮点类型
44    Real,
45    /// 文本类型
46    Text,
47    /// 二进制类型
48    Blob,
49}
50
51impl ColumnType {
52    /// 转换为 SQL 类型字符串
53    pub fn to_sql(&self) -> &'static str {
54        self.to_sql_for(DatabaseType::Turso)
55    }
56
57    /// 转换为指定数据库的 SQL 类型字符串
58    pub fn to_sql_for(&self, db_type: DatabaseType) -> &'static str {
59        match db_type {
60            DatabaseType::Turso => match self {
61                ColumnType::Integer => "INTEGER",
62                ColumnType::Real => "REAL",
63                ColumnType::Text => "TEXT",
64                ColumnType::Blob => "BLOB",
65            },
66            DatabaseType::Postgres => match self {
67                ColumnType::Integer => "BIGINT",
68                ColumnType::Real => "DOUBLE PRECISION",
69                ColumnType::Text => "TEXT",
70                ColumnType::Blob => "BYTEA",
71            },
72            DatabaseType::MySql => match self {
73                ColumnType::Integer => "BIGINT",
74                ColumnType::Real => "DOUBLE",
75                ColumnType::Text => "VARCHAR(255)",
76                ColumnType::Blob => "BLOB",
77            },
78        }
79    }
80
81    /// 转换为 MySQL SQL 类型字符串
82    #[cfg(feature = "mysql")]
83    pub fn to_mysql_sql(&self) -> &'static str {
84        self.to_sql_for(DatabaseType::MySql)
85    }
86
87    /// 从 SQL 类型字符串解析
88    pub fn from_sql(sql: &str) -> Self {
89        match sql.to_uppercase().as_str() {
90            "INTEGER" | "INT" | "BIGINT" | "SMALLINT" | "TINYINT" | "SERIAL" | "BIGSERIAL" => ColumnType::Integer,
91            "REAL" | "FLOAT" | "DOUBLE" | "NUMERIC" | "DECIMAL" | "DOUBLE PRECISION" => ColumnType::Real,
92            "TEXT" | "VARCHAR" | "CHAR" | "STRING" | "VARCHAR(255)" | "TEXT[]" => ColumnType::Text,
93            "BLOB" | "BINARY" | "BYTEA" | "LONGBLOB" => ColumnType::Blob,
94            _ => ColumnType::Text,
95        }
96    }
97}
98
99/// 列定义
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct ColumnDef {
102    /// 列名
103    pub name: String,
104    /// 列类型
105    pub col_type: ColumnType,
106    /// 是否可空
107    pub nullable: bool,
108    /// 是否主键
109    pub primary_key: bool,
110    /// 是否自增
111    pub auto_increment: bool,
112    /// 默认值
113    pub default_value: Option<String>,
114    /// 是否唯一
115    pub unique: bool,
116}
117
118impl ColumnDef {
119    /// 创建新的列定义
120    pub fn new(name: impl Into<String>, col_type: ColumnType) -> Self {
121        Self {
122            name: name.into(),
123            col_type,
124            nullable: true,
125            primary_key: false,
126            auto_increment: false,
127            default_value: None,
128            unique: false,
129        }
130    }
131
132    /// 设置为不可空
133    pub fn not_null(mut self) -> Self {
134        self.nullable = false;
135        self
136    }
137
138    /// 设置为主键
139    pub fn primary_key(mut self) -> Self {
140        self.primary_key = true;
141        self.nullable = false;
142        self
143    }
144
145    /// 设置为自增
146    pub fn auto_increment(mut self) -> Self {
147        self.auto_increment = true;
148        self
149    }
150
151    /// 设置默认值
152    pub fn default(mut self, value: impl Into<String>) -> Self {
153        self.default_value = Some(value.into());
154        self
155    }
156
157    /// 设置为唯一
158    pub fn unique(mut self) -> Self {
159        self.unique = true;
160        self
161    }
162
163    /// 生成建表 SQL 片段(使用当前数据库类型)
164    pub fn to_sql(&self) -> String {
165        self.to_sql_for(DatabaseType::current())
166    }
167
168    /// 生成指定数据库类型的建表 SQL 片段
169    pub fn to_sql_for(&self, db_type: DatabaseType) -> String {
170        let mut sql = format!("{} {}", self.name, self.col_type.to_sql_for(db_type));
171
172        if self.primary_key {
173            sql.push_str(" PRIMARY KEY");
174        }
175
176        if self.auto_increment {
177            match db_type {
178                DatabaseType::Turso => sql.push_str(" AUTOINCREMENT"),
179                DatabaseType::Postgres => {
180                    if self.primary_key && self.col_type == ColumnType::Integer {
181                        sql = format!("{} SERIAL", self.name);
182                        sql.push_str(" PRIMARY KEY");
183                    }
184                }
185                DatabaseType::MySql => sql.push_str(" AUTO_INCREMENT"),
186            }
187        }
188
189        if !self.nullable && !self.primary_key {
190            sql.push_str(" NOT NULL");
191        }
192
193        if let Some(ref default) = self.default_value {
194            sql.push_str(&format!(" DEFAULT {}", default));
195        }
196
197        if self.unique && !self.primary_key {
198            sql.push_str(" UNIQUE");
199        }
200
201        sql
202    }
203
204    /// 生成 MySQL 建表 SQL 片段
205    #[cfg(feature = "mysql")]
206    pub fn to_mysql_sql(&self) -> String {
207        self.to_sql_for(DatabaseType::MySql)
208    }
209}
210
211/// 索引定义
212#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct IndexDef {
214    /// 索引名称
215    pub name: String,
216    /// 表名
217    pub table_name: String,
218    /// 列名列表
219    pub columns: Vec<String>,
220    /// 是否唯一索引
221    pub unique: bool,
222}
223
224impl IndexDef {
225    /// 创建新的索引定义
226    pub fn new(name: impl Into<String>, table_name: impl Into<String>, columns: Vec<String>) -> Self {
227        Self { name: name.into(), table_name: table_name.into(), columns, unique: false }
228    }
229
230    /// 设置为唯一索引
231    pub fn unique(mut self) -> Self {
232        self.unique = true;
233        self
234    }
235
236    /// 生成创建索引 SQL(使用当前数据库类型)
237    pub fn to_create_sql(&self) -> String {
238        self.to_create_sql_for(DatabaseType::current())
239    }
240
241    /// 生成创建索引 SQL(指定数据库类型)
242    pub fn to_create_sql_for(&self, db_type: DatabaseType) -> String {
243        let unique_str = if self.unique { "UNIQUE " } else { "" };
244        let columns = self.columns.join(", ");
245        match db_type {
246            DatabaseType::Turso | DatabaseType::Postgres => {
247                format!("CREATE {}INDEX {} ON {} ({})", unique_str, self.name, self.table_name, columns)
248            }
249            DatabaseType::MySql => {
250                format!("CREATE {}INDEX {} ON {} ({})", unique_str, self.name, self.table_name, columns)
251            }
252        }
253    }
254
255    /// 生成删除索引 SQL
256    pub fn to_drop_sql(&self) -> String {
257        format!("DROP INDEX IF EXISTS {}", self.name)
258    }
259}
260
261/// 数据库 schema 定义
262#[derive(Debug, Clone, Serialize, Deserialize)]
263pub struct DatabaseSchema {
264    /// 数据库名称
265    pub name: String,
266    /// 数据库类型
267    pub r#type: DatabaseType,
268    /// 数据库连接字符串(可以直接包含密码)
269    pub url: Option<String>,
270    /// 环境变量名称(用于从环境变量获取连接字符串)
271    pub env: Option<String>,
272    /// 该数据库下的表结构列表
273    pub schemas: Vec<TableSchema>,
274}
275
276impl DatabaseSchema {
277    /// 创建新的数据库 schema
278    pub fn new(name: impl Into<String>, db_type: DatabaseType) -> Self {
279        Self { name: name.into(), r#type: db_type, url: None, env: None, schemas: Vec::new() }
280    }
281
282    /// 设置数据库连接 URL
283    pub fn url(mut self, url: impl Into<String>) -> Self {
284        self.url = Some(url.into());
285        self
286    }
287
288    /// 设置环境变量名称
289    pub fn env(mut self, env: impl Into<String>) -> Self {
290        self.env = Some(env.into());
291        self
292    }
293
294    /// 添加表结构
295    pub fn schema(mut self, schema: TableSchema) -> Self {
296        self.schemas.push(schema);
297        self
298    }
299
300    /// 获取数据库连接字符串
301    pub fn get_url(&self) -> Result<String, Box<dyn std::error::Error>> {
302        if let Some(url) = &self.url {
303            Ok(url.clone())
304        }
305        else if let Some(env_name) = &self.env {
306            std::env::var(env_name).map_err(|e| format!("Failed to read environment variable {}: {}", env_name, e).into())
307        }
308        else {
309            Err("No database URL or environment variable specified".into())
310        }
311    }
312}
313
314/// 表结构定义
315#[derive(Debug, Clone, Serialize, Deserialize)]
316pub struct TableSchema {
317    /// 表名
318    pub name: String,
319    /// 列定义列表
320    pub columns: Vec<ColumnDef>,
321    /// 索引定义列表
322    pub indexes: Vec<IndexDef>,
323    /// 外键约束列表
324    pub foreign_keys: Vec<ForeignKeyDef>,
325}
326
327impl TableSchema {
328    /// 创建新的表结构
329    pub fn new(name: impl Into<String>) -> Self {
330        Self { name: name.into(), columns: Vec::new(), indexes: Vec::new(), foreign_keys: Vec::new() }
331    }
332
333    /// 添加列
334    pub fn column(mut self, col: ColumnDef) -> Self {
335        self.columns.push(col);
336        self
337    }
338
339    /// 添加索引
340    pub fn index(mut self, idx: IndexDef) -> Self {
341        self.indexes.push(idx);
342        self
343    }
344
345    /// 添加外键约束
346    pub fn foreign_key(mut self, fk: ForeignKeyDef) -> Self {
347        self.foreign_keys.push(fk);
348        self
349    }
350
351    /// 生成删表 SQL
352    pub fn to_drop_sql(&self) -> String {
353        format!("DROP TABLE IF EXISTS {}", self.name)
354    }
355
356    /// 获取主键列
357    pub fn primary_key(&self) -> Option<&ColumnDef> {
358        self.columns.iter().find(|c| c.primary_key)
359    }
360
361    /// 根据名称获取列
362    pub fn get_column(&self, name: &str) -> Option<&ColumnDef> {
363        self.columns.iter().find(|c| c.name == name)
364    }
365}
366
367/// 外键定义
368#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct ForeignKeyDef {
370    /// 外键名称
371    pub name: String,
372    /// 本表列名
373    pub column: String,
374    /// 引用表名
375    pub ref_table: String,
376    /// 引用列名
377    pub ref_column: String,
378    /// 更新行为
379    pub on_update: ReferentialAction,
380    /// 删除行为
381    pub on_delete: ReferentialAction,
382}
383
384impl ForeignKeyDef {
385    /// 创建新的外键定义
386    pub fn new(
387        name: impl Into<String>,
388        column: impl Into<String>,
389        ref_table: impl Into<String>,
390        ref_column: impl Into<String>,
391    ) -> Self {
392        Self {
393            name: name.into(),
394            column: column.into(),
395            ref_table: ref_table.into(),
396            ref_column: ref_column.into(),
397            on_update: ReferentialAction::NoAction,
398            on_delete: ReferentialAction::NoAction,
399        }
400    }
401
402    /// 设置更新时的引用行为
403    pub fn on_update(mut self, action: ReferentialAction) -> Self {
404        self.on_update = action;
405        self
406    }
407
408    /// 设置删除时的引用行为
409    pub fn on_delete(mut self, action: ReferentialAction) -> Self {
410        self.on_delete = action;
411        self
412    }
413
414    /// 生成约束 SQL 片段
415    pub fn to_constraint_sql(&self) -> String {
416        format!(
417            "CONSTRAINT {} FOREIGN KEY ({}) REFERENCES {} ({}) ON UPDATE {} ON DELETE {}",
418            self.name,
419            self.column,
420            self.ref_table,
421            self.ref_column,
422            self.on_update.to_sql(),
423            self.on_delete.to_sql()
424        )
425    }
426
427    /// 生成添加外键约束 SQL
428    pub fn to_add_sql(&self, table_name: &str) -> String {
429        format!("ALTER TABLE {} ADD {}", table_name, self.to_constraint_sql())
430    }
431
432    /// 生成删除外键约束 SQL
433    pub fn to_drop_sql(&self, table_name: &str) -> String {
434        format!("ALTER TABLE {} DROP CONSTRAINT {}", table_name, self.name)
435    }
436}
437
438/// 外键引用行为
439#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
440pub enum ReferentialAction {
441    /// 无操作
442    NoAction,
443    /// 限制
444    Restrict,
445    /// 级联
446    Cascade,
447    /// 设为空
448    SetNull,
449    /// 设为默认值
450    SetDefault,
451}
452
453impl ReferentialAction {
454    /// 转换为 SQL
455    pub fn to_sql(&self) -> &'static str {
456        match self {
457            ReferentialAction::NoAction => "NO ACTION",
458            ReferentialAction::Restrict => "RESTRICT",
459            ReferentialAction::Cascade => "CASCADE",
460            ReferentialAction::SetNull => "SET NULL",
461            ReferentialAction::SetDefault => "SET DEFAULT",
462        }
463    }
464}
465
466/// 完整的 schema 配置(包含多个数据库)
467#[derive(Debug, Clone, Serialize, Deserialize)]
468pub struct SchemaConfig {
469    /// 数据库列表
470    pub databases: Vec<DatabaseSchema>,
471    /// 默认数据库名称(可选,不指定则使用第一个数据库)
472    pub default_database: Option<String>,
473}
474
475impl SchemaConfig {
476    /// 创建新的 schema 配置
477    pub fn new() -> Self {
478        Self { databases: Vec::new(), default_database: None }
479    }
480
481    /// 添加数据库
482    pub fn database(mut self, database: DatabaseSchema) -> Self {
483        self.databases.push(database);
484        self
485    }
486
487    /// 设置默认数据库
488    pub fn default_database(mut self, name: impl Into<String>) -> Self {
489        self.default_database = Some(name.into());
490        self
491    }
492
493    /// 获取默认数据库
494    pub fn get_default_database(&self) -> Option<&DatabaseSchema> {
495        if let Some(default_name) = &self.default_database {
496            self.databases.iter().find(|db| db.name == *default_name)
497        }
498        else {
499            self.databases.first()
500        }
501    }
502
503    /// 根据名称获取数据库
504    pub fn get_database(&self, name: &str) -> Option<&DatabaseSchema> {
505        self.databases.iter().find(|db| db.name == name)
506    }
507}
508
509/// 数据库链接配置(保留向后兼容)
510#[derive(Debug, Clone, Serialize, Deserialize)]
511pub struct DatabaseLinkConfig {
512    /// 数据库类型
513    pub r#type: DatabaseType,
514    /// 数据库连接字符串(可以直接包含密码)
515    pub url: Option<String>,
516    /// 环境变量名称(用于从环境变量获取连接字符串)
517    pub env: Option<String>,
518}
519
520impl DatabaseLinkConfig {
521    /// 获取数据库连接字符串
522    pub fn get_url(&self) -> Result<String, Box<dyn std::error::Error>> {
523        if let Some(url) = &self.url {
524            Ok(url.clone())
525        }
526        else if let Some(env_name) = &self.env {
527            std::env::var(env_name).map_err(|e| format!("Failed to read environment variable {}: {}", env_name, e).into())
528        }
529        else {
530            Err("No database URL or environment variable specified".into())
531        }
532    }
533}
534
535/// 列类型快捷构造函数
536pub mod col {
537    use super::{ColumnDef, ColumnType};
538
539    /// 创建整数列
540    pub fn integer(name: &str) -> ColumnDef {
541        ColumnDef::new(name, ColumnType::Integer)
542    }
543
544    /// 创建浮点列
545    pub fn real(name: &str) -> ColumnDef {
546        ColumnDef::new(name, ColumnType::Real)
547    }
548
549    /// 创建文本列
550    pub fn text(name: &str) -> ColumnDef {
551        ColumnDef::new(name, ColumnType::Text)
552    }
553
554    /// 创建二进制列
555    pub fn blob(name: &str) -> ColumnDef {
556        ColumnDef::new(name, ColumnType::Blob)
557    }
558
559    /// 创建主键列 (自增整数)
560    pub fn id(name: &str) -> ColumnDef {
561        ColumnDef::new(name, ColumnType::Integer).primary_key().auto_increment()
562    }
563
564    /// 创建布尔列
565    pub fn boolean(name: &str) -> ColumnDef {
566        ColumnDef::new(name, ColumnType::Integer).default("0")
567    }
568
569    /// 创建时间戳列
570    pub fn timestamp(name: &str) -> ColumnDef {
571        ColumnDef::new(name, ColumnType::Text)
572    }
573
574    /// 创建 JSON 列
575    pub fn json(name: &str) -> ColumnDef {
576        ColumnDef::new(name, ColumnType::Text)
577    }
578}
579
580/// 全局 Schema 注册表
581static SCHEMA_REGISTRY: Lazy<Mutex<HashMap<String, TableSchema>>> = Lazy::new(|| Mutex::new(HashMap::new()));
582
583/// 注册 TableSchema 到全局注册表
584pub fn register_schema(schema: TableSchema) {
585    let mut registry = SCHEMA_REGISTRY.lock().unwrap();
586    registry.insert(schema.name.clone(), schema);
587}
588
589/// 批量注册 TableSchema 到全局注册表
590pub fn register_schemas(schemas: Vec<TableSchema>) {
591    let mut registry = SCHEMA_REGISTRY.lock().unwrap();
592    for schema in schemas {
593        registry.insert(schema.name.clone(), schema);
594    }
595}
596
597/// 获取所有已注册的 TableSchema
598pub fn get_registered_schemas() -> Vec<TableSchema> {
599    let registry = SCHEMA_REGISTRY.lock().unwrap();
600    registry.values().cloned().collect()
601}
602
603/// 获取指定名称的 TableSchema
604pub fn get_schema(name: &str) -> Option<TableSchema> {
605    let registry = SCHEMA_REGISTRY.lock().unwrap();
606    registry.get(name).cloned()
607}
608
609/// 清空注册表
610pub fn clear_schemas() {
611    let mut registry = SCHEMA_REGISTRY.lock().unwrap();
612    registry.clear();
613}
614
615/// 将所有已注册的 TableSchema 导出为 YAML 字符串
616pub fn export_schemas_to_yaml() -> String {
617    let schemas = get_registered_schemas();
618    serde_yaml::to_string(&schemas).unwrap_or_else(|e| format!("# Error: {}", e))
619}
620
621/// 将所有已注册的 TableSchema 导出到 YAML 文件
622#[cfg(debug_assertions)]
623pub fn export_schemas_to_yaml_file(path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
624    use std::{fs::File, io::Write};
625
626    let yaml = export_schemas_to_yaml();
627    let mut file = File::create(path)?;
628    file.write_all(yaml.as_bytes())?;
629    Ok(())
630}
631
632/// 在 debug 模式下自动导出 schema 到默认路径
633#[cfg(debug_assertions)]
634pub fn auto_export_schemas() {
635    let path = std::path::Path::new("schemas.yaml");
636    if let Err(e) = export_schemas_to_yaml_file(path) {
637        eprintln!("Warning: Failed to export schemas: {}", e);
638    }
639    else {
640        println!("Schemas exported to: {}", path.display());
641    }
642}
643
644impl TableSchema {
645    /// 注册当前 TableSchema 到全局注册表
646    pub fn register(self) -> Self {
647        let name = self.name.clone();
648        register_schema(self);
649        get_schema(&name).unwrap()
650    }
651
652    /// 将当前 TableSchema 导出为 YAML 字符串
653    pub fn to_yaml(&self) -> String {
654        serde_yaml::to_string(self).unwrap_or_else(|e| format!("# Error: {}", e))
655    }
656
657    /// 生成建表 SQL(使用当前数据库类型)
658    pub fn to_create_sql(&self) -> String {
659        self.to_create_sql_for(DatabaseType::current())
660    }
661
662    /// 生成指定数据库类型的建表 SQL
663    pub fn to_create_sql_for(&self, db_type: DatabaseType) -> String {
664        let mut parts: Vec<String> = self.columns.iter().map(|c| c.to_sql_for(db_type)).collect();
665        for fk in &self.foreign_keys {
666            parts.push(fk.to_constraint_sql());
667        }
668        match db_type {
669            DatabaseType::Turso | DatabaseType::Postgres => {
670                format!("CREATE TABLE {} ({})", self.name, parts.join(", "))
671            }
672            DatabaseType::MySql => {
673                format!("CREATE TABLE {} ({}) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", self.name, parts.join(", "))
674            }
675        }
676    }
677
678    /// 生成 MySQL 建表 SQL
679    #[cfg(feature = "mysql")]
680    pub fn to_mysql_create_sql(&self) -> String {
681        self.to_create_sql_for(DatabaseType::MySql)
682    }
683
684    /// 生成所有创建索引的 SQL(使用当前数据库类型)
685    pub fn to_create_indexes_sql(&self) -> Vec<String> {
686        self.to_create_indexes_sql_for(DatabaseType::current())
687    }
688
689    /// 生成所有创建索引的 SQL(指定数据库类型)
690    pub fn to_create_indexes_sql_for(&self, db_type: DatabaseType) -> Vec<String> {
691        self.indexes.iter().map(|idx| idx.to_create_sql_for(db_type)).collect()
692    }
693
694    /// 生成完整的建表和索引 SQL(使用当前数据库类型)
695    pub fn to_full_create_sql(&self) -> Vec<String> {
696        self.to_full_create_sql_for(DatabaseType::current())
697    }
698
699    /// 生成完整的建表和索引 SQL(指定数据库类型)
700    pub fn to_full_create_sql_for(&self, db_type: DatabaseType) -> Vec<String> {
701        let mut sqls = vec![self.to_create_sql_for(db_type)];
702        sqls.extend(self.to_create_indexes_sql_for(db_type));
703        sqls
704    }
705}
706
707/// 从 YAML 字符串解析 SchemaConfig
708pub fn load_schema_config_from_yaml(yaml_str: &str) -> Result<SchemaConfig, serde_yaml::Error> {
709    serde_yaml::from_str(yaml_str)
710}
711
712/// 从 YAML 文件加载 SchemaConfig
713pub fn load_schema_config_from_yaml_file(path: impl AsRef<Path>) -> Result<SchemaConfig, Box<dyn std::error::Error>> {
714    let content = fs::read_to_string(path)?;
715    let config = load_schema_config_from_yaml(&content)?;
716    Ok(config)
717}
718
719/// 从 YAML 字符串解析 TableSchema 列表(兼容旧格式)
720pub fn load_schemas_from_yaml(yaml_str: &str) -> Result<Vec<TableSchema>, serde_yaml::Error> {
721    serde_yaml::from_str(yaml_str)
722}
723
724/// 从 YAML 文件加载 TableSchema 列表(兼容旧格式)
725pub fn load_schemas_from_yaml_file(path: impl AsRef<Path>) -> Result<Vec<TableSchema>, Box<dyn std::error::Error>> {
726    let content = fs::read_to_string(path)?;
727    let schemas = load_schemas_from_yaml(&content)?;
728    Ok(schemas)
729}
730
731/// 从 YAML 文件加载并注册所有 TableSchema(兼容旧格式)
732pub fn load_and_register_schemas_from_yaml_file(path: impl AsRef<Path>) -> Result<(), Box<dyn std::error::Error>> {
733    let schemas = load_schemas_from_yaml_file(path)?;
734    register_schemas(schemas);
735    Ok(())
736}
737
738/// 将 SchemaConfig 导出为 YAML 字符串
739pub fn export_schema_config_to_yaml(config: &SchemaConfig) -> String {
740    serde_yaml::to_string(config).unwrap_or_else(|e| format!("# Error: {}", e))
741}
742
743/// 将 SchemaConfig 导出到 YAML 文件
744pub fn export_schema_config_to_yaml_file(config: &SchemaConfig, path: impl AsRef<Path>) -> std::io::Result<()> {
745    use std::{fs::File, io::Write};
746
747    let yaml = export_schema_config_to_yaml(config);
748    let mut file = File::create(path)?;
749    file.write_all(yaml.as_bytes())?;
750    Ok(())
751}
752
753/// 从已注册的 schemas 创建 SchemaConfig(将所有表放在默认数据库中)
754pub fn create_schema_config_from_registered(default_db: DatabaseSchema, default_database: Option<String>) -> SchemaConfig {
755    let schemas = get_registered_schemas();
756    let mut default_db = default_db;
757    default_db.schemas = schemas;
758    SchemaConfig { databases: vec![default_db], default_database }
759}
760
761/// 为所有已注册的 schema 生成完整的 SQL(使用当前数据库类型)
762pub fn generate_full_sql_for_registered_schemas() -> Vec<String> {
763    generate_full_sql_for_registered_schemas_for(DatabaseType::current())
764}
765
766/// 为所有已注册的 schema 生成完整的 SQL(指定数据库类型)
767pub fn generate_full_sql_for_registered_schemas_for(db_type: DatabaseType) -> Vec<String> {
768    let schemas = get_registered_schemas();
769    let mut all_sql = Vec::new();
770    for schema in schemas {
771        all_sql.extend(schema.to_full_create_sql_for(db_type));
772    }
773    all_sql
774}
775
776/// 导出所有数据库类型的 SQL 到文件
777#[cfg(debug_assertions)]
778pub fn export_sql_for_all_databases(output_dir: impl AsRef<Path>) -> Result<(), Box<dyn std::error::Error>> {
779    let output_dir = output_dir.as_ref();
780    fs::create_dir_all(output_dir)?;
781
782    let db_types = [DatabaseType::Turso, DatabaseType::Postgres, DatabaseType::MySql];
783
784    for &db_type in &db_types {
785        let sqls = generate_full_sql_for_registered_schemas_for(db_type);
786        let db_name = match db_type {
787            DatabaseType::Turso => "turso",
788            DatabaseType::Postgres => "postgres",
789            DatabaseType::MySql => "mysql",
790        };
791        let file_path = output_dir.join(format!("schema_{}.sql", db_name));
792        let content = sqls.join(";\n\n") + ";\n";
793        fs::write(&file_path, content)?;
794        println!("Exported SQL for {} to: {}", db_name, file_path.display());
795    }
796
797    Ok(())
798}