use crate::ast::*;
use crate::error::{Error, ErrorKind};
use base64::prelude::*;
use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive};
use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
use serde_json::{Number, Value as JsonValue};
use std::any::Any;
use std::fmt::Display;
use std::sync::Arc;
use std::{
borrow::{Borrow, Cow},
convert::TryFrom,
fmt,
str::FromStr,
};
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq)]
pub struct Raw<'a>(pub(crate) Value<'a>);
pub trait IntoRaw<'a> {
fn raw(self) -> Raw<'a>;
}
impl<'a, T> IntoRaw<'a> for T
where
T: Into<Value<'a>>,
{
fn raw(self) -> Raw<'a> {
Raw(self.into())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct NativeColumnType<'a> {
pub name: Cow<'a, str>,
pub length: Option<TypeDataLength>,
}
impl std::ops::Deref for NativeColumnType<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.name
}
}
impl From<&str> for NativeColumnType<'static> {
fn from(s: &str) -> Self {
Self {
name: Cow::Owned(s.to_uppercase()),
length: None,
}
}
}
impl From<(&str, Option<TypeDataLength>)> for NativeColumnType<'static> {
fn from((name, length): (&str, Option<TypeDataLength>)) -> Self {
Self {
name: Cow::Owned(name.to_uppercase()),
length,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Value<'a> {
pub typed: ValueType<'a>,
pub native_column_type: Option<NativeColumnType<'a>>,
}
impl<'a> Value<'a> {
pub fn native_column_type_name(&'a self) -> Option<&'a str> {
self.native_column_type.as_deref()
}
pub fn with_native_column_type<T: Into<NativeColumnType<'a>>>(mut self, column_type: Option<T>) -> Self {
self.native_column_type = column_type.map(|ct| ct.into());
self
}
pub fn int32<I>(value: I) -> Self
where
I: Into<i32>,
{
ValueType::int32(value).into_value()
}
pub fn int64<I>(value: I) -> Self
where
I: Into<i64>,
{
ValueType::int64(value).into_value()
}
pub fn numeric(value: BigDecimal) -> Self {
ValueType::numeric(value).into_value()
}
pub fn float(value: f32) -> Self {
ValueType::float(value).into_value()
}
pub fn double(value: f64) -> Self {
ValueType::double(value).into_value()
}
pub fn text<T>(value: T) -> Self
where
T: Into<Cow<'a, str>>,
{
ValueType::text(value).into_value()
}
pub fn enum_variant<T>(value: T) -> Self
where
T: Into<EnumVariant<'a>>,
{
ValueType::enum_variant(value).into_value()
}
pub fn enum_variant_with_name<T, U>(value: T, name: U) -> Self
where
T: Into<EnumVariant<'a>>,
U: Into<EnumName<'a>>,
{
ValueType::enum_variant_with_name(value, name).into_value()
}
pub fn enum_array<T>(value: T) -> Self
where
T: IntoIterator<Item = EnumVariant<'a>>,
{
ValueType::enum_array(value).into_value()
}
pub fn enum_array_with_name<T, U>(value: T, name: U) -> Self
where
T: IntoIterator<Item = EnumVariant<'a>>,
U: Into<EnumName<'a>>,
{
ValueType::enum_array_with_name(value, name).into_value()
}
pub fn bytes<B>(value: B) -> Self
where
B: Into<Cow<'a, [u8]>>,
{
ValueType::bytes(value).into_value()
}
pub fn boolean<B>(value: B) -> Self
where
B: Into<bool>,
{
ValueType::boolean(value).into_value()
}
pub fn character<C>(value: C) -> Self
where
C: Into<char>,
{
ValueType::character(value).into_value()
}
pub fn array<I, V>(value: I) -> Self
where
I: IntoIterator<Item = V>,
V: Into<Value<'a>>,
{
ValueType::array(value).into_value()
}
pub fn uuid(value: Uuid) -> Self {
ValueType::uuid(value).into_value()
}
pub fn datetime(value: DateTime<Utc>) -> Self {
ValueType::datetime(value).into_value()
}
pub fn date(value: NaiveDate) -> Self {
ValueType::date(value).into_value()
}
pub fn time(value: NaiveTime) -> Self {
ValueType::time(value).into_value()
}
pub fn json(value: serde_json::Value) -> Self {
ValueType::json(value).into_value()
}
pub fn xml<T>(value: T) -> Self
where
T: Into<Cow<'a, str>>,
{
ValueType::xml(value).into_value()
}
pub fn opaque<V: Opaque>(opaque: V, ty: OpaqueType) -> Self {
ValueType::opaque(opaque, ty).into_value()
}
pub fn is_null(&self) -> bool {
self.typed.is_null()
}
pub fn as_str(&self) -> Option<&str> {
self.typed.as_str()
}
pub fn is_text(&self) -> bool {
self.typed.is_text()
}
pub fn as_char(&self) -> Option<char> {
self.typed.as_char()
}
pub fn to_string(&self) -> Option<String> {
self.typed.to_string()
}
pub fn into_string(self) -> Option<String> {
self.typed.into_string()
}
pub fn is_bytes(&self) -> bool {
self.typed.is_bytes()
}
pub fn as_bytes(&self) -> Option<&[u8]> {
self.typed.as_bytes()
}
pub fn to_bytes(&self) -> Option<Vec<u8>> {
self.typed.to_bytes()
}
pub fn is_i32(&self) -> bool {
self.typed.is_i32()
}
pub fn is_i64(&self) -> bool {
self.typed.is_i64()
}
pub fn is_integer(&self) -> bool {
self.typed.is_integer()
}
pub fn as_i64(&self) -> Option<i64> {
self.typed.as_i64()
}
pub fn as_i32(&self) -> Option<i32> {
self.typed.as_i32()
}
pub fn as_integer(&self) -> Option<i64> {
self.typed.as_integer()
}
pub fn as_f64(&self) -> Option<f64> {
self.typed.as_f64()
}
pub fn as_f32(&self) -> Option<f32> {
self.typed.as_f32()
}
pub fn is_numeric(&self) -> bool {
self.typed.is_numeric()
}
pub fn into_numeric(self) -> Option<BigDecimal> {
self.typed.into_numeric()
}
pub fn as_numeric(&self) -> Option<&BigDecimal> {
self.typed.as_numeric()
}
pub fn is_bool(&self) -> bool {
self.typed.is_bool()
}
pub fn as_bool(&self) -> Option<bool> {
self.typed.as_bool()
}
pub fn is_array(&self) -> bool {
self.typed.is_array()
}
pub fn is_uuid(&self) -> bool {
self.typed.is_uuid()
}
pub fn as_uuid(&self) -> Option<Uuid> {
self.typed.as_uuid()
}
pub fn is_datetime(&self) -> bool {
self.typed.is_datetime()
}
pub fn as_datetime(&self) -> Option<DateTime<Utc>> {
self.typed.as_datetime()
}
pub fn is_date(&self) -> bool {
self.typed.is_date()
}
pub fn as_date(&self) -> Option<NaiveDate> {
self.typed.as_date()
}
pub fn is_time(&self) -> bool {
self.typed.is_time()
}
pub fn as_time(&self) -> Option<NaiveTime> {
self.typed.as_time()
}
pub fn is_json(&self) -> bool {
self.typed.is_json()
}
pub fn as_json(&self) -> Option<&serde_json::Value> {
self.typed.as_json()
}
pub fn into_json(self) -> Option<serde_json::Value> {
self.typed.into_json()
}
pub fn into_vec<T>(self) -> Option<Vec<T>>
where
T: TryFrom<Value<'a>>,
{
self.typed.into_vec()
}
pub fn to_vec<T>(&self) -> Option<Vec<T>>
where
T: TryFrom<Value<'a>>,
{
self.typed.to_vec()
}
pub fn null_int32() -> Self {
ValueType::Int32(None).into()
}
pub fn null_int64() -> Self {
ValueType::Int64(None).into()
}
pub fn null_float() -> Self {
ValueType::Float(None).into()
}
pub fn null_double() -> Self {
ValueType::Double(None).into()
}
pub fn null_text() -> Self {
ValueType::Text(None).into()
}
pub fn null_enum() -> Self {
ValueType::Enum(None, None).into()
}
pub fn null_enum_array() -> Self {
ValueType::EnumArray(None, None).into()
}
pub fn null_bytes() -> Self {
ValueType::Bytes(None).into()
}
pub fn null_boolean() -> Self {
ValueType::Boolean(None).into()
}
pub fn null_character() -> Self {
ValueType::Char(None).into()
}
pub fn null_array() -> Self {
ValueType::Array(None).into()
}
pub fn null_numeric() -> Self {
ValueType::Numeric(None).into()
}
pub fn null_json() -> Self {
ValueType::Json(None).into()
}
pub fn null_xml() -> Self {
ValueType::Xml(None).into()
}
pub fn null_uuid() -> Self {
ValueType::Uuid(None).into()
}
pub fn null_datetime() -> Self {
ValueType::DateTime(None).into()
}
pub fn null_date() -> Self {
ValueType::Date(None).into()
}
pub fn null_time() -> Self {
ValueType::Time(None).into()
}
}
impl Display for Value<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.typed.fmt(f)
}
}
impl<'a> From<ValueType<'a>> for Value<'a> {
fn from(inner: ValueType<'a>) -> Self {
Self {
typed: inner,
native_column_type: Default::default(),
}
}
}
impl<'a> From<Value<'a>> for ValueType<'a> {
fn from(val: Value<'a>) -> Self {
val.typed
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ValueType<'a> {
Int32(Option<i32>),
Int64(Option<i64>),
Float(Option<f32>),
Double(Option<f64>),
Text(Option<Cow<'a, str>>),
Enum(Option<EnumVariant<'a>>, Option<EnumName<'a>>),
EnumArray(Option<Vec<EnumVariant<'a>>>, Option<EnumName<'a>>),
Bytes(Option<Cow<'a, [u8]>>),
Boolean(Option<bool>),
Char(Option<char>),
Array(Option<Vec<Value<'a>>>),
Numeric(Option<BigDecimal>),
Json(Option<serde_json::Value>),
Xml(Option<Cow<'a, str>>),
Uuid(Option<Uuid>),
DateTime(Option<DateTime<Utc>>),
Date(Option<NaiveDate>),
Time(Option<NaiveTime>),
Opaque(OpaqueValue),
}
#[derive(Debug, Clone)]
pub struct OpaqueValue {
value: Arc<dyn Opaque>,
typ: OpaqueType,
}
impl OpaqueValue {
pub fn new<V: Opaque>(value: V, typ: OpaqueType) -> Self {
Self {
value: Arc::new(value),
typ,
}
}
pub fn typ(&self) -> &OpaqueType {
&self.typ
}
pub fn downcast_ref<T: Opaque>(&self) -> Option<&T> {
<dyn Any>::downcast_ref(self.value.as_ref())
}
}
impl PartialEq for OpaqueValue {
fn eq(&self, other: &OpaqueValue) -> bool {
self.value.opaque_eq(other.value.as_ref())
}
}
impl fmt::Display for OpaqueValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} as {}", self.value, self.typ)
}
}
pub trait Opaque: Any + Send + Sync + fmt::Debug + fmt::Display {
fn opaque_eq(&self, other: &dyn Opaque) -> bool;
}
impl<T> Opaque for T
where
T: Any + PartialEq + Send + Sync + fmt::Debug + fmt::Display,
{
fn opaque_eq(&self, other: &dyn Opaque) -> bool {
<dyn Any>::downcast_ref(other).is_some_and(|a| self.eq(a))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum OpaqueType {
Unknown,
Int32,
Int64,
Float,
Double,
Text,
Enum,
Bytes,
Boolean,
Char,
Array(Box<Self>),
Numeric,
Json,
Object,
Xml,
Uuid,
DateTime,
Date,
Time,
Tuple(Vec<(Self, Option<NativeColumnType<'static>>)>),
}
impl fmt::Display for OpaqueType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OpaqueType::Unknown => write!(f, "Unknown"),
OpaqueType::Int32 => write!(f, "Int32"),
OpaqueType::Int64 => write!(f, "Int64"),
OpaqueType::Float => write!(f, "Float"),
OpaqueType::Double => write!(f, "Double"),
OpaqueType::Text => write!(f, "Text"),
OpaqueType::Enum => write!(f, "Enum"),
OpaqueType::Bytes => write!(f, "Bytes"),
OpaqueType::Boolean => write!(f, "Boolean"),
OpaqueType::Char => write!(f, "Char"),
OpaqueType::Array(t) => {
write!(f, "Array<")?;
t.fmt(f)?;
write!(f, ">")
}
OpaqueType::Numeric => write!(f, "Numeric"),
OpaqueType::Json => write!(f, "Json"),
OpaqueType::Object => write!(f, "Object"),
OpaqueType::Xml => write!(f, "Xml"),
OpaqueType::Uuid => write!(f, "Uuid"),
OpaqueType::DateTime => write!(f, "DateTime"),
OpaqueType::Date => write!(f, "Date"),
OpaqueType::Time => write!(f, "Time"),
OpaqueType::Tuple(types) => {
write!(f, "Tuple<")?;
let len = types.len();
for (i, (t, _)) in types.iter().enumerate() {
write!(f, "{t}")?;
if i < (len - 1) {
write!(f, ", ")?;
}
}
write!(f, ">")
}
}
}
}
pub(crate) struct Params<'a>(pub(crate) &'a [Value<'a>]);
impl Display for Params<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let len = self.0.len();
write!(f, "[")?;
for (i, val) in self.0.iter().enumerate() {
write!(f, "{val}")?;
if i < (len - 1) {
write!(f, ",")?;
}
}
write!(f, "]")
}
}
impl fmt::Display for ValueType<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let res = match self {
ValueType::Int32(val) => val.map(|v| write!(f, "{v}")),
ValueType::Int64(val) => val.map(|v| write!(f, "{v}")),
ValueType::Float(val) => val.map(|v| write!(f, "{v}")),
ValueType::Double(val) => val.map(|v| write!(f, "{v}")),
ValueType::Text(val) => val.as_ref().map(|v| write!(f, "\"{v}\"")),
ValueType::Bytes(val) => val.as_ref().map(|v| write!(f, "<{} bytes blob>", v.len())),
ValueType::Enum(val, _) => val.as_ref().map(|v| write!(f, "\"{v}\"")),
ValueType::EnumArray(vals, _) => vals.as_ref().map(|vals| {
let len = vals.len();
write!(f, "[")?;
for (i, val) in vals.iter().enumerate() {
write!(f, "{val}")?;
if i < (len - 1) {
write!(f, ",")?;
}
}
write!(f, "]")
}),
ValueType::Boolean(val) => val.map(|v| write!(f, "{v}")),
ValueType::Char(val) => val.map(|v| write!(f, "'{v}'")),
ValueType::Array(vals) => vals.as_ref().map(|vals| {
let len = vals.len();
write!(f, "[")?;
for (i, val) in vals.iter().enumerate() {
write!(f, "{val}")?;
if i < (len - 1) {
write!(f, ",")?;
}
}
write!(f, "]")
}),
ValueType::Xml(val) => val.as_ref().map(|v| write!(f, "{v}")),
ValueType::Numeric(val) => val.as_ref().map(|v| write!(f, "{v}")),
ValueType::Json(val) => val.as_ref().map(|v| write!(f, "{v}")),
ValueType::Uuid(val) => val.map(|v| write!(f, "\"{v}\"")),
ValueType::DateTime(val) => val.map(|v| write!(f, "\"{v}\"")),
ValueType::Date(val) => val.map(|v| write!(f, "\"{v}\"")),
ValueType::Time(val) => val.map(|v| write!(f, "\"{v}\"")),
ValueType::Opaque(opaque) => Some(write!(f, "${opaque}")),
};
match res {
Some(r) => r,
None => write!(f, "null"),
}
}
}
impl<'a> From<Value<'a>> for serde_json::Value {
fn from(pv: Value<'a>) -> Self {
pv.typed.into()
}
}
impl<'a> From<ValueType<'a>> for serde_json::Value {
fn from(pv: ValueType<'a>) -> Self {
let res = match pv {
ValueType::Int32(i) => i.map(|i| serde_json::Value::Number(Number::from(i))),
ValueType::Int64(i) => i.map(|i| serde_json::Value::Number(Number::from(i))),
ValueType::Float(f) => f.map(|f| match Number::from_f64(f as f64) {
Some(number) => serde_json::Value::Number(number),
None => serde_json::Value::Null,
}),
ValueType::Double(f) => f.map(|f| match Number::from_f64(f) {
Some(number) => serde_json::Value::Number(number),
None => serde_json::Value::Null,
}),
ValueType::Text(cow) => cow.map(|cow| serde_json::Value::String(cow.into_owned())),
ValueType::Bytes(bytes) => bytes.map(|bytes| serde_json::Value::String(BASE64_STANDARD.encode(bytes))),
ValueType::Enum(cow, _) => cow.map(|cow| serde_json::Value::String(cow.into_owned())),
ValueType::EnumArray(values, _) => values.map(|values| {
serde_json::Value::Array(
values
.into_iter()
.map(|value| serde_json::Value::String(value.into_owned()))
.collect(),
)
}),
ValueType::Boolean(b) => b.map(serde_json::Value::Bool),
ValueType::Char(c) => c.map(|c| {
let bytes = [c as u8];
let s = std::str::from_utf8(&bytes)
.expect("interpret byte as UTF-8")
.to_string();
serde_json::Value::String(s)
}),
ValueType::Xml(cow) => cow.map(|cow| serde_json::Value::String(cow.into_owned())),
ValueType::Array(v) => {
v.map(|v| serde_json::Value::Array(v.into_iter().map(serde_json::Value::from).collect()))
}
ValueType::Numeric(d) => d.map(|d| serde_json::to_value(d.to_f64().unwrap()).unwrap()),
ValueType::Json(v) => v,
ValueType::Uuid(u) => u.map(|u| serde_json::Value::String(u.hyphenated().to_string())),
ValueType::DateTime(dt) => dt.map(|dt| serde_json::Value::String(dt.to_rfc3339())),
ValueType::Date(date) => date.map(|date| serde_json::Value::String(format!("{date}"))),
ValueType::Time(time) => time.map(|time| serde_json::Value::String(format!("{time}"))),
ValueType::Opaque(_) => todo!(),
};
match res {
Some(val) => val,
None => serde_json::Value::Null,
}
}
}
impl<'a> ValueType<'a> {
pub fn into_value(self) -> Value<'a> {
self.into()
}
pub(crate) fn int32<I>(value: I) -> Self
where
I: Into<i32>,
{
Self::Int32(Some(value.into()))
}
pub(crate) fn int64<I>(value: I) -> Self
where
I: Into<i64>,
{
Self::Int64(Some(value.into()))
}
pub(crate) fn numeric(value: BigDecimal) -> Self {
Self::Numeric(Some(value))
}
pub(crate) fn float(value: f32) -> Self {
Self::Float(Some(value))
}
pub(crate) fn double(value: f64) -> Self {
Self::Double(Some(value))
}
pub(crate) fn text<T>(value: T) -> Self
where
T: Into<Cow<'a, str>>,
{
Self::Text(Some(value.into()))
}
pub(crate) fn enum_variant<T>(value: T) -> Self
where
T: Into<EnumVariant<'a>>,
{
Self::Enum(Some(value.into()), None)
}
pub(crate) fn enum_variant_with_name<T, U>(value: T, enum_name: U) -> Self
where
T: Into<EnumVariant<'a>>,
U: Into<EnumName<'a>>,
{
Self::Enum(Some(value.into()), Some(enum_name.into()))
}
pub(crate) fn enum_array<T>(value: T) -> Self
where
T: IntoIterator<Item = EnumVariant<'a>>,
{
Self::EnumArray(Some(value.into_iter().collect()), None)
}
pub(crate) fn enum_array_with_name<T, U>(value: T, name: U) -> Self
where
T: IntoIterator<Item = EnumVariant<'a>>,
U: Into<EnumName<'a>>,
{
Self::EnumArray(Some(value.into_iter().collect()), Some(name.into()))
}
pub(crate) fn bytes<B>(value: B) -> Self
where
B: Into<Cow<'a, [u8]>>,
{
Self::Bytes(Some(value.into()))
}
pub(crate) fn boolean<B>(value: B) -> Self
where
B: Into<bool>,
{
Self::Boolean(Some(value.into()))
}
pub(crate) fn character<C>(value: C) -> Self
where
C: Into<char>,
{
Self::Char(Some(value.into()))
}
pub(crate) fn array<I, V>(value: I) -> Self
where
I: IntoIterator<Item = V>,
V: Into<Value<'a>>,
{
Self::Array(Some(value.into_iter().map(|v| v.into()).collect()))
}
pub(crate) fn uuid(value: Uuid) -> Self {
Self::Uuid(Some(value))
}
pub(crate) fn datetime(value: DateTime<Utc>) -> Self {
Self::DateTime(Some(value))
}
pub(crate) fn date(value: NaiveDate) -> Self {
Self::Date(Some(value))
}
pub(crate) fn time(value: NaiveTime) -> Self {
Self::Time(Some(value))
}
pub(crate) fn json(value: serde_json::Value) -> Self {
Self::Json(Some(value))
}
pub(crate) fn xml<T>(value: T) -> Self
where
T: Into<Cow<'a, str>>,
{
Self::Xml(Some(value.into()))
}
pub fn opaque<V: Opaque>(opaque: V, ty: OpaqueType) -> Self {
Self::Opaque(OpaqueValue::new(opaque, ty))
}
pub fn is_null(&self) -> bool {
match self {
Self::Int32(i) => i.is_none(),
Self::Int64(i) => i.is_none(),
Self::Float(i) => i.is_none(),
Self::Double(i) => i.is_none(),
Self::Text(t) => t.is_none(),
Self::Enum(e, _) => e.is_none(),
Self::EnumArray(e, _) => e.is_none(),
Self::Bytes(b) => b.is_none(),
Self::Boolean(b) => b.is_none(),
Self::Char(c) => c.is_none(),
Self::Array(v) => v.is_none(),
Self::Xml(s) => s.is_none(),
Self::Numeric(r) => r.is_none(),
Self::Uuid(u) => u.is_none(),
Self::DateTime(dt) => dt.is_none(),
Self::Date(d) => d.is_none(),
Self::Time(t) => t.is_none(),
Self::Json(json) => json.is_none(),
Self::Opaque(_) => false,
}
}
pub(crate) fn is_text(&self) -> bool {
matches!(self, Self::Text(_))
}
pub(crate) fn as_str(&self) -> Option<&str> {
match self {
Self::Text(Some(cow)) => Some(cow.borrow()),
Self::Bytes(Some(cow)) => std::str::from_utf8(cow.as_ref()).ok(),
_ => None,
}
}
pub(crate) fn as_char(&self) -> Option<char> {
match self {
Self::Char(c) => *c,
_ => None,
}
}
pub(crate) fn to_string(&self) -> Option<String> {
match self {
Self::Text(Some(cow)) => Some(cow.to_string()),
Self::Bytes(Some(cow)) => std::str::from_utf8(cow.as_ref()).map(|s| s.to_owned()).ok(),
_ => None,
}
}
pub(crate) fn into_string(self) -> Option<String> {
match self {
Self::Text(Some(cow)) => Some(cow.into_owned()),
Self::Bytes(Some(cow)) => String::from_utf8(cow.into_owned()).ok(),
_ => None,
}
}
pub(crate) fn is_bytes(&self) -> bool {
matches!(self, Self::Bytes(_))
}
pub(crate) fn as_bytes(&self) -> Option<&[u8]> {
match self {
Self::Text(Some(cow)) => Some(cow.as_ref().as_bytes()),
Self::Bytes(Some(cow)) => Some(cow.as_ref()),
_ => None,
}
}
pub(crate) fn to_bytes(&self) -> Option<Vec<u8>> {
match self {
Self::Text(Some(cow)) => Some(cow.to_string().into_bytes()),
Self::Bytes(Some(cow)) => Some(cow.to_vec()),
_ => None,
}
}
pub(crate) fn is_i32(&self) -> bool {
matches!(self, Self::Int32(_))
}
pub(crate) fn is_i64(&self) -> bool {
matches!(self, Self::Int64(_))
}
pub fn is_integer(&self) -> bool {
matches!(self, Self::Int32(_) | Self::Int64(_))
}
pub(crate) fn as_i64(&self) -> Option<i64> {
match self {
Self::Int64(i) => *i,
_ => None,
}
}
pub(crate) fn as_i32(&self) -> Option<i32> {
match self {
Self::Int32(i) => *i,
_ => None,
}
}
pub fn as_integer(&self) -> Option<i64> {
match self {
Self::Int32(i) => i.map(|i| i as i64),
Self::Int64(i) => *i,
_ => None,
}
}
pub(crate) fn as_f64(&self) -> Option<f64> {
match self {
Self::Double(Some(f)) => Some(*f),
_ => None,
}
}
pub(crate) fn as_f32(&self) -> Option<f32> {
match self {
Self::Float(Some(f)) => Some(*f),
_ => None,
}
}
pub(crate) fn is_numeric(&self) -> bool {
matches!(self, Self::Numeric(_) | Self::Float(_) | Self::Double(_))
}
pub(crate) fn into_numeric(self) -> Option<BigDecimal> {
match self {
Self::Numeric(d) => d,
Self::Float(f) => f.and_then(BigDecimal::from_f32),
Self::Double(f) => f.and_then(BigDecimal::from_f64),
_ => None,
}
}
pub(crate) fn as_numeric(&self) -> Option<&BigDecimal> {
match self {
Self::Numeric(d) => d.as_ref(),
_ => None,
}
}
pub(crate) fn is_bool(&self) -> bool {
match self {
Self::Boolean(_) => true,
Self::Int32(Some(i)) if *i == 0 || *i == 1 => true,
Self::Int64(Some(i)) if *i == 0 || *i == 1 => true,
_ => false,
}
}
pub(crate) fn as_bool(&self) -> Option<bool> {
match self {
Self::Boolean(b) => *b,
Self::Int32(Some(i)) if *i == 0 || *i == 1 => Some(*i == 1),
Self::Int64(Some(i)) if *i == 0 || *i == 1 => Some(*i == 1),
_ => None,
}
}
pub(crate) fn is_array(&self) -> bool {
matches!(self, Self::Array(_))
}
pub(crate) fn is_uuid(&self) -> bool {
matches!(self, Self::Uuid(_))
}
pub(crate) fn as_uuid(&self) -> Option<Uuid> {
match self {
Self::Uuid(u) => *u,
_ => None,
}
}
pub(crate) fn is_datetime(&self) -> bool {
matches!(self, Self::DateTime(_))
}
pub(crate) fn as_datetime(&self) -> Option<DateTime<Utc>> {
match self {
Self::DateTime(dt) => *dt,
_ => None,
}
}
pub(crate) fn is_date(&self) -> bool {
matches!(self, Self::Date(_))
}
pub(crate) fn as_date(&self) -> Option<NaiveDate> {
match self {
Self::Date(dt) => *dt,
_ => None,
}
}
pub(crate) fn is_time(&self) -> bool {
matches!(self, Self::Time(_))
}
pub(crate) fn as_time(&self) -> Option<NaiveTime> {
match self {
Self::Time(time) => *time,
_ => None,
}
}
pub(crate) fn is_json(&self) -> bool {
matches!(self, Self::Json(_))
}
pub(crate) fn as_json(&self) -> Option<&serde_json::Value> {
match self {
Self::Json(Some(j)) => Some(j),
_ => None,
}
}
pub(crate) fn into_json(self) -> Option<serde_json::Value> {
match self {
Self::Json(Some(j)) => Some(j),
_ => None,
}
}
pub(crate) fn into_vec<T>(self) -> Option<Vec<T>>
where
T: TryFrom<Value<'a>>,
{
match self {
Self::Array(Some(vec)) => vec.into_iter().map(T::try_from).collect::<Result<Vec<_>, _>>().ok(),
_ => None,
}
}
pub(crate) fn to_vec<T>(&self) -> Option<Vec<T>>
where
T: TryFrom<Value<'a>>,
{
match self {
Self::Array(Some(vec)) => vec
.clone()
.into_iter()
.map(T::try_from)
.collect::<Result<Vec<_>, _>>()
.ok(),
_ => None,
}
}
}
value!(val: i64, Int64, val);
value!(val: i32, Int32, val);
value!(val: bool, Boolean, val);
value!(val: &'a str, Text, val.into());
value!(val: &'a String, Text, val.into());
value!(val: &'a &str, Text, (*val).into());
value!(val: String, Text, val.into());
value!(val: usize, Int64, i64::try_from(val).unwrap());
value!(val: &'a [u8], Bytes, val.into());
value!(val: f64, Double, val);
value!(val: f32, Float, val);
value!(val: DateTime<Utc>, DateTime, val);
value!(val: chrono::NaiveTime, Time, val);
value!(val: chrono::NaiveDate, Date, val);
value!(val: BigDecimal, Numeric, val);
value!(val: JsonValue, Json, val);
value!(val: Uuid, Uuid, val);
impl<'a> TryFrom<Value<'a>> for i64 {
type Error = Error;
fn try_from(value: Value<'a>) -> Result<i64, Self::Error> {
value
.typed
.as_i64()
.ok_or_else(|| Error::builder(ErrorKind::conversion("Not an i64")).build())
}
}
impl<'a> TryFrom<Value<'a>> for i32 {
type Error = Error;
fn try_from(value: Value<'a>) -> Result<i32, Self::Error> {
value
.as_i32()
.ok_or_else(|| Error::builder(ErrorKind::conversion("Not an i32")).build())
}
}
impl<'a> TryFrom<Value<'a>> for BigDecimal {
type Error = Error;
fn try_from(value: Value<'a>) -> Result<BigDecimal, Self::Error> {
value
.into_numeric()
.ok_or_else(|| Error::builder(ErrorKind::conversion("Not a decimal")).build())
}
}
impl<'a> TryFrom<Value<'a>> for f64 {
type Error = Error;
fn try_from(value: Value<'a>) -> Result<f64, Self::Error> {
value
.as_f64()
.ok_or_else(|| Error::builder(ErrorKind::conversion("Not a f64")).build())
}
}
impl<'a> TryFrom<Value<'a>> for String {
type Error = Error;
fn try_from(value: Value<'a>) -> Result<String, Self::Error> {
value
.into_string()
.ok_or_else(|| Error::builder(ErrorKind::conversion("Not a string")).build())
}
}
impl<'a> TryFrom<Value<'a>> for bool {
type Error = Error;
fn try_from(value: Value<'a>) -> Result<bool, Self::Error> {
value
.as_bool()
.ok_or_else(|| Error::builder(ErrorKind::conversion("Not a bool")).build())
}
}
impl<'a> TryFrom<Value<'a>> for DateTime<Utc> {
type Error = Error;
fn try_from(value: Value<'a>) -> Result<DateTime<Utc>, Self::Error> {
value
.as_datetime()
.ok_or_else(|| Error::builder(ErrorKind::conversion("Not a datetime")).build())
}
}
impl<'a> TryFrom<&Value<'a>> for Option<std::net::IpAddr> {
type Error = Error;
fn try_from(value: &Value<'a>) -> Result<Option<std::net::IpAddr>, Self::Error> {
match &value.typed {
ValueType::Text(Some(_)) => {
let text = value.typed.as_str().unwrap();
match std::net::IpAddr::from_str(text) {
Ok(ip) => Ok(Some(ip)),
Err(e) => Err(e.into()),
}
}
ValueType::Bytes(Some(_)) => {
let text = value.typed.as_str().unwrap();
match std::net::IpAddr::from_str(text) {
Ok(ip) => Ok(Some(ip)),
Err(e) => Err(e.into()),
}
}
_ if value.typed.is_null() => Ok(None),
v => {
let kind =
ErrorKind::conversion(format!("Couldn't convert value of type `{v:?}` to std::net::IpAddr."));
Err(Error::builder(kind).build())
}
}
}
}
impl<'a> TryFrom<&Value<'a>> for Option<uuid::Uuid> {
type Error = Error;
fn try_from(value: &Value<'a>) -> Result<Option<uuid::Uuid>, Self::Error> {
match &value.typed {
ValueType::Uuid(uuid) => Ok(*uuid),
ValueType::Text(Some(_)) => {
let text = value.typed.as_str().unwrap();
match uuid::Uuid::from_str(text) {
Ok(ip) => Ok(Some(ip)),
Err(e) => Err(e.into()),
}
}
ValueType::Bytes(Some(_)) => {
let text = value.typed.as_str().unwrap();
match uuid::Uuid::from_str(text) {
Ok(ip) => Ok(Some(ip)),
Err(e) => Err(e.into()),
}
}
_ if value.typed.is_null() => Ok(None),
v => {
let kind = ErrorKind::conversion(format!("Couldn't convert value of type `{v:?}` to uuid::Uuid."));
Err(Error::builder(kind).build())
}
}
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Values<'a> {
pub(crate) rows: Vec<Row<'a>>,
}
impl<'a> Values<'a> {
pub fn empty() -> Self {
Self { rows: Vec::new() }
}
pub fn new(rows: Vec<Row<'a>>) -> Self {
Self { rows }
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
rows: Vec::with_capacity(capacity),
}
}
pub fn push<T>(&mut self, row: T)
where
T: Into<Row<'a>>,
{
self.rows.push(row.into());
}
pub fn len(&self) -> usize {
self.rows.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn row_len(&self) -> usize {
match self.rows.split_first() {
Some((row, _)) => row.len(),
None => 0,
}
}
pub fn flatten_row(self) -> Option<Row<'a>> {
let mut result = Row::with_capacity(self.len());
for mut row in self.rows.into_iter() {
match row.pop() {
Some(value) => result.push(value),
None => return None,
}
}
Some(result)
}
}
impl<'a, I, R> From<I> for Values<'a>
where
I: Iterator<Item = R>,
R: Into<Row<'a>>,
{
fn from(rows: I) -> Self {
Self {
rows: rows.map(|r| r.into()).collect(),
}
}
}
impl<'a> IntoIterator for Values<'a> {
type Item = Row<'a>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.rows.into_iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn a_parameterized_value_of_ints32_can_be_converted_into_a_vec() {
let pv = Value::array(vec![1]);
let values: Vec<i32> = pv.typed.into_vec().expect("convert into Vec<i32>");
assert_eq!(values, vec![1]);
}
#[test]
fn a_parameterized_value_of_ints64_can_be_converted_into_a_vec() {
let pv = Value::array(vec![1_i64]);
let values: Vec<i64> = pv.typed.into_vec().expect("convert into Vec<i64>");
assert_eq!(values, vec![1]);
}
#[test]
fn a_parameterized_value_of_reals_can_be_converted_into_a_vec() {
let pv = Value::array(vec![1.0]);
let values: Vec<f64> = pv.typed.into_vec().expect("convert into Vec<f64>");
assert_eq!(values, vec![1.0]);
}
#[test]
fn a_parameterized_value_of_texts_can_be_converted_into_a_vec() {
let pv = Value::array(vec!["test"]);
let values: Vec<String> = pv.typed.into_vec().expect("convert into Vec<String>");
assert_eq!(values, vec!["test"]);
}
#[test]
fn a_parameterized_value_of_booleans_can_be_converted_into_a_vec() {
let pv = Value::array(vec![true]);
let values: Vec<bool> = pv.typed.into_vec().expect("convert into Vec<bool>");
assert_eq!(values, vec![true]);
}
#[test]
fn a_parameterized_value_of_datetimes_can_be_converted_into_a_vec() {
let datetime = DateTime::from_str("2019-07-27T05:30:30Z").expect("parsing date/time");
let pv = Value::array(vec![datetime]);
let values: Vec<DateTime<Utc>> = pv.typed.into_vec().expect("convert into Vec<DateTime>");
assert_eq!(values, vec![datetime]);
}
#[test]
fn a_parameterized_value_of_an_array_cant_be_converted_into_a_vec_of_the_wrong_type() {
let pv = Value::array(vec![1]);
let rslt: Option<Vec<f64>> = pv.typed.into_vec();
assert!(rslt.is_none());
}
#[test]
fn display_format_for_datetime() {
let dt: DateTime<Utc> = DateTime::from_str("2019-07-27T05:30:30Z").expect("failed while parsing date");
let pv = Value::datetime(dt);
assert_eq!(format!("{pv}"), "\"2019-07-27 05:30:30 UTC\"");
}
#[test]
fn display_format_for_date() {
let date = NaiveDate::from_ymd_opt(2022, 8, 11).unwrap();
let pv = Value::date(date);
assert_eq!(format!("{pv}"), "\"2022-08-11\"");
}
#[test]
fn display_format_for_time() {
let time = NaiveTime::from_hms_opt(16, 17, 00).unwrap();
let pv = Value::time(time);
assert_eq!(format!("{pv}"), "\"16:17:00\"");
}
#[test]
fn display_format_for_uuid() {
let id = Uuid::from_str("67e5504410b1426f9247bb680e5fe0c8").unwrap();
let pv = Value::uuid(id);
assert_eq!(format!("{pv}"), "\"67e55044-10b1-426f-9247-bb680e5fe0c8\"");
}
}