1use sea_orm::{ConnectionTrait, DatabaseBackend, DatabaseConnection};
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8use tracing::error;
9
10#[derive(Error, Debug)]
12pub enum TableError {
13 #[error("数据库查询失败: {0}")]
14 QueryFailed(String),
15 #[error("表不存在: {0}")]
16 TableNotFound(String),
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct TableInfo {
22 pub table_name: String,
24 pub schema_name: String,
26 pub table_type: String,
28 pub table_comment: Option<String>,
30 pub row_count: Option<u64>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct TableColumnInfo {
37 pub column_name: String,
39 pub data_type: String,
41 pub is_nullable: bool,
43 pub default_value: Option<String>,
45 pub column_comment: Option<String>,
47 pub character_maximum_length: Option<u32>,
49 pub numeric_precision: Option<u32>,
51 pub numeric_scale: Option<u32>,
53 pub is_primary_key: bool,
55}
56
57pub struct TableService;
59
60impl TableService {
61 pub async fn list_tables(
78 db: &DatabaseConnection,
79 schema: Option<&str>,
80 ) -> Result<Vec<TableInfo>, TableError> {
81 let schema_name = schema.unwrap_or("public");
82
83 if schema_name.is_empty() {
85 return Err(TableError::QueryFailed("Schema 名称不能为空".to_string()));
86 }
87
88 let backend = db.get_database_backend();
90 if backend != DatabaseBackend::Postgres {
91 return Err(TableError::QueryFailed(
92 format!("当前仅支持 PostgreSQL 数据库,当前数据库类型: {:?}", backend)
93 ));
94 }
95
96 let _ = db.execute_unprepared("SELECT 1").await.map_err(|e| {
98 TableError::QueryFailed(format!("数据库连接不可用: {}", e))
99 })?;
100
101 Err(TableError::QueryFailed(
104 format!(
105 "表列表查询功能需要 sqlx 连接池支持。\
106 建议:1) 使用 sqlx 连接池直接查询,或 2) 通过数据库管理工具查询。\
107 要查询的 Schema: {}",
108 schema_name
109 )
110 ))
111 }
112
113 pub async fn get_table_info(
125 db: &DatabaseConnection,
126 schema: Option<&str>,
127 table_name: &str,
128 ) -> Result<TableInfo, TableError> {
129 let schema_name = schema.unwrap_or("public");
130
131 if schema_name.is_empty() {
133 return Err(TableError::QueryFailed("Schema 名称不能为空".to_string()));
134 }
135 if table_name.is_empty() {
136 return Err(TableError::QueryFailed("表名称不能为空".to_string()));
137 }
138
139 let backend = db.get_database_backend();
141 if backend != DatabaseBackend::Postgres {
142 return Err(TableError::QueryFailed(
143 format!("当前仅支持 PostgreSQL 数据库,当前数据库类型: {:?}", backend)
144 ));
145 }
146
147 let _ = db.execute_unprepared("SELECT 1").await.map_err(|e| {
149 TableError::QueryFailed(format!("数据库连接不可用: {}", e))
150 })?;
151
152 Err(TableError::QueryFailed(
155 format!(
156 "表信息查询功能需要 sqlx 连接池支持。\
157 建议:1) 使用 sqlx 连接池直接查询,或 2) 通过数据库管理工具查询。\
158 要查询的表: {}.{}",
159 schema_name, table_name
160 )
161 ))
162 }
163
164 pub async fn get_table_columns(
176 db: &DatabaseConnection,
177 schema: Option<&str>,
178 table_name: &str,
179 ) -> Result<Vec<TableColumnInfo>, TableError> {
180 let schema_name = schema.unwrap_or("public");
181
182 if schema_name.is_empty() {
184 return Err(TableError::QueryFailed("Schema 名称不能为空".to_string()));
185 }
186 if table_name.is_empty() {
187 return Err(TableError::QueryFailed("表名称不能为空".to_string()));
188 }
189
190 let backend = db.get_database_backend();
192 if backend != DatabaseBackend::Postgres {
193 return Err(TableError::QueryFailed(
194 format!("当前仅支持 PostgreSQL 数据库,当前数据库类型: {:?}", backend)
195 ));
196 }
197
198 let _ = db.execute_unprepared("SELECT 1").await.map_err(|e| {
200 TableError::QueryFailed(format!("数据库连接不可用: {}", e))
201 })?;
202
203 Err(TableError::QueryFailed(
206 format!(
207 "表列信息查询功能需要 sqlx 连接池支持。\
208 建议:1) 使用 sqlx 连接池直接查询,或 2) 通过数据库管理工具查询。\
209 要查询的表: {}.{}",
210 schema_name, table_name
211 )
212 ))
213 }
214
215 pub async fn table_exists(
217 db: &DatabaseConnection,
218 schema: Option<&str>,
219 table_name: &str,
220 ) -> Result<bool, TableError> {
221 match Self::get_table_info(db, schema, table_name).await {
222 Ok(_) => Ok(true),
223 Err(TableError::TableNotFound(_)) => Ok(false),
224 Err(e) => Err(e),
225 }
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232
233 #[test]
234 fn test_table_info_serialization() {
235 let info = TableInfo {
236 table_name: "test_table".to_string(),
237 schema_name: "public".to_string(),
238 table_type: "BASE TABLE".to_string(),
239 table_comment: Some("测试表".to_string()),
240 row_count: Some(100),
241 };
242
243 let json = serde_json::to_string(&info).unwrap();
244 assert!(json.contains("test_table"));
245 }
246}