bindings/go: update readme with example, change module name

This commit is contained in:
PThorpe92 2025-01-31 15:03:14 -05:00
parent 8d93130809
commit 7ee52fca4d
No known key found for this signature in database
GPG key ID: 66DB3FBACBDD05CC
6 changed files with 55 additions and 31 deletions

View file

@ -1,41 +1,71 @@
## Limbo driver for Go's `database/sql` library
# Limbo driver for Go's `database/sql` library
**NOTE:** this is currently __heavily__ W.I.P and is not yet in a usable state. This is merged in only for the purposes of incremental progress and not because the existing code here proper. Expect many and frequent changes.
**NOTE:** this is currently __heavily__ W.I.P and is not yet in a usable state.
This uses the [purego](https://github.com/ebitengine/purego) library to call C (in this case Rust with C ABI) functions from Go without the use of `CGO`.
This driver uses the awesome [purego](https://github.com/ebitengine/purego) library to call C (in this case Rust with C ABI) functions from Go without the use of `CGO`.
## To use: (_UNSTABLE_ testing or development purposes only)
### To test
## Linux | MacOS
### Linux | MacOS
_All commands listed are relative to the bindings/go directory in the limbo repository_
```
cargo build --package limbo-go
# Your LD_LIBRARY_PATH environment variable must include limbo's `target/debug` directory
LD_LIBRARY_PATH="../../target/debug:$LD_LIBRARY_PATH" go test
export LD_LIBRARY_PATH="/path/to/limbo/target/debug:$LD_LIBRARY_PATH"
```
## Windows
```
cargo build --package limbo-go
# Copy the lib_limbo_go.dll into the current working directory (bindings/go)
# Alternatively, you could add the .dll to a location in your PATH
# You must add limbo's `target/debug` directory to your PATH
# or you could built + copy the .dll to a location in your PATH
# or just the CWD of your go module
cp ../../target/debug/lib_limbo_go.dll .
cp path\to\limbo\target\debug\lib_limbo_go.dll .
go test
```
**Temporarily** you may have to clone the limbo repository and run:
`go mod edit -replace github.com/tursodatabase/limbo=/path/to/limbo/bindings/go`
```go
import (
"fmt"
"database/sql"
_"github.com/tursodatabase/limbo"
)
func main() {
conn, err := sql.Open("sqlite3", ":memory:")
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
sql := "CREATE table go_limbo (foo INTEGER, bar TEXT)"
_ = conn.Exec(sql)
sql = "INSERT INTO go_limbo (foo, bar) values (?, ?)"
stmt, _ := conn.Prepare(sql)
defer stmt.Close()
_ = stmt.Exec(42, "limbo")
rows, _ := conn.Query("SELECT * from go_limbo")
defer rows.Close()
for rows.Next() {
var a int
var b string
_ = rows.Scan(&a, &b)
fmt.Printf("%d, %s", a, b)
}
}
```

View file

@ -1,4 +1,4 @@
module limbo
module github.com/tursodatabase/limbo
go 1.23.4

View file

@ -6,7 +6,7 @@ import (
"log"
"testing"
_ "limbo"
_ "github.com/tursodatabase/limbo"
)
var conn *sql.DB

View file

@ -7,7 +7,7 @@ use std::{
ffi::{c_char, c_void},
rc::Rc,
str::FromStr,
sync::{Arc, RwLock},
sync::Arc,
};
/// # Safety
@ -40,21 +40,18 @@ pub unsafe extern "C" fn db_open(path: *const c_char) -> *mut c_void {
#[allow(dead_code)]
struct LimboConn {
conn: RwLock<Rc<Connection>>,
conn: Rc<Connection>,
io: Arc<dyn limbo_core::IO>,
}
impl<'conn> LimboConn {
fn new(conn: Rc<Connection>, io: Arc<dyn limbo_core::IO>) -> Self {
LimboConn {
conn: conn.into(),
io,
}
LimboConn { conn, io }
}
#[allow(clippy::wrong_self_convention)]
fn to_ptr(self) -> *mut c_void {
Arc::into_raw(Arc::new(self)) as *mut c_void
Box::into_raw(Box::new(self)) as *mut c_void
}
fn from_ptr(ptr: *mut c_void) -> &'conn mut LimboConn {

View file

@ -90,6 +90,9 @@ pub extern "C" fn rows_get_columns(rows_ptr: *mut c_void) -> i32 {
rows.stmt.columns().len() as i32
}
/// Returns a pointer to a string with the name of the column at the given index.
/// The caller is responsible for freeing the memory, it should be copied on the Go side
/// immediately and 'free_string' called
#[no_mangle]
pub extern "C" fn rows_get_column_name(rows_ptr: *mut c_void, idx: i32) -> *const c_char {
if rows_ptr.is_null() {

View file

@ -13,10 +13,7 @@ pub extern "C" fn db_prepare(ctx: *mut c_void, query: *const c_char) -> *mut c_v
let query_str = unsafe { std::ffi::CStr::from_ptr(query) }.to_str().unwrap();
let db = LimboConn::from_ptr(ctx);
let Ok(conn) = db.conn.read() else {
return std::ptr::null_mut();
};
let stmt = conn.prepare(query_str);
let stmt = db.conn.prepare(query_str);
match stmt {
Ok(stmt) => LimboStatement::new(Some(stmt), LimboConn::from_ptr(ctx)).to_ptr(),
Err(_) => std::ptr::null_mut(),
@ -55,10 +52,7 @@ pub extern "C" fn stmt_execute(
return ResultCode::Error;
}
Ok(StepResult::Done) => {
let Ok(conn) = stmt.conn.conn.read() else {
return ResultCode::Done;
};
let total_changes = conn.total_changes();
let total_changes = stmt.conn.conn.total_changes();
if !changes.is_null() {
unsafe {
*changes = total_changes;