Skip to content

Commit fe8cf4f

Browse files
committed
fix(sqlite-native): restore kv error hook
1 parent 532364f commit fe8cf4f

7 files changed

Lines changed: 320 additions & 59 deletions

File tree

Cargo.lock

Lines changed: 124 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ members = [
5656
"engine/sdks/rust/envoy-protocol",
5757
"engine/sdks/rust/epoxy-protocol",
5858
"engine/sdks/rust/test-envoy",
59-
"engine/sdks/rust/ups-protocol"
59+
"engine/sdks/rust/ups-protocol",
60+
"rivetkit-typescript/packages/rivetkit-native"
6061
]
6162

6263
[workspace.package]
@@ -514,6 +515,9 @@ members = [
514515
[workspace.dependencies.rivet-envoy-protocol]
515516
path = "engine/sdks/rust/envoy-protocol"
516517

518+
[workspace.dependencies.rivetkit-sqlite-native]
519+
path = "rivetkit-typescript/packages/sqlite-native"
520+
517521
[workspace.dependencies.epoxy-protocol]
518522
path = "engine/sdks/rust/epoxy-protocol"
519523

rivetkit-typescript/packages/rivetkit-native/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface JsEnvoyConfig {
2727
poolName: string
2828
version: number
2929
metadata?: any
30+
notGlobal: boolean
3031
/**
3132
* Log level for the Rust tracing subscriber (e.g. "trace", "debug", "info", "warn", "error").
3233
* Falls back to RIVET_LOG_LEVEL, then LOG_LEVEL, then RUST_LOG env vars. Defaults to "warn".
@@ -59,6 +60,7 @@ export declare function startEnvoySyncJs(config: JsEnvoyConfig, eventCallback: (
5960
export declare function startEnvoyJs(config: JsEnvoyConfig, eventCallback: (event: any) => void): JsEnvoyHandle
6061
/** Native SQLite database handle exposed to JavaScript. */
6162
export declare class JsNativeDatabase {
63+
takeLastKvError(): string | null
6264
run(sql: string, params?: Array<JsBindParam> | undefined | null): Promise<ExecuteResult>
6365
query(sql: string, params?: Array<JsBindParam> | undefined | null): Promise<QueryResult>
6466
exec(sql: string): Promise<QueryResult>

rivetkit-typescript/packages/rivetkit-native/src/database.rs

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
use std::ffi::{c_char, CStr, CString};
1+
use std::ffi::{CStr, CString, c_char};
22
use std::ptr;
33
use std::sync::{Arc, Mutex};
44

55
use async_trait::async_trait;
66
use libsqlite3_sys::{
7-
sqlite3, sqlite3_bind_blob, sqlite3_bind_double, sqlite3_bind_int64, sqlite3_bind_null,
8-
sqlite3_bind_text, sqlite3_changes, sqlite3_column_blob, sqlite3_column_bytes,
9-
sqlite3_column_count, sqlite3_column_double, sqlite3_column_int64, sqlite3_column_name,
10-
sqlite3_column_text, sqlite3_column_type, sqlite3_errmsg, sqlite3_finalize,
11-
sqlite3_prepare_v2, sqlite3_step, SQLITE_BLOB, SQLITE_DONE, SQLITE_FLOAT, SQLITE_INTEGER,
12-
SQLITE_NULL, SQLITE_OK, SQLITE_ROW, SQLITE_TEXT, SQLITE_TRANSIENT,
7+
SQLITE_BLOB, SQLITE_DONE, SQLITE_FLOAT, SQLITE_INTEGER, SQLITE_NULL, SQLITE_OK, SQLITE_ROW,
8+
SQLITE_TEXT, SQLITE_TRANSIENT, sqlite3, sqlite3_bind_blob, sqlite3_bind_double,
9+
sqlite3_bind_int64, sqlite3_bind_null, sqlite3_bind_text, sqlite3_changes, sqlite3_column_blob,
10+
sqlite3_column_bytes, sqlite3_column_count, sqlite3_column_double, sqlite3_column_int64,
11+
sqlite3_column_name, sqlite3_column_text, sqlite3_column_type, sqlite3_errmsg,
12+
sqlite3_finalize, sqlite3_prepare_v2, sqlite3_step,
1313
};
1414
use napi::bindgen_prelude::Buffer;
1515
use napi_derive::napi;
@@ -34,6 +34,10 @@ impl EnvoyKv {
3434

3535
#[async_trait]
3636
impl SqliteKv for EnvoyKv {
37+
fn on_error(&self, actor_id: &str, error: &SqliteKvError) {
38+
tracing::error!(%actor_id, %error, "native sqlite kv operation failed");
39+
}
40+
3741
async fn on_open(&self, _actor_id: &str) -> Result<(), SqliteKvError> {
3842
Ok(())
3943
}
@@ -109,13 +113,19 @@ pub struct JsNativeDatabase {
109113

110114
impl JsNativeDatabase {
111115
pub fn as_ptr(&self) -> *mut libsqlite3_sys::sqlite3 {
112-
self
113-
.db
116+
self.db
114117
.lock()
115118
.ok()
116119
.and_then(|guard| guard.as_ref().map(NativeDatabase::as_ptr))
117120
.unwrap_or(ptr::null_mut())
118121
}
122+
123+
fn take_last_kv_error_inner(&self) -> Option<String> {
124+
self.db
125+
.lock()
126+
.ok()
127+
.and_then(|guard| guard.as_ref().and_then(NativeDatabase::take_last_kv_error))
128+
}
119129
}
120130

121131
#[napi(object)]
@@ -140,6 +150,11 @@ pub struct QueryResult {
140150

141151
#[napi]
142152
impl JsNativeDatabase {
153+
#[napi]
154+
pub fn take_last_kv_error(&self) -> Option<String> {
155+
self.take_last_kv_error_inner()
156+
}
157+
143158
#[napi]
144159
pub async fn run(
145160
&self,
@@ -243,13 +258,7 @@ fn bind_params(
243258
let text = CString::new(param.text_value.clone().unwrap_or_default())
244259
.map_err(|err| napi::Error::from_reason(err.to_string()))?;
245260
unsafe {
246-
sqlite3_bind_text(
247-
stmt,
248-
bind_index,
249-
text.as_ptr(),
250-
-1,
251-
SQLITE_TRANSIENT(),
252-
)
261+
sqlite3_bind_text(stmt, bind_index, text.as_ptr(), -1, SQLITE_TRANSIENT())
253262
}
254263
}
255264
"blob" => {
@@ -291,26 +300,17 @@ fn collect_columns(stmt: *mut libsqlite3_sys::sqlite3_stmt) -> Vec<String> {
291300
if name_ptr.is_null() {
292301
String::new()
293302
} else {
294-
CStr::from_ptr(name_ptr)
295-
.to_string_lossy()
296-
.into_owned()
303+
CStr::from_ptr(name_ptr).to_string_lossy().into_owned()
297304
}
298305
})
299306
.collect()
300307
}
301308

302-
fn column_value(
303-
stmt: *mut libsqlite3_sys::sqlite3_stmt,
304-
index: i32,
305-
) -> serde_json::Value {
309+
fn column_value(stmt: *mut libsqlite3_sys::sqlite3_stmt, index: i32) -> serde_json::Value {
306310
match unsafe { sqlite3_column_type(stmt, index) } {
307311
SQLITE_NULL => serde_json::Value::Null,
308-
SQLITE_INTEGER => {
309-
serde_json::Value::from(unsafe { sqlite3_column_int64(stmt, index) })
310-
}
311-
SQLITE_FLOAT => {
312-
serde_json::Value::from(unsafe { sqlite3_column_double(stmt, index) })
313-
}
312+
SQLITE_INTEGER => serde_json::Value::from(unsafe { sqlite3_column_int64(stmt, index) }),
313+
SQLITE_FLOAT => serde_json::Value::from(unsafe { sqlite3_column_double(stmt, index) }),
314314
SQLITE_TEXT => {
315315
let text_ptr = unsafe { sqlite3_column_text(stmt, index) };
316316
if text_ptr.is_null() {
@@ -328,9 +328,7 @@ fn column_value(
328328
serde_json::Value::Null
329329
} else {
330330
let blob_len = unsafe { sqlite3_column_bytes(stmt, index) } as usize;
331-
let blob = unsafe {
332-
std::slice::from_raw_parts(blob_ptr as *const u8, blob_len)
333-
};
331+
let blob = unsafe { std::slice::from_raw_parts(blob_ptr as *const u8, blob_len) };
334332
serde_json::Value::Array(
335333
blob.iter()
336334
.map(|byte| serde_json::Value::from(*byte))
@@ -349,9 +347,7 @@ fn execute_statement(
349347
) -> napi::Result<ExecuteResult> {
350348
let c_sql = CString::new(sql).map_err(|err| napi::Error::from_reason(err.to_string()))?;
351349
let mut stmt = ptr::null_mut();
352-
let rc = unsafe {
353-
sqlite3_prepare_v2(db, c_sql.as_ptr(), -1, &mut stmt, ptr::null_mut())
354-
};
350+
let rc = unsafe { sqlite3_prepare_v2(db, c_sql.as_ptr(), -1, &mut stmt, ptr::null_mut()) };
355351
if rc != SQLITE_OK {
356352
return Err(sqlite_error(db, "failed to prepare sqlite statement"));
357353
}
@@ -393,9 +389,7 @@ fn query_statement(
393389
) -> napi::Result<QueryResult> {
394390
let c_sql = CString::new(sql).map_err(|err| napi::Error::from_reason(err.to_string()))?;
395391
let mut stmt = ptr::null_mut();
396-
let rc = unsafe {
397-
sqlite3_prepare_v2(db, c_sql.as_ptr(), -1, &mut stmt, ptr::null_mut())
398-
};
392+
let rc = unsafe { sqlite3_prepare_v2(db, c_sql.as_ptr(), -1, &mut stmt, ptr::null_mut()) };
399393
if rc != SQLITE_OK {
400394
return Err(sqlite_error(db, "failed to prepare sqlite query"));
401395
}

0 commit comments

Comments
 (0)