Skip to content

Commit 297d7da

Browse files
committed
HACKS
1 parent dbb46bd commit 297d7da

1 file changed

Lines changed: 145 additions & 152 deletions

File tree

src/lib.rs

Lines changed: 145 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ impl From<libsql::Error> for Error {
187187
}
188188
}
189189

190-
/// Database connection options.
190+
/// SQLite connection options.
191191
#[napi(object)]
192192
pub struct Options {
193193
pub timeout: Option<f64>,
@@ -198,7 +198,7 @@ pub struct Options {
198198
pub encryptionKey: Option<String>,
199199
}
200200

201-
/// Database connection.
201+
/// SQLite database connection.
202202
#[napi]
203203
pub struct Database {
204204
db: libsql::Database,
@@ -468,11 +468,6 @@ impl Database {
468468
Ok(())
469469
}
470470

471-
#[napi]
472-
pub fn unsafeMode(&self) -> Result<()> {
473-
todo!();
474-
}
475-
476471
#[napi]
477472
pub async fn sync(&self) -> Result<SyncResult> {
478473
let result = self.db.sync().await.map_err(Error::from)?;
@@ -483,6 +478,12 @@ impl Database {
483478
}
484479
}
485480

481+
#[napi(object)]
482+
pub struct SyncResult {
483+
pub frames_synced: f64,
484+
pub replication_index: f64,
485+
}
486+
486487
#[napi]
487488
pub fn database_sync_sync(db: &Database) -> Result<SyncResult> {
488489
let rt = runtime()?;
@@ -506,6 +507,7 @@ pub fn database_prepare_sync(db: &Database, sql: String) -> Result<Statement> {
506507
rt.block_on(async move { db.prepare(sql).await })
507508
}
508509

510+
/// SQLite statement object.
509511
#[napi]
510512
pub struct Statement {
511513
stmt: Arc<tokio::sync::Mutex<libsql::Statement>>,
@@ -515,6 +517,7 @@ pub struct Statement {
515517
pluck: AtomicBool,
516518
}
517519

520+
#[napi]
518521
impl Statement {
519522
pub fn new(
520523
conn: Arc<tokio::sync::Mutex<libsql::Connection>>,
@@ -531,144 +534,7 @@ impl Statement {
531534
pluck: AtomicBool::new(pluck),
532535
}
533536
}
534-
}
535-
536-
#[napi(object)]
537-
pub struct RunResult {
538-
pub changes: f64,
539-
pub duration: f64,
540-
pub lastInsertRowid: i64,
541-
}
542-
543-
fn map_params(
544-
stmt: &libsql::Statement,
545-
params: Option<napi::JsUnknown>,
546-
) -> Result<libsql::params::Params> {
547-
if let Some(params) = params {
548-
match params.get_type()? {
549-
ValueType::Object => {
550-
let object = params.coerce_to_object()?;
551-
if object.is_array()? {
552-
map_params_array(object)
553-
} else {
554-
map_params_object(stmt, object)
555-
}
556-
}
557-
_ => map_params_single(params),
558-
}
559-
} else {
560-
Ok(libsql::params::Params::None)
561-
}
562-
}
563-
564-
fn map_params_single(param: napi::JsUnknown) -> Result<libsql::params::Params> {
565-
Ok(libsql::params::Params::Positional(vec![map_value(param)?]))
566-
}
567-
568-
fn map_params_array(object: napi::JsObject) -> Result<libsql::params::Params> {
569-
let mut params = vec![];
570-
let length = object.get_array_length()?;
571-
for i in 0..length {
572-
let element = object.get_element::<napi::JsUnknown>(i)?;
573-
let value = map_value(element)?;
574-
params.push(value);
575-
}
576-
Ok(libsql::params::Params::Positional(params))
577-
}
578-
579-
fn map_params_object(
580-
stmt: &libsql::Statement,
581-
object: napi::JsObject,
582-
) -> Result<libsql::params::Params> {
583-
let mut params = vec![];
584-
for idx in 0..stmt.parameter_count() {
585-
let name = stmt.parameter_name((idx + 1) as i32).unwrap();
586-
let name = name.to_string();
587-
// Remove the leading ':' or '@' or '$' from parameter name
588-
let key = &name[1..];
589-
if let Ok(value) = object.get_named_property::<napi::JsUnknown>(key) {
590-
let value = map_value(value)?;
591-
params.push((name, value));
592-
}
593-
}
594-
Ok(libsql::params::Params::Named(params))
595-
}
596-
597-
/// Maps a JavaScript value to libSQL value types.
598-
fn map_value(value: JsUnknown) -> Result<libsql::Value> {
599-
let value_type = value.get_type()?;
600-
601-
match value_type {
602-
ValueType::Null | ValueType::Undefined => Ok(libsql::Value::Null),
603-
604-
ValueType::Boolean => {
605-
let js_bool = value.coerce_to_bool()?;
606-
let b = js_bool.get_value()?;
607-
Ok(libsql::Value::Integer(if b { 1 } else { 0 }))
608-
}
609-
610-
ValueType::Number => {
611-
let js_num = value.coerce_to_number()?;
612-
let n = js_num.get_double()?;
613-
Ok(libsql::Value::Real(n))
614-
}
615-
616-
ValueType::BigInt => {
617-
let js_bigint = napi::JsBigInt::from_unknown(value)?;
618-
let (v, lossless) = js_bigint.get_i64()?;
619-
if !lossless {
620-
return Err(napi::Error::from_reason(
621-
"BigInt value is out of range for SQLite INTEGER (i64)",
622-
));
623-
}
624-
Ok(libsql::Value::Integer(v))
625-
}
626-
627-
ValueType::String => {
628-
let js_str = value.coerce_to_string()?;
629-
let utf8 = js_str.into_utf8()?;
630-
// into_utf8 returns a Utf8 object that derefs to str
631-
Ok(libsql::Value::Text(utf8.as_str()?.to_owned()))
632-
}
633-
634-
ValueType::Object => {
635-
let obj = value.coerce_to_object()?;
636-
637-
// Check if it's a buffer
638-
if obj.is_buffer()? {
639-
let buf = napi::JsBuffer::try_from(obj.into_unknown())?;
640-
let data = buf.into_value()?.to_vec();
641-
return Ok(libsql::Value::Blob(data));
642-
}
643-
644-
if obj.is_typedarray()? {
645-
let js_typed = napi::JsTypedArray::try_from(obj.into_unknown())?;
646-
let typed_array_value = js_typed.into_value()?;
647-
648-
let buffer_data = typed_array_value.arraybuffer.into_value()?;
649-
let start = typed_array_value.byte_offset;
650-
let end = start + typed_array_value.length;
651-
652-
if end > buffer_data.len() {
653-
return Err(napi::Error::from_reason("TypedArray length out of bounds"));
654-
}
655-
656-
let slice = &buffer_data[start..end];
657-
return Ok(libsql::Value::Blob(slice.to_vec()));
658-
}
659-
Err(napi::Error::from_reason(
660-
"SQLite3 can only bind numbers, strings, bigints, buffers, and null",
661-
))
662-
}
663-
664-
_ => Err(napi::Error::from_reason(
665-
"SQLite3 can only bind numbers, strings, bigints, buffers, and null",
666-
)),
667-
}
668-
}
669537

670-
#[napi]
671-
impl Statement {
672538
#[napi]
673539
pub fn columns(&self, env: Env) -> Result<Array> {
674540
let rt = runtime()?;
@@ -789,9 +655,7 @@ impl Statement {
789655
conn.changes()
790656
};
791657
let last_insert_row_id = conn.last_insert_rowid();
792-
// Calculate duration
793658
let duration = start.elapsed().as_secs_f64();
794-
795659
Ok(RunResult {
796660
changes: changes as f64,
797661
duration,
@@ -896,6 +760,141 @@ impl Statement {
896760
}
897761
}
898762

763+
/// SQLite `run()` result object
764+
#[napi(object)]
765+
pub struct RunResult {
766+
pub changes: f64,
767+
pub duration: f64,
768+
pub lastInsertRowid: i64,
769+
}
770+
771+
fn map_params(
772+
stmt: &libsql::Statement,
773+
params: Option<napi::JsUnknown>,
774+
) -> Result<libsql::params::Params> {
775+
if let Some(params) = params {
776+
match params.get_type()? {
777+
ValueType::Object => {
778+
let object = params.coerce_to_object()?;
779+
if object.is_array()? {
780+
map_params_array(object)
781+
} else {
782+
map_params_object(stmt, object)
783+
}
784+
}
785+
_ => map_params_single(params),
786+
}
787+
} else {
788+
Ok(libsql::params::Params::None)
789+
}
790+
}
791+
792+
fn map_params_single(param: napi::JsUnknown) -> Result<libsql::params::Params> {
793+
Ok(libsql::params::Params::Positional(vec![map_value(param)?]))
794+
}
795+
796+
fn map_params_array(object: napi::JsObject) -> Result<libsql::params::Params> {
797+
let mut params = vec![];
798+
let length = object.get_array_length()?;
799+
for i in 0..length {
800+
let element = object.get_element::<napi::JsUnknown>(i)?;
801+
let value = map_value(element)?;
802+
params.push(value);
803+
}
804+
Ok(libsql::params::Params::Positional(params))
805+
}
806+
807+
fn map_params_object(
808+
stmt: &libsql::Statement,
809+
object: napi::JsObject,
810+
) -> Result<libsql::params::Params> {
811+
let mut params = vec![];
812+
for idx in 0..stmt.parameter_count() {
813+
let name = stmt.parameter_name((idx + 1) as i32).unwrap();
814+
let name = name.to_string();
815+
// Remove the leading ':' or '@' or '$' from parameter name
816+
let key = &name[1..];
817+
if let Ok(value) = object.get_named_property::<napi::JsUnknown>(key) {
818+
let value = map_value(value)?;
819+
params.push((name, value));
820+
}
821+
}
822+
Ok(libsql::params::Params::Named(params))
823+
}
824+
825+
/// Maps a JavaScript value to libSQL value types.
826+
fn map_value(value: JsUnknown) -> Result<libsql::Value> {
827+
let value_type = value.get_type()?;
828+
829+
match value_type {
830+
ValueType::Null | ValueType::Undefined => Ok(libsql::Value::Null),
831+
832+
ValueType::Boolean => {
833+
let js_bool = value.coerce_to_bool()?;
834+
let b = js_bool.get_value()?;
835+
Ok(libsql::Value::Integer(if b { 1 } else { 0 }))
836+
}
837+
838+
ValueType::Number => {
839+
let js_num = value.coerce_to_number()?;
840+
let n = js_num.get_double()?;
841+
Ok(libsql::Value::Real(n))
842+
}
843+
844+
ValueType::BigInt => {
845+
let js_bigint = napi::JsBigInt::from_unknown(value)?;
846+
let (v, lossless) = js_bigint.get_i64()?;
847+
if !lossless {
848+
return Err(napi::Error::from_reason(
849+
"BigInt value is out of range for SQLite INTEGER (i64)",
850+
));
851+
}
852+
Ok(libsql::Value::Integer(v))
853+
}
854+
855+
ValueType::String => {
856+
let js_str = value.coerce_to_string()?;
857+
let utf8 = js_str.into_utf8()?;
858+
// into_utf8 returns a Utf8 object that derefs to str
859+
Ok(libsql::Value::Text(utf8.as_str()?.to_owned()))
860+
}
861+
862+
ValueType::Object => {
863+
let obj = value.coerce_to_object()?;
864+
865+
// Check if it's a buffer
866+
if obj.is_buffer()? {
867+
let buf = napi::JsBuffer::try_from(obj.into_unknown())?;
868+
let data = buf.into_value()?.to_vec();
869+
return Ok(libsql::Value::Blob(data));
870+
}
871+
872+
if obj.is_typedarray()? {
873+
let js_typed = napi::JsTypedArray::try_from(obj.into_unknown())?;
874+
let typed_array_value = js_typed.into_value()?;
875+
876+
let buffer_data = typed_array_value.arraybuffer.into_value()?;
877+
let start = typed_array_value.byte_offset;
878+
let end = start + typed_array_value.length;
879+
880+
if end > buffer_data.len() {
881+
return Err(napi::Error::from_reason("TypedArray length out of bounds"));
882+
}
883+
884+
let slice = &buffer_data[start..end];
885+
return Ok(libsql::Value::Blob(slice.to_vec()));
886+
}
887+
Err(napi::Error::from_reason(
888+
"SQLite3 can only bind numbers, strings, bigints, buffers, and null",
889+
))
890+
}
891+
892+
_ => Err(napi::Error::from_reason(
893+
"SQLite3 can only bind numbers, strings, bigints, buffers, and null",
894+
)),
895+
}
896+
}
897+
899898
/// A raw iterator over rows. The JavaScript layer wraps this in a iterable.
900899
#[napi]
901900
pub struct RowsIterator {
@@ -1124,9 +1123,3 @@ fn ensure_logger() {
11241123
.try_init();
11251124
});
11261125
}
1127-
1128-
#[napi(object)]
1129-
pub struct SyncResult {
1130-
pub frames_synced: f64,
1131-
pub replication_index: f64,
1132-
}

0 commit comments

Comments
 (0)