前言
这篇就来看看插件sql
SQL | Taurihttps://tauri.app/plugin/sql/
正文
准备
添加依赖
tauri-plugin-sql = {version = "2.2.0",features = ["sqlite"]}
features可以是mysql、sqlite、postsql
进去features看看
sqlite = ["sqlx/sqlite","sqlx/runtime-tokio",
]
可以发现本质使用的是sqlx
sqlx - Rusthttps://docs.rs/sqlx/latest/sqlx/注册插件
.plugin(tauri_plugin_sql::Builder::default().build())
并不像其他插件一样,有init方法,因为需要一些配置,比如连接数据库。
配置
要想配置数据库,如果数据库里面有东西,比如表,需要用到如下函数add_migrations
pub fn add_migrations(mut self,db_url: &str, migrations: Vec<Migration>) -> Self
需要传入db_url和migrations
比如db_url可以设置sqlite:start.db
migrations是个Vec,元素类型是Migration
Migration的定义如下
#[derive(Debug)]
pub struct Migration {pub version: i64,pub description: &'static str,pub sql: &'static str,pub kind: MigrationKind,
}
MigrationKind是指定迁移的类型
#[derive(Debug)]
pub enum MigrationKind {Up,Down,
}
项目结构如下
在migration.rs中
use tauri_plugin_sql::{Migration,MigrationKind};
pub fn get_migration()->Vec<Migration>{vec![// Define your migrations hereMigration {version: 1,description: "Create book table",sql: r"CREATE TABLE book (id INTEGER PRIMARY KEY,author TEXT,title TEXT,published_date date);",kind: MigrationKind::Up,}]
}
创建了一张表
注册
.plugin(tauri_plugin_sql::Builder::default().add_migrations("sqlite:start.db",get_migration()).build())
想要在后端使用
怎么在后端使用,这确实是个问题,笔者发现好像没有在后端使用的东西,全都是前端调用
比如说
pub(crate) async fn connect<R: Runtime>(conn_url: &str,_app: &AppHandle<R>,) -> Result<Self, crate::Error>
按道理来说,connect应该可以使用,但是这是私有的,只在crate内部公开,
笔者也没找到怎么使用,
看看内部的通信函数
#[command]
pub(crate) async fn load<R: Runtime>(app: AppHandle<R>,db_instances: State<'_, DbInstances>,migrations: State<'_, Migrations>,db: String,
) -> Result<String, crate::Error> {let pool = DbPool::connect(&db, &app).await?;if let Some(migrations) = migrations.0.lock().await.remove(&db) {let migrator = Migrator::new(migrations).await?;pool.migrate(&migrator).await?;}db_instances.0.write().await.insert(db.clone(), pool);Ok(db)
}
impl DbPool {pub(crate) async fn connectpub(crate) async fn migratepub(crate) async fn close(&self) pub(crate) async fn execute}
可以看出使用了DbInstances和Migrations,两个State
要先连接 DbPool::connect,但是这个connect没公开,其他方法也没有公开
看来这个插件就是写在前端的。后端无法使用。
要么使用sqlx,要么修改源码。额,都很麻烦。
笔者不在后端使用这个插件。直接使用sqlx
sqlx
暂时丢掉插件,简单使用一下这个crate
创建一个数据库和book表
添加依赖
sqlx = { version = "0.8.5", features = ["sqlite", "runtime-tokio"] }
在connect.rs中,定义DbInstances ,然后将其注册成State
use sqlx::sqlite::SqlitePoolOptions;
use sqlx::Sqlite;
use sqlx::Pool;
use tauri::{command, AppHandle, State};
async fn connect()-> Pool<Sqlite> {SqlitePoolOptions::new().connect("sqlite:start.db").await.unwrap()}
pub struct DbInstances {pub db: Pool<Sqlite>
}
impl DbInstances {pub async fn new() -> Self {Self {db: connect().await}}
}
通信函数
use sqlx::Executor;
use crate::sql::connect::DbInstances;
use tauri::{command, AppHandle, State};
use tauri::Result;#[command]
pub async fn insert_one(state: State<'_, DbInstances>)->Result<()> {let db=state.db.clone();db.execute(r"INSERT INTO book (id, author, title, published_date) VALUES (2, 'gg', 'good', '2024-04-20');").await.unwrap();Ok(())}
注册State和通信函数之后。
执行后
成功。简单地使用了一下sqlx
前端使用插件sql
既然这个插件是为前端服务的,就在前端简单使用一下。
添加依赖
pnpm add @tauri-apps/plugin-sql
后端注册完成后,简单的代码如下
import Database,{QueryResult} from '@tauri-apps/plugin-sql';
export async function useSql(){const db = await Database.load('sqlite:start.db');let a=await db.execute("INSERT INTO book (id, author, title, published_date) VALUES (22, 'gg', 'good', '2024-04-20');");console.log(a)let b=await db.select("select * from book")console.log(b)db.close()
}
所有的通信函数都在这里。
使用load方法和execuct方法,需要配置权限
"sql:default","sql:allow-execute"
通信函数load
#[command]
pub(crate) async fn load<R: Runtime>(app: AppHandle<R>,db_instances: State<'_, DbInstances>,migrations: State<'_, Migrations>,db: String,
) -> Result<String, crate::Error> {let pool = DbPool::connect(&db, &app).await?;if let Some(migrations) = migrations.0.lock().await.remove(&db) {let migrator = Migrator::new(migrations).await?;pool.migrate(&migrator).await?;}db_instances.0.write().await.insert(db.clone(), pool);Ok(db)
}
先连接,看看DbPool::connect方法
match conn_url.split_once(':').ok_or_else(|| crate::Error::InvalidDbUrl(conn_url.to_string()))?.0{#[cfg(feature = "sqlite")]"sqlite" => {let app_path = _app.path().app_config_dir().expect("No App config path was found!");create_dir_all(&app_path).expect("Couldn't create app config dir");let conn_url = &path_mapper(app_path, conn_url);if !Sqlite::database_exists(conn_url).await.unwrap_or(false) {Sqlite::create_database(conn_url).await?;}Ok(Self::Sqlite(Pool::connect(conn_url).await?))}
fn path_mapper(mut app_path: std::path::PathBuf, connection_string: &str) -> String {app_path.push(connection_string.split_once(':').expect("Couldn't parse the connection string for DB!").1,);
对于sqlite:start.db可以发现位置其实是在app_config_dir+start.db
笔者是Window系统,位置如下
写相当路径会相对 app_config_dir。
可以写绝对路径,比如
const db = await Database.load('sqlite:D:/start/start.db');
当然,需要有表,结果如下
从官网的案例中可以发现
const result = await db.execute(
"UPDATE todos SET title = $1, status = $2 WHERE id = $3",
[todos.title, todos.status, todos.id],
);
可以在sql语句中使用占位符。基本操作。
预加载
可以在配置文件中提前配置。不重要
"plugins": {"sql": {"preload": ["sqlite:start.db"]}},
总结
这个插件实际上感觉就是对sqlx的封装。也不是很完全的封装,也没有对sql语句的封装。
等用于为前端提供了数据库连接和执行的接口。