Skip to main content

db_cores/common/
db.rs

1
2use serde::{Deserialize, Deserializer, Serialize};
3use serde_json::{ Value as JsonValue};
4use std::path::PathBuf;
5use crate::DatabaseKind;
6
7
8#[derive(Debug, Serialize, Deserialize, Clone)]
9pub struct OthersRes<T> {
10    pub rows_affected: u64,
11    pub sql: Option<String>,
12    pub results: Option<Vec<T>>,
13}
14impl<T> Default for OthersRes<T> {
15    fn default() -> Self {
16        Self {
17            rows_affected: 0,
18            results: None,
19            sql: None,
20        }
21    }
22}
23impl<T> OthersRes<T> {
24    pub fn new(rows_affected: u64) -> Self {
25        Self {
26            rows_affected,
27            results: None,
28            sql: None,
29        }
30    }
31    pub fn with(data: Vec<T>, rows_affected: usize) -> Self {
32        Self {
33            rows_affected: rows_affected as u64,
34            results: Some(data),
35            sql: None,
36        }
37    }
38}
39
40#[derive(Debug, Serialize, Deserialize, Clone)]
41pub struct ColumnBaseInfo {
42    pub name: String,
43    #[serde(rename = "type")]
44    pub r#type: String,
45    pub index: u64,
46}
47
48#[derive(Debug, Serialize, Deserialize, Clone)]
49pub struct SelectRes<T> {
50    pub results: Vec<T>,
51    pub length: usize,
52    pub count: usize,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub sql: Option<String>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub columns: Option<Vec<ColumnBaseInfo>>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub table_name: Option<String>,
59}
60impl<T> Default for SelectRes<T> {
61    fn default() -> Self {
62        Self {
63            results: Vec::new(),
64            length: 0,
65            count: 0,
66            sql: None,
67            columns: None,
68            table_name: None,
69        }
70    }
71}
72impl<T> SelectRes<T> {
73    pub fn new(
74        results: Vec<T>,
75        count: usize,
76        columns: Option<Vec<ColumnBaseInfo>>,
77        sql: Option<String>,
78    ) -> Self {
79        let length = results.len();
80        Self {
81            results,
82            length,
83            count,
84            sql,
85            columns,
86            table_name: None,
87        }
88    }
89}
90
91#[derive(Debug, Serialize, Deserialize, Clone, Default)]
92pub struct SqlRespone {
93    pub length: u64,        // 返回的数据长度
94    pub rows_affected: u64, // 影响行数
95    pub count: u64,
96    pub results: Option<Vec<JsonValue>>, // 返回的数据
97    pub columns: Option<Vec<ColumnBaseInfo>>,
98    pub is_query: bool,
99    pub sql: Option<String>,
100    pub table_name: Option<String>,
101}
102
103#[derive(Debug)]
104#[cfg_attr(any(feature = "postgres", feature = "mysql", feature = "sqlite"), derive(sqlx::FromRow))]
105pub struct DataCount {
106    pub count: u32,
107}
108
109#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
110#[cfg_attr(any(feature = "postgres", feature = "mysql", feature = "sqlite"), derive(sqlx::FromRow))]
111pub struct TableColumn {
112    pub name: String,
113    pub ordinal_position: i32, // 所有数据库统一使用从 1 开始的字段顺序,sqlite中对应 cid
114    #[serde(rename = "type")]
115    pub r#type: String,
116    pub base_type: Option<String>,          // 原始类型字符串,便于调试
117    pub foreign_key_table: Option<String>,  // 外键引用的表
118    pub foreign_key_column: Option<String>, // 外键引用的字段
119
120    #[serde(deserialize_with = "bool_or_int_to_bool")]
121    pub auto_increment: bool, // 是否自增
122    #[serde(deserialize_with = "bool_or_int_to_bool")]
123    pub not_null: bool, // 是否非空
124    pub dflt_value: Option<String>, // 默认值
125    #[serde(deserialize_with = "bool_or_int_to_bool")]
126    pub pk: bool, // 是否主键
127    pub index_name: Option<String>, // 索引名称
128    #[serde(deserialize_with = "bool_or_int_to_bool")]
129    pub non_unique: bool, // 是否唯一索引
130    pub description: Option<String>, // 字段注释
131}
132
133fn bool_or_int_to_bool<'de, D>(deserializer: D) -> std::result::Result<bool, D::Error>
134where
135    D: Deserializer<'de>,
136{
137    // 尝试反序列化为 JsonValue
138    let v = JsonValue::deserialize(deserializer)?;
139    // println!("bool_or_int_to_bool:{:#?}",v);
140    match v {
141        JsonValue::Bool(b) => Ok(b), // 如果是布尔值直接返回
142        JsonValue::Number(n) => {
143            // 如果是数字,检查是否是 1 或 0
144            if let Some(i) = n.as_i64() {
145                match i {
146                    1 => Ok(true),
147                    0 => Ok(false),
148                    _ => Err(serde::de::Error::invalid_value(
149                        serde::de::Unexpected::Signed(i),
150                        &"expected 1 or 0 for boolean value",
151                    )),
152                }
153            } else {
154                Err(serde::de::Error::invalid_type(
155                    serde::de::Unexpected::Other("non-integer number"),
156                    &"expected integer 1 or 0 for boolean value",
157                ))
158            }
159        }
160        _ => Err(serde::de::Error::invalid_type(
161            serde::de::Unexpected::Other("unexpected value"),
162            &"expected boolean or integer 1/0",
163        )),
164    }
165}
166// 自定义反序列化函数
167
168#[derive(Debug, Serialize, Deserialize, Clone)]
169pub struct DbConnect {
170    pub kind: DatabaseKind,
171    #[serde(default = "DbConnect::default_empty")]
172    pub host: String,
173    pub port: i64,
174    #[serde(default = "DbConnect::default_empty")]
175    pub username: String,
176    #[serde(default = "DbConnect::default_empty")]
177    pub password: String,
178    #[serde(default = "DbConnect::default_empty")]
179    pub db_name: String,
180    #[serde(default = "DbConnect::default_empty")]
181    pub charset: String,
182    pub ssl_mode: Option<String>,
183    pub ca_cert: Option<String>,
184    pub client_cert: Option<String>,
185    pub client_key: Option<String>,
186    pub max_connections: Option<i64>,
187    pub min_connections: Option<i64>,
188    pub timeout: Option<i64>,
189    pub service_name: Option<String>,
190    pub instance: Option<String>,
191
192    pub file_dir: PathBuf,
193    pub file_path: PathBuf,
194    pub http: Option<String>,
195    pub region: Option<String>,
196    pub api: Option<String>,
197    pub api_token: Option<String>,
198}
199
200impl Default for DbConnect {
201    fn default() -> Self {
202        Self {
203            kind: DatabaseKind::Postgres,
204            host: "127.0.0.1".to_string(),
205            port: 5432,
206            username: "postgres".to_string(),
207            password: "postgres".to_string(),
208            db_name: "".to_string(),
209            charset: "".to_string(),
210            ssl_mode: None,
211            ca_cert: None,
212            client_cert: None,
213            client_key: None,
214            max_connections: None,
215            min_connections: None,
216            timeout: None,
217            service_name: None,
218            instance: None,
219            file_dir: PathBuf::new(),
220            file_path: PathBuf::new(),
221            http: None,
222            region: None,
223            api: None,
224            api_token: None,
225        }
226    }
227}
228
229impl DbConnect {
230    fn default_empty() -> String {
231        String::new()
232    }
233    /// 比较并更新,如果有字段更改则返回 true,没有更改返回 false
234    pub fn merge_with_changes(&mut self, new_connect: &DbConnect) -> bool {
235        let mut changed = false;
236        if self.host != new_connect.host {
237            self.host = new_connect.host.clone();
238            changed = true
239        }
240        if self.port != new_connect.port {
241            self.port = new_connect.port;
242            changed = true
243        }
244        if self.username != new_connect.username {
245            self.username = new_connect.username.clone();
246            changed = true
247        }
248        if self.password != new_connect.password {
249            self.password = new_connect.password.clone();
250            changed = true
251        }
252        if self.db_name != new_connect.db_name {
253            self.db_name = new_connect.db_name.clone();
254            changed = true
255        }
256        if self.charset != new_connect.charset {
257            self.charset = new_connect.charset.clone();
258            changed = true
259        }
260        if self.file_path != new_connect.file_path {
261            self.file_path = new_connect.file_path.clone();
262            changed = true
263        }
264        if self.file_dir != new_connect.file_dir {
265            self.file_dir = new_connect.file_dir.clone();
266            changed = true
267        }
268        if self.api != new_connect.api {
269            self.api = new_connect.api.clone();
270            changed = true
271        }
272        if self.http != new_connect.http {
273            self.http = new_connect.http.clone();
274            changed = true
275        }
276        // 更新发生,返回 true
277        changed
278    }
279}
280
281#[derive(Serialize, Debug, Deserialize, PartialEq, Eq, Clone)]
282pub struct SchemaInfo {
283    pub name: String,
284    pub tables: Vec<TableInfo>,
285}
286#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
287#[cfg_attr(any(feature = "postgres", feature = "mysql", feature = "sqlite"), derive(sqlx::FromRow))]
288pub struct DatabaseInfo {
289    pub db_name: String,
290    pub tables: Vec<TableInfo>,
291    pub schemas: Vec<SchemaInfo>,
292}
293
294#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
295pub struct TableInfo {
296    pub table_name: String, // 表名
297    #[serde(skip_serializing_if = "Option::is_none")]
298    pub table_comment: Option<String>,
299    pub columns: Vec<TableColumn>, // 字段列表
300    pub create_sql: String,
301}