tursodatabase / libsql-client-rs

libSQL Rust client library can be used to communicate with sqld natively over HTTP protocol with native Rust interface.
MIT License
75 stars 29 forks source link

libsql_client::SyncClient incompatible with napi #65

Open coindegen opened 10 months ago

coindegen commented 10 months ago

Hello, I'm trying to use libsql client inside of napi (https://napi.rs/). Here is my lib.rs:

use dotenv::dotenv;
use libsql_client;
use napi::bindgen_prelude::*;
use napi_derive::napi;
use std::env;
use url;

#[napi]
async fn execute_command() -> Result<u32> {
    dotenv().ok();

    let db_url = env::var("TURSO_DATABASE_URL").expect("TURSO_DATABASE_URL is not set in .env");
    let auth_token =
        Some(env::var("TURSO_AUTH_TOKEN").expect("TURSO_AUTH_TOKEN is not set in .env"));
    println!("Using production db: {}", db_url);

    let client = libsql_client::SyncClient::from_config(libsql_client::Config {
        url: url::Url::parse(&db_url).expect("Failed to parse URL"),
        auth_token,
    })
    .expect("Failed to create client");

    println!("Sending SQL command");

    let result1 = client.execute("INSERT INTO User (id, avatar_uri, banner_uri, username, description, status, created_at, updated_at) VALUES ('clpuv1hch154qjd241p58gj0k','https://avatars.dicebear.com/api/jdenticon/JE3In5PM.svg','https://ucarecdn.com/e2cd6163-6197-4b56-8c35-de169588390f/defaultbanner.png','','','active','2023-11-27T17:25:15.668Z','2023-12-07T07:12:06.929Z')").unwrap();

    println!("Result: {:?}", result1);

    client.execute("select * from User").unwrap();

    Ok(0)
}

Cargo.toml

[package]
name = "upload"
version = "1.0.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
url = "2.3.1"
dotenv = "0.15.0"
libsql-client = "0.33.1"
tokio = { version = "1.29.1", features = ["full"] }
napi = { version = "2.14.1", features = ["async"] }
napi-derive = "2.14.2"
napi-build = "2.1.0"

When I run this, it hangs at "Sending SQL command" and nothing gets written to my DB. I believe this is related to this issue: https://github.com/libsql/libsql-client-rs/issues/48

Similar to the solution described there, is there a simple workaround to make this work?

Curiously, if instead I connect to a local DB (as opposed to the remote Turso DB above), the program doesn't hang, my insert works just fine:

        let current_dir = env::current_dir().expect("Failed to get current directory");
        let db_path = current_dir.join("prisma/dev.db");
        let db_url = format!(
            "file:////{}",
            db_path.to_str().expect("Failed to convert path to string")
        );
        let auth_token = None;
        println!("Using local db: {}", db_url);

Also, when I use the regular async libsql Client and use Node's spawn to run my program (using #[tokio::main] attribute instead of #[napi], it also works fine. The reason I am using the SyncClient with napi-rs is because the regular Client gives this compiler error:

`*mut libsql_sys::ffi::sqlite3` cannot be shared between threads safely
within `libsql_client::Client`, the trait `Sync` is not implemented for `*mut libsql_sys::ffi::sqlite3`
required for `&libsql_client::Client` to implement `std::marker::Send`

Any pointers please?