sqlpage/webserver/database/
mod.rs1pub mod blob_to_data_url;
2mod connect;
3mod csv_import;
4pub mod execute_queries;
5pub mod migrations;
6mod sql;
7mod sqlpage_functions;
8mod syntax_tree;
9
10mod error_highlighting;
11mod sql_to_json;
12
13pub use sql::ParsedSqlFile;
14use sql::{DbPlaceHolder, DB_PLACEHOLDERS};
15use sqlx::any::AnyKind;
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum SupportedDatabase {
21 Sqlite,
22 Postgres,
23 MySql,
24 Mssql,
25 Snowflake,
26 Generic,
27}
28
29impl SupportedDatabase {
30 #[must_use]
32 pub fn from_dbms_name(dbms_name: &str) -> Self {
33 match dbms_name.to_lowercase().as_str() {
34 "sqlite" | "sqlite3" => Self::Sqlite,
35 "postgres" | "postgresql" => Self::Postgres,
36 "mysql" | "mariadb" => Self::MySql,
37 "mssql" | "sql server" | "microsoft sql server" => Self::Mssql,
38 "snowflake" => Self::Snowflake,
39 _ => Self::Generic,
40 }
41 }
42
43 #[must_use]
45 pub fn display_name(self) -> &'static str {
46 match self {
47 Self::Sqlite => "SQLite",
48 Self::Postgres => "PostgreSQL",
49 Self::MySql => "MySQL",
50 Self::Mssql => "Microsoft SQL Server",
51 Self::Snowflake => "Snowflake",
52 Self::Generic => "Generic",
53 }
54 }
55}
56
57pub struct Database {
58 pub connection: sqlx::AnyPool,
59 pub info: DbInfo,
60}
61
62#[derive(Debug, Clone)]
63pub struct DbInfo {
64 pub dbms_name: String,
65 pub database_type: SupportedDatabase,
67 pub kind: AnyKind,
69}
70
71impl Database {
72 pub async fn close(&self) -> anyhow::Result<()> {
73 log::info!("Closing all database connections...");
74 self.connection.close().await;
75 Ok(())
76 }
77}
78
79#[derive(Debug)]
80pub enum DbItem {
81 Row(serde_json::Value),
82 FinishedQuery,
83 Error(anyhow::Error),
84}
85
86impl std::fmt::Display for Database {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 write!(f, "{:?}", self.connection.any_kind())
89 }
90}
91
92#[inline]
93#[must_use]
94pub fn make_placeholder(dbms: AnyKind, arg_number: usize) -> String {
95 if let Some((_, placeholder)) = DB_PLACEHOLDERS.iter().find(|(kind, _)| *kind == dbms) {
96 match *placeholder {
97 DbPlaceHolder::PrefixedNumber { prefix } => format!("{prefix}{arg_number}"),
98 DbPlaceHolder::Positional { placeholder } => placeholder.to_string(),
99 }
100 } else {
101 unreachable!("missing dbms: {dbms:?} in DB_PLACEHOLDERS ({DB_PLACEHOLDERS:?})")
102 }
103}