mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-26 11:31:37 +08:00
Add ToSql implementations for u64 and usize
This commit is contained in:
parent
8841187717
commit
b0ade73f43
@ -11,22 +11,22 @@
|
||||
//! The number situation is a little complicated due to the fact that all
|
||||
//! numbers in SQLite are stored as `INTEGER` (`i64`) or `REAL` (`f64`).
|
||||
//!
|
||||
//! `ToSql` cannot fail and is therefore implemented for all number types that
|
||||
//! can be losslessly converted to one of these types, i.e. `u8`, `u16`, `u32`,
|
||||
//! `i8`, `i16`, `i32`, `i64`, `isize`, `f32` and `f64`. It is *not* implemented
|
||||
//! for `u64` or `usize`.
|
||||
//!
|
||||
//! `FromSql` can fail, and is implemented for all primitive number types,
|
||||
//! however you may get a runtime error or rounding depending on the types
|
||||
//! and values.
|
||||
//! `ToSql` and `FromSql` are implemented for all primitive number types.
|
||||
//! `FromSql` has different behaviour depending on the SQL and Rust types, and
|
||||
//! the value.
|
||||
//!
|
||||
//! * `INTEGER` to integer: returns an `Error::IntegralValueOutOfRange` error
|
||||
//! if the value does not fit.
|
||||
//! if the value does not fit in the Rust type.
|
||||
//! * `REAL` to integer: always returns an `Error::InvalidColumnType` error.
|
||||
//! * `INTEGER` to float: casts using `as` operator. Never fails.
|
||||
//! * `REAL` to float: casts using `as` operator. Never fails.
|
||||
//!
|
||||
//! Additionally, if the `time` feature is enabled, implementations are
|
||||
//! `ToSql` always succeeds except when storing a `u64` or `usize` value that
|
||||
//! cannot fit in an `INTEGER` (`i64`). Also note that SQLite ignores column
|
||||
//! types, so if you store an `i64` in a column with type `REAL` it will be
|
||||
//! stored as an `INTEGER`, not a `REAL`.
|
||||
//!
|
||||
//! If the `time` feature is enabled, implementations are
|
||||
//! provided for `time::OffsetDateTime` that use the RFC 3339 date/time format,
|
||||
//! `"%Y-%m-%dT%H:%M:%S.%fZ"`, to store time values as strings. These values
|
||||
//! can be parsed by SQLite's builtin
|
||||
@ -398,7 +398,7 @@ mod test {
|
||||
assert_eq!(res.unwrap(), $expected_value);
|
||||
$db_etc.delete_statement.execute(NO_PARAMS).unwrap();
|
||||
};
|
||||
($db_etc:ident, $insert_value:expr, $get_type:ty, expect_error) => {
|
||||
($db_etc:ident, $insert_value:expr, $get_type:ty, expect_from_sql_error) => {
|
||||
$db_etc
|
||||
.insert_statement
|
||||
.execute(params![$insert_value])
|
||||
@ -409,6 +409,12 @@ mod test {
|
||||
res.unwrap_err();
|
||||
$db_etc.delete_statement.execute(NO_PARAMS).unwrap();
|
||||
};
|
||||
($db_etc:ident, $insert_value:expr, $get_type:ty, expect_to_sql_error) => {
|
||||
$db_etc
|
||||
.insert_statement
|
||||
.execute(params![$insert_value])
|
||||
.unwrap_err();
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -446,22 +452,28 @@ mod test {
|
||||
test_conversion!(db_etc, i64::MIN, i64, expect i64::MIN);
|
||||
test_conversion!(db_etc, i64::MAX, i64, expect i64::MAX);
|
||||
test_conversion!(db_etc, i64::MAX, u64, expect i64::MAX as u64);
|
||||
test_conversion!(db_etc, 100usize, usize, expect 100usize);
|
||||
test_conversion!(db_etc, 100u64, u64, expect 100u64);
|
||||
test_conversion!(db_etc, i64::MAX as u64, u64, expect i64::MAX as u64);
|
||||
|
||||
// Out-of-range integral conversions.
|
||||
test_conversion!(db_etc, 200u8, i8, expect_error);
|
||||
test_conversion!(db_etc, 400u16, i8, expect_error);
|
||||
test_conversion!(db_etc, 400u16, u8, expect_error);
|
||||
test_conversion!(db_etc, -1i8, u8, expect_error);
|
||||
test_conversion!(db_etc, i64::MIN, u64, expect_error);
|
||||
test_conversion!(db_etc, 200u8, i8, expect_from_sql_error);
|
||||
test_conversion!(db_etc, 400u16, i8, expect_from_sql_error);
|
||||
test_conversion!(db_etc, 400u16, u8, expect_from_sql_error);
|
||||
test_conversion!(db_etc, -1i8, u8, expect_from_sql_error);
|
||||
test_conversion!(db_etc, i64::MIN, u64, expect_from_sql_error);
|
||||
test_conversion!(db_etc, u64::MAX, i64, expect_to_sql_error);
|
||||
test_conversion!(db_etc, u64::MAX, u64, expect_to_sql_error);
|
||||
test_conversion!(db_etc, i64::MAX as u64 + 1, u64, expect_to_sql_error);
|
||||
|
||||
// Integer to float, always works.
|
||||
// FromSql integer to float, always works.
|
||||
test_conversion!(db_etc, i64::MIN, f32, expect i64::MIN as f32);
|
||||
test_conversion!(db_etc, i64::MAX, f32, expect i64::MAX as f32);
|
||||
test_conversion!(db_etc, i64::MIN, f64, expect i64::MIN as f64);
|
||||
test_conversion!(db_etc, i64::MAX, f64, expect i64::MAX as f64);
|
||||
|
||||
// Float to int conversion, never works even if the actual value is an
|
||||
// integer.
|
||||
test_conversion!(db_etc, 0f64, i64, expect_error);
|
||||
// FromSql float to int conversion, never works even if the actual value
|
||||
// is an integer.
|
||||
test_conversion!(db_etc, 0f64, i64, expect_from_sql_error);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
use super::{Null, Value, ValueRef};
|
||||
#[cfg(feature = "array")]
|
||||
use crate::vtab::array::Array;
|
||||
use crate::Result;
|
||||
use crate::{Error, Result};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
/// `ToSqlOutput` represents the possible output types for implementors of the
|
||||
/// `ToSqlOutput` represents the possible output types for implementers of the
|
||||
/// `ToSql` trait.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
@ -86,7 +87,8 @@ impl ToSql for ToSqlOutput<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for types that can be converted into SQLite values.
|
||||
/// A trait for types that can be converted into SQLite values. Returns
|
||||
/// `Error::ToSqlConversionFailure` if the conversion fails.
|
||||
pub trait ToSql {
|
||||
/// Converts Rust value to SQLite value
|
||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>>;
|
||||
@ -157,6 +159,25 @@ to_sql_self!(i128);
|
||||
#[cfg(feature = "uuid")]
|
||||
to_sql_self!(uuid::Uuid);
|
||||
|
||||
macro_rules! to_sql_self_fallible(
|
||||
($t:ty) => (
|
||||
impl ToSql for $t {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
|
||||
Ok(ToSqlOutput::Owned(Value::Integer(
|
||||
i64::try_from(*self).map_err(
|
||||
// TODO: Include the values in the error message.
|
||||
|err| Error::ToSqlConversionFailure(err.into())
|
||||
)?
|
||||
)))
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Special implementations for usize and u64 because these conversions can fail.
|
||||
to_sql_self_fallible!(u64);
|
||||
to_sql_self_fallible!(usize);
|
||||
|
||||
impl<T: ?Sized> ToSql for &'_ T
|
||||
where
|
||||
T: ToSql,
|
||||
|
Loading…
Reference in New Issue
Block a user