use bytes::Bytes;
use crate::tvp::TvpData;
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum SqlValue {
Null,
Bool(bool),
TinyInt(u8),
SmallInt(i16),
Int(i32),
BigInt(i64),
Float(f32),
Double(f64),
String(String),
Binary(Bytes),
#[cfg(feature = "decimal")]
Decimal(rust_decimal::Decimal),
#[cfg(feature = "decimal")]
Money(rust_decimal::Decimal),
#[cfg(feature = "decimal")]
SmallMoney(rust_decimal::Decimal),
#[cfg(feature = "uuid")]
Uuid(uuid::Uuid),
#[cfg(feature = "chrono")]
Date(chrono::NaiveDate),
#[cfg(feature = "chrono")]
Time(chrono::NaiveTime),
#[cfg(feature = "chrono")]
DateTime(chrono::NaiveDateTime),
#[cfg(feature = "chrono")]
SmallDateTime(chrono::NaiveDateTime),
#[cfg(feature = "chrono")]
DateTimeOffset(chrono::DateTime<chrono::FixedOffset>),
#[cfg(feature = "json")]
Json(serde_json::Value),
Xml(String),
Tvp(Box<TvpData>),
}
impl SqlValue {
#[must_use]
pub fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
#[must_use]
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_i32(&self) -> Option<i32> {
match self {
Self::Int(v) => Some(*v),
Self::SmallInt(v) => Some(*v as i32),
Self::TinyInt(v) => Some(*v as i32),
_ => None,
}
}
#[must_use]
pub fn as_i64(&self) -> Option<i64> {
match self {
Self::BigInt(v) => Some(*v),
Self::Int(v) => Some(*v as i64),
Self::SmallInt(v) => Some(*v as i64),
Self::TinyInt(v) => Some(*v as i64),
_ => None,
}
}
#[must_use]
pub fn as_f64(&self) -> Option<f64> {
match self {
Self::Double(v) => Some(*v),
Self::Float(v) => Some(*v as f64),
_ => None,
}
}
#[must_use]
pub fn as_str(&self) -> Option<&str> {
match self {
Self::String(v) => Some(v),
Self::Xml(v) => Some(v),
_ => None,
}
}
#[must_use]
pub fn as_bytes(&self) -> Option<&[u8]> {
match self {
Self::Binary(v) => Some(v),
_ => None,
}
}
#[must_use]
pub fn type_name(&self) -> &'static str {
match self {
Self::Null => "NULL",
Self::Bool(_) => "BIT",
Self::TinyInt(_) => "TINYINT",
Self::SmallInt(_) => "SMALLINT",
Self::Int(_) => "INT",
Self::BigInt(_) => "BIGINT",
Self::Float(_) => "REAL",
Self::Double(_) => "FLOAT",
Self::String(_) => "NVARCHAR",
Self::Binary(_) => "VARBINARY",
#[cfg(feature = "decimal")]
Self::Decimal(_) => "DECIMAL",
#[cfg(feature = "decimal")]
Self::Money(_) => "MONEY",
#[cfg(feature = "decimal")]
Self::SmallMoney(_) => "SMALLMONEY",
#[cfg(feature = "uuid")]
Self::Uuid(_) => "UNIQUEIDENTIFIER",
#[cfg(feature = "chrono")]
Self::Date(_) => "DATE",
#[cfg(feature = "chrono")]
Self::Time(_) => "TIME",
#[cfg(feature = "chrono")]
Self::DateTime(_) => "DATETIME2",
#[cfg(feature = "chrono")]
Self::SmallDateTime(_) => "SMALLDATETIME",
#[cfg(feature = "chrono")]
Self::DateTimeOffset(_) => "DATETIMEOFFSET",
#[cfg(feature = "json")]
Self::Json(_) => "JSON",
Self::Xml(_) => "XML",
Self::Tvp(_) => "TVP",
}
}
#[must_use]
pub fn as_tvp(&self) -> Option<&TvpData> {
match self {
Self::Tvp(v) => Some(v),
_ => None,
}
}
}
impl Default for SqlValue {
fn default() -> Self {
Self::Null
}
}
impl From<bool> for SqlValue {
fn from(v: bool) -> Self {
Self::Bool(v)
}
}
impl From<i32> for SqlValue {
fn from(v: i32) -> Self {
Self::Int(v)
}
}
impl From<i64> for SqlValue {
fn from(v: i64) -> Self {
Self::BigInt(v)
}
}
impl From<f32> for SqlValue {
fn from(v: f32) -> Self {
Self::Float(v)
}
}
impl From<f64> for SqlValue {
fn from(v: f64) -> Self {
Self::Double(v)
}
}
impl From<String> for SqlValue {
fn from(v: String) -> Self {
Self::String(v)
}
}
impl From<&str> for SqlValue {
fn from(v: &str) -> Self {
Self::String(v.to_owned())
}
}
impl<T> From<Option<T>> for SqlValue
where
T: Into<SqlValue>,
{
fn from(v: Option<T>) -> Self {
match v {
Some(v) => v.into(),
None => Self::Null,
}
}
}
#[cfg(feature = "uuid")]
impl From<uuid::Uuid> for SqlValue {
fn from(v: uuid::Uuid) -> Self {
Self::Uuid(v)
}
}
#[cfg(feature = "decimal")]
impl From<rust_decimal::Decimal> for SqlValue {
fn from(v: rust_decimal::Decimal) -> Self {
Self::Decimal(v)
}
}
#[cfg(feature = "chrono")]
impl From<chrono::NaiveDate> for SqlValue {
fn from(v: chrono::NaiveDate) -> Self {
Self::Date(v)
}
}
#[cfg(feature = "chrono")]
impl From<chrono::NaiveDateTime> for SqlValue {
fn from(v: chrono::NaiveDateTime) -> Self {
Self::DateTime(v)
}
}
#[cfg(feature = "json")]
impl From<serde_json::Value> for SqlValue {
fn from(v: serde_json::Value) -> Self {
Self::Json(v)
}
}
impl From<TvpData> for SqlValue {
fn from(v: TvpData) -> Self {
Self::Tvp(Box::new(v))
}
}
#[cfg(feature = "decimal")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Money(pub rust_decimal::Decimal);
#[cfg(feature = "decimal")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SmallMoney(pub rust_decimal::Decimal);
#[cfg(feature = "chrono")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SmallDateTime(pub chrono::NaiveDateTime);
#[cfg(feature = "decimal")]
impl From<Money> for SqlValue {
fn from(v: Money) -> Self {
Self::Money(v.0)
}
}
#[cfg(feature = "decimal")]
impl From<SmallMoney> for SqlValue {
fn from(v: SmallMoney) -> Self {
Self::SmallMoney(v.0)
}
}
#[cfg(feature = "chrono")]
impl From<SmallDateTime> for SqlValue {
fn from(v: SmallDateTime) -> Self {
Self::SmallDateTime(v.0)
}
}