sift-query-core 0.1.0

Backend-independent query model and strict parameter parser for SiftQuery
Documentation
use super::invalid_cursor;
use crate::{ParamError, RowValue, ScalarValue};

#[derive(Debug, Clone, PartialEq)]
pub enum CursorValue {
    Null,
    Scalar(ScalarValue),
}

pub trait IntoCursorValue {
    fn to_cursor_value(&self) -> CursorValue;
}

macro_rules! impl_cursor_value {
    ($type:ty, $variant:ident) => {
        impl IntoCursorValue for $type {
            fn to_cursor_value(&self) -> CursorValue {
                CursorValue::Scalar(ScalarValue::$variant(self.clone()))
            }
        }
    };
}

impl_cursor_value!(bool, Bool);
impl_cursor_value!(i32, I32);
impl_cursor_value!(i64, I64);
impl_cursor_value!(f32, F32);
impl_cursor_value!(f64, F64);
impl_cursor_value!(String, Text);
impl_cursor_value!(Vec<u8>, Bytes);
#[cfg(feature = "decimal")]
impl_cursor_value!(rust_decimal::Decimal, Decimal);
#[cfg(feature = "chrono")]
impl_cursor_value!(chrono::NaiveDate, Date);
#[cfg(feature = "chrono")]
impl_cursor_value!(chrono::NaiveTime, Time);
#[cfg(feature = "chrono")]
impl_cursor_value!(chrono::NaiveDateTime, DateTime);
#[cfg(feature = "chrono")]
impl_cursor_value!(chrono::DateTime<chrono::Utc>, Timestamp);
#[cfg(feature = "uuid")]
impl_cursor_value!(uuid::Uuid, Uuid);

impl<T: IntoCursorValue> IntoCursorValue for Option<T> {
    fn to_cursor_value(&self) -> CursorValue {
        self.as_ref()
            .map_or(CursorValue::Null, IntoCursorValue::to_cursor_value)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Cursor {
    pub(super) values: Vec<CursorValue>,
}

impl Cursor {
    #[must_use]
    pub fn values(&self) -> &[CursorValue] {
        &self.values
    }
}

impl CursorValue {
    pub fn from_row_value(value: &RowValue) -> Result<Self, ParamError> {
        Ok(match value {
            RowValue::List(_) => return Err(invalid_cursor("lists cannot be cursor keys")),
            #[cfg(feature = "postgres-types")]
            RowValue::ArrayI64(_)
            | RowValue::ArrayText(_)
            | RowValue::Int8Range(_)
            | RowValue::Network(_) => {
                return Err(invalid_cursor("native types cannot be cursor keys"));
            }
            RowValue::Null => Self::Null,
            RowValue::Bool(value) => Self::Scalar(ScalarValue::Bool(*value)),
            RowValue::I32(value) => Self::Scalar(ScalarValue::I32(*value)),
            RowValue::I64(value) => Self::Scalar(ScalarValue::I64(*value)),
            RowValue::F32(value) => Self::Scalar(ScalarValue::F32(*value)),
            RowValue::F64(value) => Self::Scalar(ScalarValue::F64(*value)),
            #[cfg(feature = "decimal")]
            RowValue::Decimal(value) => Self::Scalar(ScalarValue::Decimal(*value)),
            RowValue::Text(value) => Self::Scalar(ScalarValue::Text(value.clone())),
            RowValue::Bytes(value) => Self::Scalar(ScalarValue::Bytes(value.clone())),
            #[cfg(feature = "chrono")]
            RowValue::Date(value) => Self::Scalar(ScalarValue::Date(*value)),
            #[cfg(feature = "chrono")]
            RowValue::Time(value) => Self::Scalar(ScalarValue::Time(*value)),
            #[cfg(feature = "chrono")]
            RowValue::DateTime(value) => Self::Scalar(ScalarValue::DateTime(*value)),
            #[cfg(feature = "chrono")]
            RowValue::Timestamp(value) => Self::Scalar(ScalarValue::Timestamp(*value)),
            #[cfg(feature = "uuid")]
            RowValue::Uuid(value) => Self::Scalar(ScalarValue::Uuid(*value)),
            #[cfg(feature = "json")]
            RowValue::Json(_) => return Err(invalid_cursor("JSON cannot be a cursor key")),
        })
    }
}