@@ -11,6 +11,7 @@ use rusqlite::{
11
11
Row , ToSql ,
12
12
} ;
13
13
use serde:: { Deserialize , Serialize } ;
14
+ use serde_json:: value:: RawValue ;
14
15
use smallvec:: { SmallVec , ToSmallVec } ;
15
16
use speedy:: { Context , Readable , Reader , Writable , Writer } ;
16
17
use sqlite:: ChangeType ;
@@ -120,9 +121,25 @@ impl ToSql for ChangeId {
120
121
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
121
122
#[ serde( untagged) ]
122
123
pub enum Statement {
124
+ Verbose {
125
+ query : String ,
126
+ params : Option < Vec < SqliteParam > > ,
127
+ named_params : Option < HashMap < String , SqliteParam > > ,
128
+ } ,
123
129
Simple ( String ) ,
124
- WithParams ( String , Vec < SqliteValue > ) ,
125
- WithNamedParams ( String , HashMap < String , SqliteValue > ) ,
130
+ WithParams ( String , Vec < SqliteParam > ) ,
131
+ WithNamedParams ( String , HashMap < String , SqliteParam > ) ,
132
+ }
133
+
134
+ impl Statement {
135
+ pub fn query ( & self ) -> & str {
136
+ match self {
137
+ Statement :: Verbose { query, .. }
138
+ | Statement :: Simple ( query)
139
+ | Statement :: WithParams ( query, _)
140
+ | Statement :: WithNamedParams ( query, _) => query,
141
+ }
142
+ }
126
143
}
127
144
128
145
impl From < & str > for Statement {
@@ -292,6 +309,76 @@ impl FromSql for ColumnType {
292
309
}
293
310
}
294
311
312
+ #[ allow( clippy:: large_enum_variant) ]
313
+ #[ derive( Debug , Default , Clone , Serialize , Deserialize ) ]
314
+ #[ serde( untagged) ]
315
+ pub enum SqliteParam {
316
+ #[ default]
317
+ Null ,
318
+ Bool ( bool ) ,
319
+ Integer ( i64 ) ,
320
+ Real ( f64 ) ,
321
+ Text ( CompactString ) ,
322
+ Blob ( SmallVec < [ u8 ; 512 ] > ) ,
323
+ Json ( Box < RawValue > ) ,
324
+ }
325
+
326
+ impl From < & str > for SqliteParam {
327
+ fn from ( value : & str ) -> Self {
328
+ Self :: Text ( value. into ( ) )
329
+ }
330
+ }
331
+
332
+ impl From < Vec < u8 > > for SqliteParam {
333
+ fn from ( value : Vec < u8 > ) -> Self {
334
+ Self :: Blob ( value. into ( ) )
335
+ }
336
+ }
337
+
338
+ impl From < String > for SqliteParam {
339
+ fn from ( value : String ) -> Self {
340
+ Self :: Text ( value. into ( ) )
341
+ }
342
+ }
343
+
344
+ impl From < u16 > for SqliteParam {
345
+ fn from ( value : u16 ) -> Self {
346
+ Self :: Integer ( value as i64 )
347
+ }
348
+ }
349
+
350
+ impl From < i64 > for SqliteParam {
351
+ fn from ( value : i64 ) -> Self {
352
+ Self :: Integer ( value)
353
+ }
354
+ }
355
+
356
+ impl ToSql for SqliteParam {
357
+ fn to_sql ( & self ) -> rusqlite:: Result < ToSqlOutput < ' _ > > {
358
+ Ok ( match self {
359
+ SqliteParam :: Null => ToSqlOutput :: Owned ( Value :: Null ) ,
360
+ SqliteParam :: Bool ( v) => ToSqlOutput :: Owned ( Value :: Integer ( * v as i64 ) ) ,
361
+ SqliteParam :: Integer ( i) => ToSqlOutput :: Owned ( Value :: Integer ( * i) ) ,
362
+ SqliteParam :: Real ( f) => ToSqlOutput :: Owned ( Value :: Real ( * f) ) ,
363
+ SqliteParam :: Text ( t) => ToSqlOutput :: Borrowed ( ValueRef :: Text ( t. as_bytes ( ) ) ) ,
364
+ SqliteParam :: Blob ( b) => ToSqlOutput :: Borrowed ( ValueRef :: Blob ( b) ) ,
365
+ SqliteParam :: Json ( map) => ToSqlOutput :: Borrowed ( ValueRef :: Text ( map. get ( ) . as_bytes ( ) ) ) ,
366
+ } )
367
+ }
368
+ }
369
+
370
+ impl < ' a > ToSql for SqliteValueRef < ' a > {
371
+ fn to_sql ( & self ) -> rusqlite:: Result < ToSqlOutput < ' a > > {
372
+ Ok ( match self {
373
+ SqliteValueRef :: Null => ToSqlOutput :: Owned ( Value :: Null ) ,
374
+ SqliteValueRef :: Integer ( i) => ToSqlOutput :: Owned ( Value :: Integer ( * i) ) ,
375
+ SqliteValueRef :: Real ( f) => ToSqlOutput :: Owned ( Value :: Real ( * f) ) ,
376
+ SqliteValueRef :: Text ( t) => ToSqlOutput :: Borrowed ( ValueRef :: Text ( t. as_bytes ( ) ) ) ,
377
+ SqliteValueRef :: Blob ( b) => ToSqlOutput :: Borrowed ( ValueRef :: Blob ( b) ) ,
378
+ } )
379
+ }
380
+ }
381
+
295
382
#[ allow( clippy:: large_enum_variant) ]
296
383
#[ derive( Debug , Default , Clone , Serialize , Deserialize , PartialEq , Hash ) ]
297
384
#[ serde( untagged) ]
@@ -655,3 +742,39 @@ impl ToSql for ColumnName {
655
742
self . 0 . as_str ( ) . to_sql ( )
656
743
}
657
744
}
745
+
746
+ #[ cfg( test) ]
747
+ mod tests {
748
+ use super :: * ;
749
+
750
+ #[ test]
751
+ fn test_statement_serialization ( ) {
752
+ let s = serde_json:: to_string ( & vec ! [ Statement :: WithParams (
753
+ "select 1
754
+ from table
755
+ where column = ?"
756
+ . into( ) ,
757
+ vec![ "my-value" . into( ) ] ,
758
+ ) ] )
759
+ . unwrap ( ) ;
760
+ println ! ( "{s}" ) ;
761
+
762
+ let stmts: Vec < Statement > = serde_json:: from_str ( & s) . unwrap ( ) ;
763
+ println ! ( "stmts: {stmts:?}" ) ;
764
+
765
+ let json = r#"[["some statement",[1,"encodedID","nodeName",1,"Name","State",true,true,"",1234,1698084893487,1698084893487]]]"# ;
766
+
767
+ let value: serde_json:: Value = serde_json:: from_str ( json) . unwrap ( ) ;
768
+ println ! ( "value: {value:#?}" ) ;
769
+
770
+ let stmts: Vec < Statement > = serde_json:: from_str ( json) . unwrap ( ) ;
771
+ println ! ( "stmts: {stmts:?}" ) ;
772
+
773
+ let json = r#"[{"query": "some statement", "params": [1,"encodedID","nodeName",1,"Name","State",true,true,"",1234,1698084893487,1698084893487]}]"# ;
774
+ let value: serde_json:: Value = serde_json:: from_str ( json) . unwrap ( ) ;
775
+ println ! ( "value: {value:#?}" ) ;
776
+
777
+ let stmts: Vec < Statement > = serde_json:: from_str ( json) . unwrap ( ) ;
778
+ println ! ( "stmts: {stmts:?}" ) ;
779
+ }
780
+ }
0 commit comments