【Tauri2】035——sql和sqlx

前言

这篇就来看看插件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

rust 复制代码
    pub fn add_migrations(mut self,
                          db_url: &str, 
                          migrations: Vec<Migration>) -> Self 

需要传入db_urlmigrations

比如db_url可以设置sqlite:start.db

migrations是个Vec,元素类型是Migration

Migration的定义如下

rust 复制代码
#[derive(Debug)]
pub struct Migration {
    pub version: i64,
    pub description: &'static str,
    pub sql: &'static str,
    pub kind: MigrationKind,
}

MigrationKind是指定迁移的类型

rust 复制代码
#[derive(Debug)]
pub enum MigrationKind {
    Up,
    Down,
}

项目结构如下

在migration.rs中

rust 复制代码
use tauri_plugin_sql::{Migration,MigrationKind};
pub fn get_migration()->Vec<Migration>{
    vec![
        // Define your migrations here
        Migration {
            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,
        }
    ] 
}

创建了一张表

注册

rust 复制代码
       .plugin(tauri_plugin_sql::Builder::default()
            .add_migrations("sqlite:start.db",get_migration())
            .build())

想要在后端使用

怎么在后端使用,这确实是个问题,笔者发现好像没有在后端使用的东西,全都是前端调用

比如说

rust 复制代码
    pub(crate) async fn connect<R: Runtime>(
        conn_url: &str,
        _app: &AppHandle<R>,
    ) -> Result<Self, crate::Error> 

按道理来说,connect应该可以使用,但是这是私有的,只在crate内部公开,

笔者也没找到怎么使用,

看看内部的通信函数

rust 复制代码
#[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)
}
rust 复制代码
impl DbPool {
    pub(crate) async fn connect
    pub(crate) async fn migrate

    pub(crate) async fn close(&self) 
    pub(crate) async fn execute
    }

可以看出使用了DbInstances和Migrations,两个State

要先连接DbPool::connect,但是这个connect没公开,其他方法也没有公开

看来这个插件就是写在前端的。后端无法使用。

要么使用sqlx,要么修改源码。额,都很麻烦。

笔者不在后端使用这个插件。直接使用sqlx

sqlx

暂时丢掉插件,简单使用一下这个crate

创建一个数据库和book表

添加依赖

rust 复制代码
sqlx = { version = "0.8.5", features = ["sqlite", "runtime-tokio"] }

在connect.rs中,定义DbInstances ,然后将其注册成State

rust 复制代码
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
        }
    }
}

通信函数

rust 复制代码
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

既然这个插件是为前端服务的,就在前端简单使用一下。

添加依赖

rust 复制代码
pnpm add @tauri-apps/plugin-sql

后端注册完成后,简单的代码如下

TypeScript 复制代码
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方法,需要配置权限

rust 复制代码
    "sql:default",
    "sql:allow-execute"

通信函数load

rust 复制代码
#[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方法

rust 复制代码
 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?))
            }
rust 复制代码
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。

可以写绝对路径,比如

rust 复制代码
const db = await Database.load('sqlite:D:/start/start.db');

当然,需要有表,结果如下

从官网的案例中可以发现

rust 复制代码
const result = await db.execute(
"UPDATE todos SET title = $1, status = $2 WHERE id = $3",
[todos.title, todos.status, todos.id],
);

可以在sql语句中使用占位符。基本操作。

预加载

可以在配置文件中提前配置。不重要

TypeScript 复制代码
  "plugins": {
    "sql": {
      "preload": ["sqlite:start.db"]
    }
  },

总结

这个插件实际上感觉就是对sqlx的封装。也不是很完全的封装,也没有对sql语句的封装。

等用于为前端提供了数据库连接和执行的接口。

相关推荐
Elastic 中国社区官方博客12 小时前
Elastic Platform 8.18 和 9.0:ES|QL Lookup Joins 功能现已推出,Lucene 10!
大数据·人工智能·sql·elasticsearch·搜索引擎·全文检索·lucene
Always_away18 小时前
数据库系统概论|第五章:数据库完整性—课程笔记1
数据库·笔记·sql·学习
weixin_3077791319 小时前
ETL架构、数据建模及性能优化实践
开发语言·数据仓库·sql·架构·etl
菜是一种态度1 天前
PostgreSQL数据库操作SQL
数据库·sql·postgresql
邪恶马铃薯1 天前
SQL常用数据清洗语句
数据库·sql
Themberfue1 天前
Redis ⑧-RESP | 渐进式遍历 | 数据库管理
数据库·redis·sql·缓存
刀一寸1 天前
PGSql查看表结构以及注释信息
数据库·sql
疏狂难除1 天前
【Tauri2】036——Sidecar和shell插件 (二)
node·tauri2
wangzhongyudie2 天前
SQL实战:04之SQL中的分组问题求解
数据库·hive·sql