use std::marker::PhantomData;
use serde_json::{Map, Value};
use super::{
Common, FlussoValue, RangeRelation, Sort, SortOrder, common_opts, exists_q, kind, single, wrap,
};
use crate::query::{AsQuery, Query, Root};
fn date_value(value: &(impl FlussoValue<kind::Date> + serde::Serialize)) -> Value {
match serde_json::to_value(value) {
Ok(Value::String(string)) => Value::String(string),
Ok(other) => Value::String(other.to_string()),
Err(_) => Value::String(String::new()),
}
}
#[derive(Debug, Clone)]
pub struct EqQuery<S = Root> {
path: String,
value: Value,
common: Common,
_scope: PhantomData<fn() -> S>,
}
impl<S> EqQuery<S> {
fn new(path: &str, value: Value) -> Self {
Self {
path: path.to_string(),
value,
common: Common::default(),
_scope: PhantomData,
}
}
common_opts!(common);
}
impl<S> AsQuery<S> for EqQuery<S> {
fn into_query(self) -> Option<Query<S>> {
if self.common.is_empty() {
Some(single("term", &self.path, self.value))
} else {
let mut body = Map::new();
body.insert("value".to_string(), self.value);
self.common.write(&mut body);
Some(single("term", &self.path, Value::Object(body)))
}
}
}
#[derive(Debug, Clone)]
pub struct TermsQuery<S = Root> {
path: String,
values: Vec<Value>,
common: Common,
_scope: PhantomData<fn() -> S>,
}
impl<S> TermsQuery<S> {
pub(crate) fn new(path: &str, values: Vec<Value>) -> Self {
Self {
path: path.to_string(),
values,
common: Common::default(),
_scope: PhantomData,
}
}
common_opts!(common);
}
impl<S> AsQuery<S> for TermsQuery<S> {
fn into_query(self) -> Option<Query<S>> {
let mut body = Map::new();
body.insert(self.path, Value::Array(self.values));
self.common.write(&mut body);
Some(wrap("terms", body))
}
}
#[derive(Debug, Clone)]
pub struct RangeQuery<S = Root> {
path: String,
bounds: Vec<(&'static str, Value)>,
extra: Map<String, Value>,
common: Common,
_scope: PhantomData<fn() -> S>,
}
impl<S> RangeQuery<S> {
pub(crate) fn new(path: &str, bounds: Vec<(&'static str, Value)>) -> Self {
Self {
path: path.to_string(),
bounds,
extra: Map::new(),
common: Common::default(),
_scope: PhantomData,
}
}
#[must_use]
pub fn format(mut self, format: impl Into<String>) -> Self {
self.extra
.insert("format".to_string(), Value::String(format.into()));
self
}
#[must_use]
pub fn time_zone(mut self, time_zone: impl Into<String>) -> Self {
self.extra
.insert("time_zone".to_string(), Value::String(time_zone.into()));
self
}
#[must_use]
pub fn relation(mut self, relation: RangeRelation) -> Self {
self.extra.insert(
"relation".to_string(),
Value::String(relation.as_str().to_string()),
);
self
}
common_opts!(common);
}
impl<S> AsQuery<S> for RangeQuery<S> {
fn into_query(self) -> Option<Query<S>> {
let mut body = self.extra;
for (key, value) in self.bounds {
body.insert(key.to_string(), value);
}
self.common.write(&mut body);
Some(single("range", &self.path, Value::Object(body)))
}
}
#[derive(Debug, Clone)]
pub struct Bool<S = Root> {
path: String,
_scope: PhantomData<fn() -> S>,
}
impl<S> Bool<S> {
pub fn at(path: impl Into<String>) -> Self {
Self {
path: path.into(),
_scope: PhantomData,
}
}
pub fn eq(&self, value: bool) -> EqQuery<S> {
EqQuery::new(&self.path, Value::Bool(value))
}
pub fn exists(&self) -> Query<S> {
exists_q(&self.path)
}
pub fn asc(&self) -> Sort {
Sort::new(&self.path, SortOrder::Asc)
}
pub fn desc(&self) -> Sort {
Sort::new(&self.path, SortOrder::Desc)
}
}
#[derive(Debug, Clone)]
pub struct Number<T, S = Root> {
path: String,
_marker: PhantomData<fn() -> (T, S)>,
}
impl<T, S> Number<T, S>
where
T: Into<Value> + Copy,
{
pub fn at(path: impl Into<String>) -> Self {
Self {
path: path.into(),
_marker: PhantomData,
}
}
pub fn eq(&self, value: T) -> EqQuery<S> {
EqQuery::new(&self.path, value.into())
}
pub fn any_of(&self, values: impl IntoIterator<Item = T>) -> TermsQuery<S> {
let array = values.into_iter().map(Into::into).collect();
TermsQuery::new(&self.path, array)
}
pub fn lt(&self, value: T) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("lt", value.into())])
}
pub fn lte(&self, value: T) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("lte", value.into())])
}
pub fn gt(&self, value: T) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("gt", value.into())])
}
pub fn gte(&self, value: T) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("gte", value.into())])
}
pub fn between(&self, low: T, high: T) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("gte", low.into()), ("lte", high.into())])
}
pub fn exists(&self) -> Query<S> {
exists_q(&self.path)
}
pub fn asc(&self) -> Sort {
Sort::new(&self.path, SortOrder::Asc)
}
pub fn desc(&self) -> Sort {
Sort::new(&self.path, SortOrder::Desc)
}
}
#[derive(Debug, Clone)]
pub struct Date<S = Root> {
path: String,
_scope: PhantomData<fn() -> S>,
}
impl<S> Date<S> {
pub fn at(path: impl Into<String>) -> Self {
Self {
path: path.into(),
_scope: PhantomData,
}
}
pub fn eq(&self, value: impl FlussoValue<kind::Date> + serde::Serialize) -> EqQuery<S> {
EqQuery::new(&self.path, date_value(&value))
}
pub fn any_of(
&self,
values: impl IntoIterator<Item = impl FlussoValue<kind::Date> + serde::Serialize>,
) -> TermsQuery<S> {
let array = values.into_iter().map(|v| date_value(&v)).collect();
TermsQuery::new(&self.path, array)
}
pub fn lt(&self, value: impl FlussoValue<kind::Date> + serde::Serialize) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("lt", date_value(&value))])
}
pub fn lte(&self, value: impl FlussoValue<kind::Date> + serde::Serialize) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("lte", date_value(&value))])
}
pub fn gt(&self, value: impl FlussoValue<kind::Date> + serde::Serialize) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("gt", date_value(&value))])
}
pub fn gte(&self, value: impl FlussoValue<kind::Date> + serde::Serialize) -> RangeQuery<S> {
RangeQuery::new(&self.path, vec![("gte", date_value(&value))])
}
pub fn between(
&self,
low: impl FlussoValue<kind::Date> + serde::Serialize,
high: impl FlussoValue<kind::Date> + serde::Serialize,
) -> RangeQuery<S> {
RangeQuery::new(
&self.path,
vec![("gte", date_value(&low)), ("lte", date_value(&high))],
)
}
pub fn exists(&self) -> Query<S> {
exists_q(&self.path)
}
pub fn asc(&self) -> Sort {
Sort::new(&self.path, SortOrder::Asc)
}
pub fn desc(&self) -> Sort {
Sort::new(&self.path, SortOrder::Desc)
}
}