use crate::ast::{CompareOperator, Expr, Value};
use std::marker::PhantomData;
pub trait Schema {
type Field: Copy + Eq;
fn field_name(field: Self::Field) -> &'static str;
}
pub struct FieldRef<S: Schema, T> {
field: S::Field,
_phantom: PhantomData<(S, T)>,
}
impl<S: Schema, T> FieldRef<S, T> {
#[must_use]
pub const fn new(field: S::Field) -> Self {
Self {
field,
_phantom: PhantomData,
}
}
#[must_use]
pub fn name(&self) -> &'static str {
S::field_name(self.field)
}
#[must_use]
fn identifier(&self) -> Expr {
Expr::Identifier(self.name().to_owned())
}
}
impl<S: Schema, T> Clone for FieldRef<S, T> {
fn clone(&self) -> Self {
*self
}
}
impl<S: Schema, T> Copy for FieldRef<S, T> {}
impl<S: Schema, T> std::fmt::Debug for FieldRef<S, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FieldRef")
.field("field", &self.name())
.finish()
}
}
impl<S: Schema, T> PartialEq for FieldRef<S, T> {
fn eq(&self, other: &Self) -> bool {
self.field == other.field
}
}
impl<S: Schema, T> Eq for FieldRef<S, T> {}
impl<S: Schema, T> std::hash::Hash for FieldRef<S, T>
where
S::Field: std::hash::Hash,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.field.hash(state);
}
}
#[doc(hidden)]
pub trait AsFieldName {
fn as_field_name(&self) -> &'static str;
}
#[doc(hidden)]
pub trait AsFieldKey<S: Schema> {
fn as_field_key(&self) -> S::Field;
}
impl<S: Schema, T> AsFieldName for FieldRef<S, T> {
fn as_field_name(&self) -> &'static str {
self.name()
}
}
impl<S: Schema, T> AsFieldKey<S> for FieldRef<S, T> {
fn as_field_key(&self) -> S::Field {
self.field
}
}
impl<T: AsFieldName + ?Sized> AsFieldName for &T {
fn as_field_name(&self) -> &'static str {
(*self).as_field_name()
}
}
impl<S: Schema, T: AsFieldKey<S> + ?Sized> AsFieldKey<S> for &T {
fn as_field_key(&self) -> S::Field {
(*self).as_field_key()
}
}
pub trait IntoODataValue {
fn into_odata_value(self) -> Value;
}
impl IntoODataValue for bool {
fn into_odata_value(self) -> Value {
Value::Bool(self)
}
}
impl IntoODataValue for uuid::Uuid {
fn into_odata_value(self) -> Value {
Value::Uuid(self)
}
}
impl IntoODataValue for String {
fn into_odata_value(self) -> Value {
Value::String(self)
}
}
impl IntoODataValue for &str {
fn into_odata_value(self) -> Value {
Value::String(self.to_owned())
}
}
impl IntoODataValue for i32 {
fn into_odata_value(self) -> Value {
Value::Number(self.into())
}
}
impl IntoODataValue for i64 {
fn into_odata_value(self) -> Value {
Value::Number(self.into())
}
}
impl IntoODataValue for u32 {
fn into_odata_value(self) -> Value {
Value::Number(self.into())
}
}
impl IntoODataValue for u64 {
fn into_odata_value(self) -> Value {
Value::Number(self.into())
}
}
impl IntoODataValue for chrono::DateTime<chrono::Utc> {
fn into_odata_value(self) -> Value {
Value::DateTime(self)
}
}
impl IntoODataValue for chrono::NaiveDate {
fn into_odata_value(self) -> Value {
Value::Date(self)
}
}
impl IntoODataValue for chrono::NaiveTime {
fn into_odata_value(self) -> Value {
Value::Time(self)
}
}
impl<S: Schema, T> FieldRef<S, T> {
#[must_use]
pub fn eq<V: IntoODataValue>(self, value: V) -> Expr {
Expr::Compare(
Box::new(self.identifier()),
CompareOperator::Eq,
Box::new(Expr::Value(value.into_odata_value())),
)
}
#[must_use]
pub fn ne<V: IntoODataValue>(self, value: V) -> Expr {
Expr::Compare(
Box::new(self.identifier()),
CompareOperator::Ne,
Box::new(Expr::Value(value.into_odata_value())),
)
}
#[must_use]
pub fn gt<V: IntoODataValue>(self, value: V) -> Expr {
Expr::Compare(
Box::new(self.identifier()),
CompareOperator::Gt,
Box::new(Expr::Value(value.into_odata_value())),
)
}
#[must_use]
pub fn ge<V: IntoODataValue>(self, value: V) -> Expr {
Expr::Compare(
Box::new(self.identifier()),
CompareOperator::Ge,
Box::new(Expr::Value(value.into_odata_value())),
)
}
#[must_use]
pub fn lt<V: IntoODataValue>(self, value: V) -> Expr {
Expr::Compare(
Box::new(self.identifier()),
CompareOperator::Lt,
Box::new(Expr::Value(value.into_odata_value())),
)
}
#[must_use]
pub fn le<V: IntoODataValue>(self, value: V) -> Expr {
Expr::Compare(
Box::new(self.identifier()),
CompareOperator::Le,
Box::new(Expr::Value(value.into_odata_value())),
)
}
#[must_use]
pub fn is_null(self) -> Expr {
Expr::Compare(
Box::new(self.identifier()),
CompareOperator::Eq,
Box::new(Expr::Value(Value::Null)),
)
}
#[must_use]
pub fn is_not_null(self) -> Expr {
Expr::Compare(
Box::new(self.identifier()),
CompareOperator::Ne,
Box::new(Expr::Value(Value::Null)),
)
}
}
impl<S: Schema> FieldRef<S, String> {
#[must_use]
pub fn contains(self, substring: &str) -> Expr {
Expr::Function(
"contains".to_owned(),
vec![
self.identifier(),
Expr::Value(Value::String(substring.to_owned())),
],
)
}
#[must_use]
pub fn startswith(self, prefix: &str) -> Expr {
Expr::Function(
"startswith".to_owned(),
vec![
self.identifier(),
Expr::Value(Value::String(prefix.to_owned())),
],
)
}
#[must_use]
pub fn endswith(self, suffix: &str) -> Expr {
Expr::Function(
"endswith".to_owned(),
vec![
self.identifier(),
Expr::Value(Value::String(suffix.to_owned())),
],
)
}
}