use std::os::unix::ffi::{OsStrExt, OsStringExt};
use crate::{
db::{self, Bindable, StatementContext, StatementRow},
schema::{datum::Datum, relation::RelationData},
DBResult, Error,
};
use super::{BorrowedDatum, DatumDiscriminator, DatumDiscriminatorRef, OwnedDatum};
macro_rules! borrowed_int {
($t:ident) => {
impl BorrowedDatum<'_, isize> for $t {
fn as_owned(&self) -> isize {
(*self) as isize
}
}
impl BorrowedDatum<'_, i64> for $t {
fn as_owned(&self) -> i64 {
(*self) as i64
}
}
impl BorrowedDatum<'_, i32> for $t {
fn as_owned(&self) -> i32 {
(*self) as i32
}
}
};
}
macro_rules! borrowed_uint {
($t:ident) => {
impl BorrowedDatum<'_, usize> for $t {
fn as_owned(&self) -> usize {
(*self) as usize
}
}
impl BorrowedDatum<'_, u64> for $t {
fn as_owned(&self) -> u64 {
(*self) as u64
}
}
impl BorrowedDatum<'_, u32> for $t {
fn as_owned(&self) -> u32 {
(*self) as u32
}
}
};
}
#[cfg(feature = "time")]
const _: () = {
use crate::Error;
impl OwnedDatum for time::OffsetDateTime {
type RefData<'a> = Self;
fn as_ref(&self) -> Self {
*self
}
}
impl BorrowedDatum<'_, time::OffsetDateTime> for time::OffsetDateTime {
fn as_owned(&self) -> Self {
*self
}
}
impl Datum for time::OffsetDateTime {
fn sql_type() -> &'static str {
"text"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
let ts = self.unix_timestamp();
ts.bind_to(stmt, index)
}
fn build_from(
rdata: RelationData,
stmt: &mut StatementRow,
index: &mut i32,
) -> DBResult<Self>
where
Self: Sized,
{
let unix = i64::build_from(rdata, stmt, index)?;
Self::from_unix_timestamp(unix).map_err(|e| Error::UnknownValue(e.to_string()))
}
}
impl OwnedDatum for time::UtcDateTime {
type RefData<'a> = Self;
fn as_ref(&self) -> Self {
*self
}
}
impl BorrowedDatum<'_, time::UtcDateTime> for time::UtcDateTime {
fn as_owned(&self) -> Self {
*self
}
}
impl Datum for time::UtcDateTime {
fn sql_type() -> &'static str {
"text"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
let ts = self.unix_timestamp();
ts.bind_to(stmt, index)
}
fn build_from(
rdata: RelationData,
stmt: &mut StatementRow,
index: &mut i32,
) -> DBResult<Self>
where
Self: Sized,
{
let unix = i64::build_from(rdata, stmt, index)?;
Self::from_unix_timestamp(unix).map_err(|e| Error::UnknownValue(e.to_string()))
}
}
};
impl OwnedDatum for String {
type RefData<'a> = &'a str;
fn as_ref(&self) -> Self::RefData<'_> {
self.as_str()
}
}
impl Datum for String {
fn sql_type() -> &'static str {
"text"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, self.as_str())
}
fn build_from(_: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val = stmt.read(*index)?;
*index += 1;
Ok(val)
}
}
impl Datum for &str {
fn sql_type() -> &'static str {
"text"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, *self)
}
fn build_from(_adata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val = stmt.borrow(*index)?;
*index += 1;
Ok(val)
}
}
impl<'a> BorrowedDatum<'a, String> for &'a str {
fn as_owned(&self) -> String {
self.to_string()
}
}
fn try_into_i64(
d: impl TryInto<i64, Error = std::num::TryFromIntError>,
ctx: &'static str,
) -> DBResult<i64> {
d.try_into().map_err(|e| Error::OutOfRange(e, ctx))
}
impl OwnedDatum for usize {
type RefData<'a> = usize;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
borrowed_uint!(usize);
impl Datum for usize {
fn sql_type() -> &'static str {
"int"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, try_into_i64(*self, "binding usize as i64")?)
}
fn build_from(rdata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(i64::build_from(rdata, stmt, index)? as usize)
}
}
impl OwnedDatum for isize {
type RefData<'a> = isize;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
borrowed_int!(isize);
impl Datum for isize {
fn sql_type() -> &'static str {
"int"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, try_into_i64(*self, "binding isize as i64")?)
}
fn build_from(rdata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(i64::build_from(rdata, stmt, index)? as isize)
}
}
impl OwnedDatum for u64 {
type RefData<'a> = u64;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
borrowed_uint!(u64);
impl Datum for u64 {
fn sql_type() -> &'static str {
"int"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, try_into_i64(*self, "binding u64 as i64")?)
}
fn build_from(rdata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(i64::build_from(rdata, stmt, index)? as u64)
}
}
impl OwnedDatum for i64 {
type RefData<'a> = i64;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
borrowed_int!(i64);
impl Datum for i64 {
fn sql_type() -> &'static str {
"int"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, *self)
}
fn build_from(_: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val = stmt.read(*index)?;
*index += 1;
Ok(val)
}
}
impl Datum for u32 {
fn sql_type() -> &'static str {
"int"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, *self as i64)
}
fn build_from(rdata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(i64::build_from(rdata, stmt, index)? as u32)
}
}
impl OwnedDatum for u32 {
type RefData<'l>
= u32
where
Self: 'l;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
borrowed_uint!(u32);
impl Datum for i32 {
fn sql_type() -> &'static str {
"int"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, *self as i64)
}
fn build_from(rdata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(i64::build_from(rdata, stmt, index)? as i32)
}
}
impl OwnedDatum for i32 {
type RefData<'l>
= i32
where
Self: 'l;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
borrowed_int!(i32);
impl<T: 'static + OwnedDatum> OwnedDatum for Option<T> {
type RefData<'a> = Option<&'a T>;
fn as_ref(&self) -> Self::RefData<'_> {
self.as_ref()
}
}
impl<'a, T: OwnedDatum> BorrowedDatum<'a, Option<T>> for Option<&'a T> {
fn as_owned(&self) -> Option<T> {
self.cloned()
}
}
impl<T: Datum> Datum for Option<T> {
fn sql_type() -> &'static str {
T::sql_type()
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
if let Some(v) = self.as_ref() {
v.bind_to(stmt, index)
} else {
().bind(stmt, index)
}
}
fn build_from(rdata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
if stmt.read::<db::IsNull>(*index)?.0 {
*index += 1;
Ok(None)
} else {
T::build_from(rdata, stmt, index).map(Some)
}
}
}
impl OwnedDatum for bool {
type RefData<'a> = bool;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
impl BorrowedDatum<'_, bool> for bool {
fn as_owned(&self) -> bool {
*self
}
}
impl Datum for bool {
fn sql_type() -> &'static str {
"int"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, if *self { 1i64 } else { 0i64 })
}
fn build_from(rdata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
Ok(i64::build_from(rdata, stmt, index)? != 0)
}
}
impl OwnedDatum for Vec<u8> {
type RefData<'a> = &'a [u8];
fn as_ref(&self) -> Self::RefData<'_> {
self.as_slice()
}
}
impl Datum for Vec<u8> {
fn sql_type() -> &'static str {
"blob"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, self.as_slice())
}
fn build_from(_: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val = stmt.read(*index)?;
*index += 1;
Ok(val)
}
}
impl Datum for &[u8] {
fn sql_type() -> &'static str {
"blob"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, *self)
}
fn build_from(_adata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val = stmt.borrow(*index)?;
*index += 1;
Ok(val)
}
}
impl<'a> BorrowedDatum<'a, Vec<u8>> for &'a [u8] {
fn as_owned(&self) -> Vec<u8> {
Vec::from(*self)
}
}
impl<T: OwnedDatum + serde::Serialize + serde::de::DeserializeOwned> Datum for Vec<T> {
fn sql_type() -> &'static str {
"text"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
self.as_slice().bind_to(stmt, index)
}
fn build_from(rdata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let s = <&str as Datum>::build_from(rdata, stmt, index)?;
let d = serde_json::from_str::<Vec<T>>(s).map_err(Error::JSON)?;
Ok(d)
}
}
impl<T: OwnedDatum + serde::Serialize + serde::de::DeserializeOwned> Datum for &[T] {
fn sql_type() -> &'static str {
"text"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
let json = std::pin::Pin::new(
serde_json::to_string(self).expect("couldn't serialize object into JSON"),
);
let r = <&str as Datum>::bind_to(&&*json.as_ref(), stmt, index);
stmt.transfer(json);
r
}
}
impl Datum for f32 {
fn sql_type() -> &'static str {
"numeric"
}
fn build_from(_adata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val = stmt.read(*index)?;
*index += 1;
Ok(val)
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, *self)
}
}
impl OwnedDatum for f32 {
type RefData<'a> = f32;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
impl<'a> BorrowedDatum<'a, f32> for f32 {
fn as_owned(&self) -> f32 {
*self
}
}
impl Datum for f64 {
fn sql_type() -> &'static str {
"numeric"
}
fn build_from(_adata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val = stmt.read(*index)?;
*index += 1;
Ok(val)
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, *self)
}
}
impl OwnedDatum for f64 {
type RefData<'a> = Self;
fn as_ref(&self) -> Self::RefData<'_> {
*self
}
}
impl<'a> BorrowedDatum<'a, f64> for f64 {
fn as_owned(&self) -> f64 {
*self
}
}
impl Datum for std::ffi::OsString {
fn sql_type() -> &'static str {
"blob"
}
fn build_from(_adata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val: Vec<u8> = stmt.read(*index)?;
Ok(std::ffi::OsString::from_vec(val))
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, self.as_os_str().as_bytes())
}
}
impl Datum for &'_ std::ffi::OsStr {
fn sql_type() -> &'static str {
"blob"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, self.as_bytes())
}
}
impl OwnedDatum for std::ffi::OsString {
type RefData<'a> = &'a std::ffi::OsStr;
fn as_ref(&self) -> Self::RefData<'_> {
self.as_os_str()
}
}
impl BorrowedDatum<'_, std::ffi::OsString> for &'_ std::ffi::OsStr {
fn as_owned(&self) -> std::ffi::OsString {
self.into()
}
}
impl Datum for std::path::PathBuf {
fn sql_type() -> &'static str {
"blob"
}
fn build_from(_adata: RelationData, stmt: &mut StatementRow, index: &mut i32) -> DBResult<Self>
where
Self: Sized,
{
let val: Vec<u8> = stmt.read(*index)?;
Ok(std::ffi::OsString::from_vec(val).into())
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, self.as_path().as_os_str().as_bytes())
}
}
impl Datum for &'_ std::path::Path {
fn sql_type() -> &'static str {
"blob"
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
stmt.bind(index, self.as_os_str().as_bytes())
}
}
impl OwnedDatum for std::path::PathBuf {
type RefData<'a> = &'a std::path::Path;
fn as_ref(&self) -> Self::RefData<'_> {
self.as_path()
}
}
impl BorrowedDatum<'_, std::path::PathBuf> for &'_ std::path::Path {
fn as_owned(&self) -> std::path::PathBuf {
self.into()
}
}
impl BorrowedDatum<'_, std::path::PathBuf> for &'_ std::ffi::OsStr {
fn as_owned(&self) -> std::path::PathBuf {
self.into()
}
}
impl<T: Datum> Datum for &T {
fn sql_type() -> &'static str {
T::sql_type()
}
fn bind_to(&self, stmt: &mut StatementContext, index: i32) -> DBResult<()> {
T::bind_to(self, stmt, index)
}
fn accept_discriminator(d: &mut impl DatumDiscriminator)
where
Self: Sized,
{
T::accept_discriminator(d)
}
fn accept_discriminator_ref(&self, d: &mut impl DatumDiscriminatorRef)
where
Self: Sized,
{
T::accept_discriminator_ref(self, d)
}
fn accept_entity_visitor(v: &mut impl crate::schema::entity::EntityVisitor) {
T::accept_entity_visitor(v)
}
}
impl<T: OwnedDatum> BorrowedDatum<'_, T> for &T {
fn as_owned(&self) -> T {
(*self).clone()
}
}