Skip to content

Commit

Permalink
feat: add sqlx drivers, add connection struct
Browse files Browse the repository at this point in the history
  • Loading branch information
invm committed Jul 9, 2023
1 parent bd9726c commit 5595118
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 43 deletions.
33 changes: 17 additions & 16 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
volumes:
psql15:
mysql8:
mysql:
# psql:

services:
psql15:
image: postgres:15
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: example
POSTGRES_DB: noir
volumes:
- psql15:/var/lib/postgresql/data
ports:
- 5432:5432
mysql8:
mysql:
image: mysql:8.0.33
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: noir
MYSQL_DATABASE: noir
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: world_x
ports:
- 3306:3306
volumes:
- mysql8:/var/lib/mysql
- mysql:/var/lib/mysql
- ./dev/:/docker-entrypoint-initdb.d
# psql:
# image: postgres:15
# environment:
# POSTGRES_USER: postgres
# POSTGRES_PASSWORD: example
# POSTGRES_DB: noir
# volumes:
# - psql:/var/lib/postgresql/data
# ports:
# - 5432:5432
1 change: 1 addition & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ tauri = { version = "1.4", features = [ "shell-open"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rusqlite = { version = "0.29.0", features = ["bundled", "uuid"] }
sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-rustls" ] }
sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-rustls", "mysql", "sqlite", "postgres" ] }
simplecrypt = "1.0.2"
anyhow = "1.0.71"
log = "0.4.19"
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fn main() {
}))
.manage(AppState {
db: Default::default(),
connections: Default::default(),
})
.setup(|app| {
init::init_app()?;
Expand Down
90 changes: 84 additions & 6 deletions src-tauri/src/database/connections.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
use anyhow::Result;
use rusqlite::{named_params, Connection};
use serde::{Deserialize, Serialize};
use sqlx::mysql::MySqlPoolOptions;
use std::path::PathBuf;
use uuid::Uuid;

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum BaseConnectionMode {
Host(HostCredentials),
Socket(SocketCredentials),
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum FileConnectionMode {
File(PathBuf),
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum Scheme {
Mysql(BaseConnectionMode),
Postgres(BaseConnectionMode),
Sqlite(FileConnectionMode),
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct SocketCredentials {
pub username: String,
pub password: Option<String>,
pub path: PathBuf,
pub dbname: String,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct HostCredentials {
pub username: String,
pub password: Option<String>,
Expand All @@ -39,14 +40,27 @@ pub struct HostCredentials {
pub dbname: String,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct ConnectionConfig {
pub id: Uuid,
pub scheme: Scheme,
pub name: String,
pub color: String,
}

#[derive(Debug, Clone)]
pub enum Pool {
Mysql(sqlx::Pool<sqlx::MySql>),
Postgres(sqlx::Pool<sqlx::Postgres>),
Sqlite(sqlx::Pool<sqlx::Sqlite>),
}

#[derive(Debug, Clone)]
pub struct ConnectedConnection {
pub config: ConnectionConfig,
pub pool: Pool,
}

impl TryFrom<&str> for Scheme {
type Error = anyhow::Error;

Expand Down Expand Up @@ -78,6 +92,70 @@ impl ConnectionConfig {
color: color.to_string(),
})
}

pub fn to_dsn(&self) -> String {
match &self.scheme {
Scheme::Mysql(BaseConnectionMode::Host(host)) => {
format!(
"mysql://{}:{}@{}:{}/{}",
host.username,
host.password.clone().unwrap_or_default(),
host.host,
host.port,
host.dbname
)
}
Scheme::Mysql(BaseConnectionMode::Socket(socket)) => {
format!(
"mysql://{}:{}@{}",
socket.username,
socket.password.clone().unwrap_or_default(),
socket.path.display()
)
}
Scheme::Postgres(BaseConnectionMode::Host(host)) => {
format!(
"postgres://{}:{}@{}:{}/{}",
host.username,
host.password.clone().unwrap_or_default(),
host.host,
host.port,
host.dbname
)
}
Scheme::Postgres(BaseConnectionMode::Socket(socket)) => {
format!(
"postgres://{}:{}@{}",
socket.username,
socket.password.clone().unwrap_or_default(),
socket.path.display()
)
}
Scheme::Sqlite(FileConnectionMode::File(path)) => {
format!("sqlite://{}", path.display())
}
}
}
}

impl ConnectedConnection {
pub async fn new(config: ConnectionConfig) -> Result<Self> {
match &config.scheme {
Scheme::Mysql(BaseConnectionMode::Host(_)) => {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect(&config.to_dsn())
.await?;
return Ok(ConnectedConnection {
config,
pool: Pool::Mysql(pool),
});
}
Scheme::Mysql(BaseConnectionMode::Socket(_)) => todo!(),
Scheme::Postgres(_) => todo!(),
Scheme::Sqlite(_) => todo!(),
}
}
}

pub fn add_connection(db: &Connection, conn: &ConnectionConfig) -> Result<()> {
Expand Down
12 changes: 11 additions & 1 deletion src-tauri/src/handlers/queries.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::utils::error::CommandResult;
use crate::{database::connections::ConnectionConfig, utils::error::CommandResult};
use log::info;
use tauri::{command, AppHandle};

Expand All @@ -8,3 +8,13 @@ pub fn execute_query(_app_handle: AppHandle, query: String) -> CommandResult<()>
println!("{}", sql_lexer::sanitize_string(query.to_string()));
Ok(())
}

#[command]
pub fn ping_db(_app_handle: AppHandle, _conn: ConnectionConfig) -> CommandResult<()> {
Ok(())
}

#[command]
pub fn init_db(_app_handle: AppHandle, _conn: ConnectionConfig) -> CommandResult<()> {
Ok(())
}
61 changes: 42 additions & 19 deletions src-tauri/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,53 @@
use rusqlite::Connection;
use tauri::{AppHandle, State, Manager};
use std::sync::Mutex;
use tauri::{AppHandle, Manager, State};

use crate::database::connections::ConnectedConnection;

pub struct AppState {
pub db: std::sync::Mutex<Option<Connection>>,
pub db: Mutex<Option<Connection>>,
pub connections: Mutex<Vec<ConnectedConnection>>,
}

pub trait ServiceAccess {
fn db<F, TResult>(&self, operation: F) -> TResult where F: FnOnce(&Connection) -> TResult;
fn db<F, TResult>(&self, operation: F) -> TResult
where
F: FnOnce(&Connection) -> TResult;

fn db_mut<F, TResult>(&self, operation: F) -> TResult
where
F: FnOnce(&mut Connection) -> TResult;

fn db_mut<F, TResult>(&self, operation: F) -> TResult where F: FnOnce(&mut Connection) -> TResult;
fn connections<F, TResult>(&self) -> Mutex<Vec<ConnectedConnection>>;
}

impl ServiceAccess for AppHandle {
fn db<F, TResult>(&self, operation: F) -> TResult where F: FnOnce(&Connection) -> TResult {
let app_state: State<AppState> = self.state();
let db_connection_guard = app_state.db.lock().unwrap();
let db = db_connection_guard.as_ref().unwrap();

operation(db)
}

fn db_mut<F, TResult>(&self, operation: F) -> TResult where F: FnOnce(&mut Connection) -> TResult {
let app_state: State<AppState> = self.state();
let mut db_connection_guard = app_state.db.lock().unwrap();
let db = db_connection_guard.as_mut().unwrap();

operation(db)
}
fn db<F, TResult>(&self, operation: F) -> TResult
where
F: FnOnce(&Connection) -> TResult,
{
let app_state: State<AppState> = self.state();
let db_connection_guard = app_state.db.lock().unwrap();
let db = db_connection_guard.as_ref().unwrap();

operation(db)
}

fn db_mut<F, TResult>(&self, operation: F) -> TResult
where
F: FnOnce(&mut Connection) -> TResult,
{
let app_state: State<AppState> = self.state();
let mut db_connection_guard = app_state.db.lock().unwrap();
let db = db_connection_guard.as_mut().unwrap();

operation(db)
}

fn connections<F, TResult>(&self) -> Mutex<Vec<ConnectedConnection>> {
let app_state: State<AppState> = self.state();
let connections_guard = app_state.connections.lock().unwrap();

connections_guard.clone().into()
}
}

0 comments on commit 5595118

Please sign in to comment.