@@ -187,7 +187,7 @@ impl From<libsql::Error> for Error {
187187 }
188188}
189189
190- /// Database connection options.
190+ /// SQLite connection options.
191191#[ napi( object) ]
192192pub 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]
203203pub 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]
487488pub 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]
510512pub struct Statement {
511513 stmt : Arc < tokio:: sync:: Mutex < libsql:: Statement > > ,
@@ -515,6 +517,7 @@ pub struct Statement {
515517 pluck : AtomicBool ,
516518}
517519
520+ #[ napi]
518521impl 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]
901900pub 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