Setup Sqlite in Tauri

Nestero
Bismillahirrahmanirrahim

Persipan

Install beberapa paket yang dibutuhkan, sebagai berikut:

  • Tauri CLI / Create Tauri App
  • Sqlx CLI
cargo install create-tauri-app sqlx-cli

Membuat Project Baru

Untuk membuat project baru tauri bisa dilakukan dengan perintah create-tauri-app, yang sudah diinstall sebelumnya,

cargo create-tauri-app
✔ Project name · kontak
✔ Identifier · zero.nestero.kontak
✔ Choose which language to use for your frontend · Rust - (cargo)
✔ Choose your UI template · Vanilla

Template created! To get started run:
  cd kontak
  cargo tauri android init

For Desktop development, run:
  cargo tauri dev

For Android development, run:
  cargo tauri android dev

untuk Project name dan Identifier, silahkan disesuaikan, struktur foldernya nanti kurang lebih seperti ini,

├── README.md
├── src
│   ├── assets
│   │   ├── javascript.svg
│   │   └── tauri.svg
│   ├── index.html
│   ├── main.js
│   └── styles.css
└── src-tauri
    ├── build.rs
    ├── capabilities
    │   └── default.json
    ├── Cargo.toml
    ├── icons
    │   ├── 128x128@2x.png
    │   ├── 128x128.png
    │   ├── 32x32.png
    │   ├── icon.icns
    │   ├── icon.ico
    │   ├── icon.png
    │   ├── Square107x107Logo.png
    │   ├── Square142x142Logo.png
    │   ├── Square150x150Logo.png
    │   ├── Square284x284Logo.png
    │   ├── Square30x30Logo.png
    │   ├── Square310x310Logo.png
    │   ├── Square44x44Logo.png
    │   ├── Square71x71Logo.png
    │   ├── Square89x89Logo.png
    │   └── StoreLogo.png
    ├── src
    │   ├── lib.rs
    │   └── main.rs
    └── tauri.conf.json

Cargo.toml

Tambahkan 2 dependensi berikut pada src-tauri/Cargo.toml

[dependencies]
tokio = { version = "1.47.1", features = ["full"] }
sqlx = { version = "0.8.6", features = ["runtime-tokio-rustls", "sqlite"] }

Membuat Migrasi sql

Buat file migrasi sql dengan sqlx cli, yang sudah diinstall sebelumnya,

cargo sqlx migrate add db_kontak

akan menghasilkan file sql pada folder migrations/TIMESTAMP_db_kontak.sql, isi dengan tabel sql yang akan dibuat contoh:

CREATE TABLE IF NOT EXISTS kontak (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  no_kontak TEXT NOT NULL UNIQUE,
  nama TEXT NOT NULL,
  alamat TEXT NOT NULL
);

Koneksi Database

Buat file database.rs pada src-tauri/src/db.rs

use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
use sqlx::SqlitePool;
use std::str::FromStr;

pub async fn init_db(database_url: &str) -> Result<SqlitePool, Box<dyn std::error::Error>> {
    // Parsing opsi koneksi
    let connection_options = SqliteConnectOptions::from_str(database_url)?
        .create_if_missing(true); // Pastikan ini true agar DB dibuat jika belum ada

    // Buat pool koneksi dengan opsi tersebut
    let pool = SqlitePoolOptions::new()
        .connect_with(connection_options)
        .await?;

    // Jalankan migrasi
    // Pastikan folder "migrations" ada di root project
    sqlx::migrate!("../migrations").run(&pool).await?;
    
    Ok(pool)
}

Lib.rs

Selanjutnya masukan setup database ke src-tauri/src/lib.rs

pub mod db;

use tauri::Manager;
use std::fs;

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .setup(|app| {
            let app_handle = app.handle().clone();

            // Jalankan inisialisasi DB di background async task
            tauri::async_runtime::spawn(async move {
                // Untuk Android (Tunggu resources terextract)
                #[cfg(target_os = "android")]
                thread::sleep(Duration::from_millis(500));

                // Dapatkan Path App Data
                let app_data_dir = app_handle
                    .path()
                    .app_data_dir()
                    .expect("Gagal mendapatkan app data dir");

                // Buat folder jika belum ada
                if !app_data_dir.exists() {
                    fs::create_dir_all(&app_data_dir).expect("Gagal buat direktori app data");
                }

                let db_path_tujuan = app_data_dir.join("kontak_db.sqlite");
                
                // Cek apakah DB sudah ada, jika tidak coba copy dari resources
                if !db_path_tujuan.exists() {
                    println!("Database belum ada, mencoba mencari di resources...");
                    
                    // Helper function sederhana untuk mencari resource path
                    let resource_path = app_handle.path().resource_dir().map(|dir| dir.join("assets/db.sqlite"));
                    
                    match resource_path {
                        Ok(src_path) => {
                            if src_path.exists() {
                                match fs::copy(&src_path, &db_path_tujuan) {
                                    Ok(_) => println!("Berhasil copy database dari resources"),
                                    Err(e) => eprintln!("Gagal copy database: {}", e),
                                }
                            } else {
                                println!("File assets/db.sqlite tidak ditemukan, database baru akan dibuat.");
                            }
                        }
                        Err(e) => eprintln!("Gagal resolve resource dir: {}", e),
                    }
                    
                }

                // Koneksi ke Database
                let db_url = format!("sqlite:{}", db_path_tujuan.to_str().expect("Path tidak valid"));
                println!("Menghubungkan ke DB: {}", db_url);

                match db::init_db(&db_url).await {
                    Ok(pool) => {
                        println!("Database terkoneksi dan Migrasi Berhasil!");
                        // Manage pool agar bisa diakses di command tauri nanti
                        app_handle.manage(pool); 
                    }
                    Err(e) => {
                        eprintln!("CRITICAL ERROR - Gagal Inisialisasi DB: {:?}", e);
                    }
                }
            });

            Ok(())
        })
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Assets

Pada file lib.rs diatas ada satu fungsi yang akan mengecek file db.sqlite pada resource, agar file tersebut include dalam bundle pada saat proses build, perlu ditambahkan di konfigurasi pada src-tauri/tauri.conf.json

  "bundle": {
    ....................
    "resources": [
      "assets/db.sqlite"
    ]
  }
}

dan jangan lupa buat fileny pada src-tauri/assets/db.sqlite.

Sejauh ini apabila berhasil maka pada saat menjalankan cargo tauri dev file database akan terbuat dan migrasi secara otomatis pada saat pertama kali aplikasi dijalankan, contohnya pada sistem operasi gnu/linux data akan terbuat otomati pada direktori ~/.local/share/zero.nestero.kontak

Sesungguhnya yang menyebabkan ilmu hilang adalah lupa dan tidak mengulanginya.

"Sesungguhnya yang menyebabkan ilmu hilang adalah lupa dan tidak mengulanginya."

Imam Az-Zuhri rahimahullah

Tags:

Referensi:

Catatan Terkait:

NESTECH ID

Copyright 2025. All rights reserved.