33 releases (breaking)
0.36.0 | Aug 22, 2024 |
---|---|
0.35.0 | Feb 19, 2024 |
0.34.0 | Nov 14, 2023 |
0.33.1 | May 18, 2023 |
0.11.0 | Jun 2, 2017 |
#120 in Encoding
12,760 downloads per month
Used in 19 crates
(13 directly)
68KB
1.5K
SLoC
serde_rusqlite
Documentation
Usage
Add this to your Cargo.toml:
[dependencies]
serde_rusqlite = "0.36.0"
Serde Rusqlite
This crate provides convenience functions to bridge serde and rusqlite. With their help
you can "deserialize" rusqlite Row
's into serde Deserialize
types and "serialize" types
implementing Serialize
into bound query arguments (positional or named) that rusqlite expects.
Serialization of named bound arguments is only supported from struct
s and map
s because other
serde types lack column name information. Likewise, serialization of positional bound arguments
is only supported from tuple
s, sequence
s and primitive non-iterable types. In the latter case
the result will be single-element vector. Each serialized field or element must implement
rusqlite::types::ToSql
.
For deserialization you can use two families of functions: from_*()
and from_*_with_columns()
.
The most used one is the former. The latter allows you to specify column names for types that need
them, but don't supply them. This includes different Map
types like HashMap
. Specifying columns
for deserialization into e.g. struct
doesn't have any effect as the field list of the struct itself
will be used in any case.
SQLite only supports 5 types: NULL
(None
), INTEGER
(i64
), REAL
(f64
), TEXT
(String
)
and BLOB
(Vec<u8>
). Corresponding rust types are inside brackets.
Some types employ non-trivial handling, these are described below:
-
Serialization of
u64
will fail if it can't be represented byi64
due to sqlite limitations. -
Simple
enum
s will be serialized as strings so:enum Gender { M, F, }
will have two possible
TEXT
options in the database "M" and "F". Deserialization intoenum
fromTEXT
is also supported. -
bool
s are serialized asINTEGER
s 0 or 1, can be deserialized fromINTEGER
andREAL
where 0 and 0.0 arefalse
, anything else istrue
. -
f64
andf32
values ofNaN
are serialized asNULL
s. When deserializing such valueOption<f64>
will have value ofNone
andf64
will have value ofNaN
. The same applies tof32
. -
Bytes
,ByteBuf
fromserde_bytes
are supported as optimized way of handlingBLOB
s. -
unit
serializes toNULL
. -
Only
sequence
s ofu8
are serialized and deserialized,BLOB
database type is used. It's more optimal though to useBytes
andByteBuf
fromserde_bytes
for such fields. -
unit_struct
serializes tostruct
name asTEXT
, when deserializing the check is made to ensure thatstruct
name coincides with the string in the database.
Examples
use serde_derive::{Deserialize, Serialize};
use serde_rusqlite::*;
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Example {
id: i64,
name: String,
}
let connection = rusqlite::Connection::open_in_memory().unwrap();
connection.execute("CREATE TABLE example (id INT, name TEXT)", []).unwrap();
// using structure to generate named bound query arguments
let row1 = Example { id: 1, name: "first name".into() };
connection.execute("INSERT INTO example (id, name) VALUES (:id, :name)", to_params_named(&row1).unwrap().to_slice().as_slice()).unwrap();
// and limiting the set of fields that are to be serialized
let row2 = Example { id: 10, name: "second name".into() };
connection.execute("INSERT INTO example (id, name) VALUES (2, :name)", to_params_named_with_fields(&row2, &["name"]).unwrap().to_slice().as_slice()).unwrap();
// using tuple to generate positional bound query arguments
let row2 = (3, "third name");
connection.execute("INSERT INTO example (id, name) VALUES (?, ?)", to_params(&row2).unwrap()).unwrap();
// deserializing using query() and from_rows(), the most efficient way
let mut statement = connection.prepare("SELECT * FROM example").unwrap();
let mut res = from_rows::<Example>(statement.query([]).unwrap());
assert_eq!(res.next().unwrap().unwrap(), row1);
assert_eq!(res.next().unwrap().unwrap(), Example { id: 2, name: "second name".into() });
// deserializing using query_and_then() and from_row(), incurs extra overhead in from_row() call
let mut statement = connection.prepare("SELECT * FROM example").unwrap();
let mut rows = statement.query_and_then([], from_row::<Example>).unwrap();
assert_eq!(rows.next().unwrap().unwrap(), row1);
assert_eq!(rows.next().unwrap().unwrap(), Example { id: 2, name: "second name".into() });
// deserializing using query_and_then() and from_row_with_columns(), better performance than from_row()
let mut statement = connection.prepare("SELECT * FROM example").unwrap();
let columns = columns_from_statement(&statement);
let mut rows = statement.query_and_then([], |row| from_row_with_columns::<Example>(row, &columns)).unwrap();
assert_eq!(rows.next().unwrap().unwrap(), row1);
assert_eq!(rows.next().unwrap().unwrap(), Example { id: 2, name: "second name".into() });
// deserializing using query() and from_rows_ref()
let mut statement = connection.prepare("SELECT * FROM example").unwrap();
let mut rows = statement.query([]).unwrap();
{
// only first record is deserialized here
let mut res = from_rows_ref::<Example>(&mut rows);
assert_eq!(res.next().unwrap().unwrap(), row1);
}
// the second record is deserialized using the original Rows iterator
assert_eq!(from_row::<Example>(&rows.next().unwrap().unwrap()).unwrap(), Example { id: 2, name: "second name".into() });
License: MIT OR Apache-2.0
Dependencies
~22MB
~425K SLoC