tursodatabase / libsql

libSQL is a fork of SQLite that is both Open Source, and Open Contributions.
https://turso.tech/libsql
MIT License
9.34k stars 243 forks source link

execute params argument isn't compatible with rusqlite #278

Open CodingDoug opened 1 year ago

CodingDoug commented 1 year ago

Porting from the example provided by rusqlite in its documentation:

use rusqlite::{Connection, Result};

#[derive(Debug)]
struct Person {
    id: i32,
    name: String,
    data: Option<Vec<u8>>,
}

    let me = Person {
        id: 0,
        name: "Steven".to_string(),
        data: None,
    };
    conn.execute(
        "INSERT INTO person (name, data) VALUES (?1, ?2)",
        (&me.name, &me.data),
    )?;

When ported verbatim to libsql changing only the crate:

use libsql::{Database, Connection, Result};

The following error results:

error[E0277]: the trait bound `libsql::Params: From<(&String, &Option<std::vec::Vec<u8>>)>` is not satisfied
  --> src/libsql/mod.rs:29:9
   |
27 |     conn.execute(
   |          ------- required by a bound introduced by this call
28 |         "INSERT INTO person (name, data) VALUES (?1, ?2)",
29 |         (&me.name, &me.data),
   |         ^^^^^^^^^^^^^^^^^^^^ the trait `From<(&String, &Option<std::vec::Vec<u8>>)>` is not implemented for `libsql::Params`
   |
   = help: the following other types implement trait `From<T>`:
             <libsql::Params as From<()>>
             <libsql::Params as From<std::vec::Vec<(String, libsql::Value)>>>
             <libsql::Params as From<std::vec::Vec<libsql::Value>>>
   = note: required for `(&String, &Option<std::vec::Vec<u8>>)` to implement `Into<libsql::Params>`
note: required by a bound in `libsql::Connection::execute`
  --> /Users/doug/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libsql-0.1.6/src/connection.rs:74:12
   |
74 |         P: Into<Params>,
   |            ^^^^^^^^^^^^ required by this bound in `Connection::execute`

As someone inexperienced in Rust, the only way I can easily see to make this particular example compile is not straightforward to me:

        params![&*me.name]

Also note also that libsql does not seem to accept Option parameters like me.name. Apparently rusqlite takes None to mean SQL NULL that libsql should also take?

CodingDoug commented 1 year ago

On the point of the last question about the use of Option in rusqlite: https://stackoverflow.com/a/70819044

...in general, the tool for “might be null” in Rust is Option, and taking a look at rusqlite::ToSql confirms that there is a

impl<T: ToSql> ToSql for Option<T>

which does what you want. (It's undocumented, unfortunately, but following the “[src]” link shows its implementation.) To use it:

if person.name == "null" { None } else { Some(person.name) }
CodingDoug commented 1 year ago

Another thing to note here - execute in rusqlite fails with the following message if the query returns any rows at all:

Execute returned results - did you mean to call query?