Implement Bindable for Option<T>

Option<T> is generally used to represent either a T or a null value. In SQLite,
it makes sense to model this as either a regular T binding (when the option is
Some) or a regular NULL binding (when the option is None). This commit
implements Bindable for any Option<T> where T is already Bindable, allowing
those Options to be used directly with statements, filling in NULL where needed.

No new unsafe code is needed. Tests are included.
This commit is contained in:
Daniel Dulaney 2019-09-22 23:51:52 -04:00
parent 2e280411b0
commit 7fbbb6438d
2 changed files with 33 additions and 0 deletions

View File

@ -229,6 +229,17 @@ impl Bindable for () {
}
}
impl<T: Bindable> Bindable for Option<T> {
#[inline]
fn bind(self, statement: &mut Statement, i: usize) -> Result<()> {
debug_assert!(i > 0, "the indexing starts from 1");
match self {
Some(inner) => inner.bind(statement, i),
None => ().bind(statement, i),
}
}
}
impl Readable for Value {
fn read(statement: &Statement, i: usize) -> Result<Self> {
Ok(match statement.kind(i) {

View File

@ -186,6 +186,28 @@ fn statement_bind() {
assert_eq!(ok!(statement.next()), State::Done);
}
#[test]
fn statement_optional_bind() {
let connection = setup_users(":memory:");
let statement = "INSERT INTO users VALUES (?, ?, ?, ?)";
let mut statement = ok!(connection.prepare(statement));
ok!(statement.bind(1, None::<i64>));
ok!(statement.bind(2, None::<&str>));
ok!(statement.bind(3, None::<f64>));
ok!(statement.bind(4, None::<&[u8]>));
assert_eq!(ok!(statement.next()), State::Done);
let statement = "INSERT INTO users VALUES (?, ?, ?, ?)";
let mut statement = ok!(connection.prepare(statement));
ok!(statement.bind(1, Some(2i64)));
ok!(statement.bind(2, Some("Bob")));
ok!(statement.bind(3, Some(69.42)));
ok!(statement.bind(4, Some(&[0x69u8, 0x42u8][..])));
assert_eq!(ok!(statement.next()), State::Done);
}
#[test]
fn statement_count() {
let connection = setup_users(":memory:");