macro_rules! match_operator_arm {
($name: expr, $ty: ty, $registry: expr) => {{
Some(async_graphql::registry::MetaInputValue {
name: $name.into(),
description: None,
ty: <Option<$ty> as async_graphql::InputType>::create_type_info($registry),
default_value: None,
visible: None,
is_secret: false,
inaccessible: false,
tags: vec![],
directive_invocations: vec![],
deprecation: async_graphql::registry::Deprecation::NoDeprecated,
})
}};
}
macro_rules! match_id_operator_arm {
($name: expr, $ty: ty, $registry: expr) => {{
let ty =
<Option<crate::filter::Id<$ty>> as async_graphql::InputType>::create_type_info($registry);
Some(async_graphql::registry::MetaInputValue {
name: $name.into(),
description: None,
ty,
default_value: None,
visible: None,
is_secret: false,
inaccessible: false,
tags: vec![],
directive_invocations: vec![],
deprecation: async_graphql::registry::Deprecation::NoDeprecated,
})
}};
}
macro_rules! impl_as_db_filter {
(base($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToDbFilter for $ty {
type Filter = BaseFilter<$ty>;
fn to_db_filter(self) -> Self::Filter {
BaseFilter::from(self)
}
}
)*
};
(option($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToDbFilter for Option<$ty> {
type Filter = OptionalBaseFilter<$ty>;
fn to_db_filter(self) -> Self::Filter {
OptionalBaseFilter::from(self)
}
}
)*
};
(bytea($($ty: ty), +$(,)?)) => {
$(
impl<const N: usize> crate::filter::ToDbFilter for $ty {
type Filter = ByteaFilter<$ty>;
fn to_db_filter(self) -> Self::Filter {
ByteaFilter::from(self)
}
}
)*
};
(option_bytea($($ty: ty), +$(,)?)) => {
$(
impl<const N: usize> crate::filter::ToDbFilter for Option<$ty> {
type Filter = OptionalByteaFilter<$ty>;
fn to_db_filter(self) -> Self::Filter {
OptionalByteaFilter::from(self)
}
}
)*
};
(string($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToDbFilter for $ty {
type Filter = StringFilter<$ty>;
fn to_db_filter(self) -> Self::Filter {
StringFilter::from(self)
}
}
)*
};
(option_string($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToDbFilter for Option<$ty> {
type Filter = OptionalStringFilter<$ty>;
fn to_db_filter(self) -> Self::Filter {
OptionalStringFilter::from(self)
}
}
)*
};
(array($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToDbFilter for Vec<$ty> {
type Filter = crate::filter::ArrayFilter<$ty>;
fn to_db_filter(self) -> Self::Filter {
crate::filter::ArrayFilter::from(self)
}
}
)*
};
(optional_array($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToDbFilter for Option<Vec<$ty>> {
type Filter = crate::filter::OptionalArrayFilter<$ty>;
fn to_db_filter(self) -> Self::Filter {
crate::filter::OptionalArrayFilter::from(self)
}
}
)*
};
}
macro_rules! impl_as_graphql_filter {
(base($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToGraphqlFilter for $ty {
type Filter = BaseFilter<$ty>;
fn to_graphql_filter(self) -> Self::Filter {
BaseFilter::from(self)
}
}
)*
};
(option($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToGraphqlFilter for Option<$ty> {
type Filter = OptionalBaseFilter<$ty>;
fn to_graphql_filter(self) -> Self::Filter {
OptionalBaseFilter::from(self)
}
}
)*
};
(bytea($($ty: ty), +$(,)?)) => {
$(
impl<const N: usize> crate::filter::ToGraphqlFilter for $ty {
type Filter = ByteaFilter<$ty>;
fn to_graphql_filter(self) -> Self::Filter {
ByteaFilter::from(self)
}
}
)*
};
(option_bytea($($ty: ty), +$(,)?)) => {
$(
impl<const N: usize> crate::filter::ToGraphqlFilter for Option<$ty> {
type Filter = OptionalByteaFilter<$ty>;
fn to_graphql_filter(self) -> Self::Filter {
OptionalByteaFilter::from(self)
}
}
)*
};
(string($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToGraphqlFilter for $ty {
type Filter = StringFilter<$ty>;
fn to_graphql_filter(self) -> Self::Filter {
StringFilter::from(self)
}
}
)*
};
(option_string($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToGraphqlFilter for Option<$ty> {
type Filter = OptionalStringFilter<$ty>;
fn to_graphql_filter(self) -> Self::Filter {
OptionalStringFilter::from(self)
}
}
)*
};
(array($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToGraphqlFilter for Vec<$ty> {
type Filter = crate::filter::ArrayFilter<$ty>;
fn to_graphql_filter(self) -> Self::Filter {
crate::filter::ArrayFilter::from(self)
}
}
)*
};
(optional_array($($ty: ty), +$(,)?)) => {
$(
impl crate::filter::ToGraphqlFilter for Option<Vec<$ty>> {
type Filter = crate::filter::OptionalArrayFilter<$ty>;
fn to_graphql_filter(self) -> Self::Filter {
crate::filter::OptionalArrayFilter::from(self)
}
}
)*
};
}
macro_rules! impl_as_graphql_id_filter {
($($ty: ty), +$(,)?) => {
$(
impl crate::filter::ToNestedGraphqlNestedIdFilter for $ty {
type Filter = crate::filter::NestedIdFilter<crate::filter::NestedIdWrapper<$ty>>;
fn to_graphql_id_filter(self) -> Self::Filter {
crate::filter::NestedIdFilter::from(crate::filter::NestedIdWrapper(self))
}
}
)*
};
(bytea($($ty: ty), +$(,)?)) => {
$(
impl<const N: usize> crate::filter::ToNestedGraphqlNestedIdFilter for $ty {
type Filter = crate::filter::NestedIdFilter<crate::filter::NestedIdWrapper<$ty>>;
fn to_graphql_id_filter(self) -> Self::Filter {
crate::filter::NestedIdFilter::from(crate::filter::NestedIdWrapper(self))
}
}
)*
};
}
macro_rules! bind {
($builder:ident, $val: ident, $op: expr, $field: ident, $and: ident) => {{
if let Some(val) = $val {
if *$and {
$builder.push(" AND ");
}
*$and = true;
$builder.push($field);
$builder.push($op);
$builder.push_bind(val);
}
Ok(())
}};
}
macro_rules! bind_iter {
($builder:ident, $vals: ident, $op: expr, $field: ident, $and: ident) => {{
if let Some(vals) = $vals {
if vals.len() > 0 {
if *$and {
$builder.push(" AND ");
}
*$and = true;
$builder.push($field);
$builder.push($op);
let mut sep = $builder.separated(", ");
for v in vals {
sep.push_bind(v);
}
sep.push_unseparated(") ");
}
}
Ok(())
}};
}
macro_rules! bind_nullable {
($builder:ident, $val: ident, $field: ident, $and: ident) => {{
if let Some(null) = $val {
if *$and {
$builder.push(" AND ");
}
*$and = true;
$builder.push($field);
if *null {
$builder.push(" IS NULL ");
} else {
$builder.push(" IS NOT NULL ");
}
}
Ok(())
}};
}
macro_rules! bind_prefix {
($builder:ident, $val: ident, $op: expr, $field: ident, $and: ident) => {{
if let &Some(ref val) = $val {
if *$and {
$builder.push(" AND ");
}
*$and = true;
$builder.push($field);
$builder.push($op);
$builder.push(format!(" '%{}' ", val));
}
Ok(())
}};
}
macro_rules! bind_suffix {
($builder:ident, $val: ident, $op: expr, $field: ident, $and: ident) => {{
if let &Some(ref val) = $val {
if *$and {
$builder.push(" AND ");
}
*$and = true;
$builder.push($field);
$builder.push($op);
$builder.push(format!(" '{}%' ", val));
}
Ok(())
}};
}
macro_rules! bind_surround {
($builder:ident, $val: ident, $op: expr, $field: ident, $and: ident) => {{
if let &Some(ref val) = $val {
if *$and {
$builder.push(" AND ");
}
*$and = true;
$builder.push($field);
$builder.push($op);
$builder.push(format!(" '%{}%' ", val));
}
Ok(())
}};
}
macro_rules! bind_contains_bytea {
($builder:ident, $val: ident, $op: expr, $field: ident, $and: ident) => {{
if let &Some(ref val) = $val {
if *$and {
$builder.push(" AND ");
}
*$and = true;
$builder.push(" strpos(");
$builder.push($field);
$builder.push(",");
$builder.push_bind(val);
$builder.push(") > 0 ");
}
Ok(())
}};
}
macro_rules! bind_not_contains_bytea {
($builder:ident, $val: ident, $op: expr, $field: ident, $and: ident) => {{
if let &Some(ref val) = $val {
if *$and {
$builder.push(" AND ");
}
*$and = true;
$builder.push(" strpos(");
$builder.push($field);
$builder.push(",");
$builder.push_bind(val);
$builder.push(") = 0 ");
}
Ok(())
}};
}
macro_rules! try_map_operator {
($this:ident::$operator:ident::$map:ident, null { $($nop:ident),* $(,)? }, primitive { $($op:ident),* $(,)? }, primitives { $($ops:ident),* $(,)? }) => {
match $this {
$(
$operator::$nop(v) => match v {
Some(v) => Ok($operator::$nop(Some(v))),
None => Ok($operator::$nop(None)),
},
)*
$(
$operator::$op(v) => match v {
Some(v) => Ok($operator::$op(Some($map(v)?))),
None => Ok($operator::$op(None)),
},
)*
$(
$operator::$ops(v) => match v {
Some(v) => {
if v.is_empty() {
Ok($operator::$ops(None))
} else {
let mut vec = Vec::with_capacity(v.len());
for v in v {
vec.push($map(v)?);
}
Ok($operator::$ops(Some(vec)))
}
}
None => Ok($operator::$ops(None)),
},
)*
}
};
}
macro_rules! impl_try_map_operator {
($operator:ident, null { $($nop:ident),* $(,)? }, primitive { $($op:ident),* $(,)? }, primitives { $($ops:ident),* $(,)? }) => {
impl<I: async_graphql::InputType> $operator<I> {
pub fn try_map<U, E, F: Fn(I) -> Result<U, E>>(
self,
f: &F,
) -> Result<$operator<U>, E> {
try_map_operator!(self::$operator::f, null {$($nop,)*}, primitive {$($op,)*}, primitives {$($ops,)*})
}
}
};
}
macro_rules! try_map_filter {
($target:ident::$filter:ident::$map:ident, {$($op:ident),* $(,)?}) => {
match $target.0 {
[$($op,)*] => {
$(
let $op = $op.try_map(&$map)?;
)*
Ok($filter([
$($op,)*
]))
}
}
};
}
macro_rules! impl_try_map_filter {
($filter:ident, {$($op:ident),* $(,)?}) => {
impl<I: async_graphql::InputType> $filter<I> {
pub fn try_map<U, E, F>(self, f: F) -> Result<$filter<U>, E>
where
Self: Filter<Primitive = I>,
U: for<'a> sqlx::Encode<'a, sqlx::Postgres> + sqlx::Type<sqlx::Postgres> + Send + Sync,
F: Fn(I) -> Result<U, E>,
{
try_map_filter!(self::$filter::f, {$($op),*})
}
}
};
}
pub trait Operator {
type Primitive;
type Primitives;
fn sql_op(&self) -> &'static str
where
Self::Primitive:
for<'a> sqlx::Encode<'a, sqlx::Postgres> + sqlx::Type<sqlx::Postgres> + Send + Sync;
fn bind<'q>(
&'q self,
field: &str,
builder: &mut sqlx::QueryBuilder<'q, sqlx::Postgres>,
and: &mut bool,
) -> Result<(), async_graphql::Error>
where
Self::Primitive:
for<'a> sqlx::Encode<'a, sqlx::Postgres> + sqlx::Type<sqlx::Postgres> + Send + Sync;
fn to_value(&self) -> async_graphql::Value
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType;
fn graphql_suffix(&self) -> &'static str
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType;
}
macro_rules! operator {
(
$operator:ident,
extra_bounds: { $($extra_bound:ident),* $(,)? }, extra_binds: { $($extra_bind_arm:ident => $extra_bind_expr:ident),* $(,)? },
null {
$(
$nop:ident:$nop_var:ident:$nop_suffix:literal),* $(,)?
},
primitive {
$($op:ident:$var:ident:$suffix:literal),* $(,)?
},
primitives {
$(
$ops:ident:$ops_var:ident:$ops_suffix:literal
),* $(,)?
}
) => {
#[derive(Debug, Clone)]
pub enum $operator<I> {
$(
$nop(Option<bool>),
)*
$(
$op(Option<I>),
)*
$(
$ops(Option<Vec<I>>),
)*
}
impl<I> $operator<I> {
$(
paste::paste! {
pub fn [< into_ $nop_var >](self) -> Option<bool> {
if let Self::$nop(v) = self {
v
} else {
panic!("unexpected operator")
}
}
}
)*
$(
paste::paste! {
pub fn [< into_ $var >](self) -> Option<I> {
if let Self::$op(v) = self {
v
} else {
panic!("unexpected operator")
}
}
}
)*
$(
paste::paste! {
pub fn [< into_ $ops_var >](self) -> Option<Vec<I>> {
if let Self::$ops(v) = self {
v
} else {
panic!("unexpected operator")
}
}
}
)*
#[inline]
pub fn is_some(&self) -> bool {
match self {
$(
$operator::$nop(v) => v.is_some(),
)*
$(
$operator::$op(v) => v.is_some(),
)*
$(
$operator::$ops(v) => match v {
Some(v) => !v.is_empty(),
None => false,
},
)*
}
}
#[inline]
pub fn is_none(&self) -> bool {
match self {
$(
$operator::$nop(v) => v.is_none(),
)*
$(
$operator::$op(v) => v.is_none(),
)*
$(
$operator::$ops(v) => match v {
Some(v) => v.is_empty(),
None => true,
},
)*
}
}
#[inline]
pub fn merge(&mut self, other: Self) {
match (self, other) {
$(
($operator::$nop(this), $operator::$nop(Some(other))) => {
this.get_or_insert(other);
},
)*
$(
($operator::$op(this), $operator::$op(Some(other))) => {
this.get_or_insert(other);
},
)*
$(
($operator::$ops(this), $operator::$ops(Some(other))) => {
this.get_or_insert(other);
},
)*
_ => {}
}
}
}
impl<I> core::hash::Hash for $operator<I> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
match self {
$(
$operator::$nop(_) => $nop_suffix.hash(state),
)*
$(
$operator::$op(_) => $suffix.hash(state),
)*
$(
$operator::$ops(_) => $ops_suffix.hash(state),
)*
}
}
}
impl<I: Send + Sync $(+ $extra_bound)*> super::Operator for $operator<I> {
type Primitive = I;
type Primitives = Vec<I>;
fn sql_op(&self) -> &'static str
where
Self::Primitive: for<'a> sqlx::Encode<'a, sqlx::Postgres> + sqlx::Type<sqlx::Postgres> + Send + Sync
{
match self {
$(
$operator::$nop(_) => crate::sql::SqlKeywords::$nop,
)*
$(
$operator::$op(_) => crate::sql::SqlKeywords::$op,
)*
$(
$operator::$ops(_) => crate::sql::SqlKeywords::$ops,
)*
}
}
fn bind<'q>(
&'q self,
field: &str,
builder: &mut sqlx::QueryBuilder<'q, sqlx::Postgres>,
and: &mut bool,
) -> Result<(), async_graphql::Error>
where
Self::Primitive: for<'a> sqlx::Encode<'a, sqlx::Postgres> + sqlx::Type<sqlx::Postgres> + Send + Sync
{
match self {
$(
$operator::$extra_bind_arm(val) => $extra_bind_expr!(builder, val, self.sql_op(), field, and),
)*
$(
$operator::$nop(val) => bind_nullable!(builder, val, field, and),
)*
$(
#[allow(unreachable_patterns)]
$operator::$op(val) => bind!(builder, val, self.sql_op(), field, and),
)*
$(
$operator::$ops(val) => bind_iter!(builder, val, self.sql_op(), field, and),
)*
}
}
fn to_value(&self) -> async_graphql::Value
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType {
match self {
$(
$operator::$nop(v) => async_graphql::InputType::to_value(v),
)*
$(
$operator::$op(v) => async_graphql::InputType::to_value(v),
)*
$(
$operator::$ops(v) => async_graphql::InputType::to_value(v),
)*
}
}
fn graphql_suffix(&self) -> &'static str
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType {
match self {
$(
$operator::$nop(_) => concat!("_", $nop_suffix),
)*
$(
$operator::$op(_) => {
if !$suffix.is_empty() {
concat!("_", $suffix)
} else {
""
}
},
)*
$(
$operator::$ops(_) => concat!("_", $ops_suffix),
)*
}
}
}
impl_try_map_operator!{ $operator, null {$($nop,)*}, primitive {$($op,)*}, primitives {$($ops,)*} }
};
}
pub trait Filter: Default + Clone + Sized + Send + Sync {
type Primitive;
type Primitives;
fn primitive_type_info(registry: &mut async_graphql::registry::Registry) -> String
where
Self::Primitive: async_graphql::InputType,
{
<Option<Self::Primitive> as async_graphql::InputType>::create_type_info(registry)
}
fn primitives_type_info(registry: &mut async_graphql::registry::Registry) -> String
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
<Option<Self::Primitives> as async_graphql::InputType>::create_type_info(registry)
}
fn match_operator(
_name: &'static str,
_op: &'static str,
_registry: &mut async_graphql::registry::Registry,
) -> Option<async_graphql::registry::MetaInputValue>
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
None
}
fn match_id_operator(
_name: &'static str,
_op: &'static str,
_registry: &mut async_graphql::registry::Registry,
) -> Option<async_graphql::registry::MetaInputValue>
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
None
}
fn parse<T: async_graphql::InputType>(
_field_name: &'static str,
_obj: &async_graphql::indexmap::IndexMap<async_graphql::Name, async_graphql::Value>,
) -> Result<Option<Self>, async_graphql::InputValueError<T>>
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
Ok(None)
}
fn to_value(
&self,
_field_name: &'static str,
_map: &mut async_graphql::indexmap::IndexMap<async_graphql::Name, async_graphql::Value>,
) where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
}
fn type_name() -> &'static str {
::std::any::type_name::<Self>()
}
fn merge(&mut self, other: Self);
fn pg_type() -> Option<sqlx::postgres::PgTypeInfo>
where
Self::Primitive: sqlx::Type<sqlx::Postgres>,
{
None
}
fn is_collection() -> bool {
false
}
fn is_pg_array() -> bool
where
Self::Primitive: sqlx::Type<sqlx::Postgres>,
{
false
}
fn apply_filter<'q, QB: ::core::borrow::BorrowMut<sqlx::QueryBuilder<'q, sqlx::Postgres>>>(
&'q self,
_field: &str,
_builder: QB,
) -> Result<(), async_graphql::Error>
where
Self::Primitive:
for<'a> sqlx::Encode<'a, sqlx::Postgres> + sqlx::Type<sqlx::Postgres> + Send + Sync,
{
Ok(())
}
fn is_empty(&self) -> bool;
}
macro_rules! filter {
(
$filter:ident: [$operator:ident;$n:expr], extra_bounds: {
$($extra_bound:ident),* $(,)?
},
extra_binds: {
$($extra_bind_arm:ident => $extra_bind_expr:ident),* $(,)?
},
null {
$(
$nop_idx: literal:$nop:ident:$nop_var:ident:$nop_suffix:literal),* $(,)?
},
primitive {
$($op_idx: literal:$op:ident:$var:ident:$suffix:literal),* $(,)?
},
primitives {
$(
$ops_idx:literal:$ops:ident:$ops_var:ident:$ops_suffix:literal
),* $(,)?
}
) => {
operator!(
$operator,
extra_bounds: { $($extra_bound),* },
extra_binds: { $($extra_bind_arm => $extra_bind_expr,)* },
null { $($nop:$nop_var:$nop_suffix,)* },
primitive {
$($op:$var:$suffix,)*
},
primitives {
$($ops:$ops_var:$ops_suffix,)*
}
);
#[derive(Debug, Clone)]
pub struct $filter<I>(pub(crate) [$operator<I>; $n]);
impl<I> From<I> for $filter<I> {
fn from(val: I) -> Self {
let mut this = Self::new();
this.set_eq(Some(val));
this
}
}
impl<I> From<Option<I>> for $filter<I> {
fn from(val: Option<I>) -> Self {
let mut this = Self::new();
this.set_eq(val);
this
}
}
impl<I> Default for $filter<I> {
fn default() -> Self {
Self::new()
}
}
impl<I> $filter<I> {
pub const fn new() -> Self {
Self([
$(
$operator::$op(None),
)*
$(
$operator::$ops(None),
)*
$(
$operator::$nop(None),
)*
])
}
$(
paste::paste! {
pub fn [< take_ $nop_var >](&mut self) -> Option<bool> {
core::mem::replace(&mut self.0[$nop_idx], $operator::$nop(None)). [< into_ $nop_var>]()
}
pub fn [< set_ $nop_var >](&mut self, val: Option<bool>) {
self.0[$nop_idx] = $operator::$nop(val);
}
}
)*
$(
paste::paste! {
pub fn [< take_ $var >](&mut self) -> Option<I> {
core::mem::replace(&mut self.0[$op_idx], $operator::$op(None)). [< into_ $var>]()
}
pub fn [< set_ $var >](&mut self, val: Option<I>) {
self.0[$op_idx] = $operator::$op(val);
}
}
)*
$(
paste::paste! {
pub fn [< take_ $ops_var >](&mut self) -> Option<Vec<I>> {
core::mem::replace(&mut self.0[$ops_idx], $operator::$ops(None)). [< into_ $ops_var>]()
}
pub fn [< set_ $ops_var >](&mut self, val: Option<Vec<I>>) {
self.0[$ops_idx] = $operator::$ops(val);
}
}
)*
}
impl_try_map_filter! { $filter, { $($var,)* $($ops_var,)* $($nop_var,)* } }
impl<I: Send + Sync $(+ $extra_bound)*> From<crate::filter::IdFilter<$filter<I>>> for $filter<I> {
fn from(filter: crate::filter::IdFilter<$filter<I>>) -> Self {
filter.into_inner()
}
}
impl<I: Clone + Send + Sync $(+ $extra_bound)*> Filter for $filter<I> {
type Primitive = I;
type Primitives = Vec<Self::Primitive>;
fn match_operator(
name: &'static str,
op: &'static str,
registry: &mut async_graphql::registry::Registry,
) -> Option<async_graphql::registry::MetaInputValue>
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
match op {
$(
$nop_suffix => match_operator_arm!(name, bool, registry),
)*
$(
$suffix => match_operator_arm!(name, Self::Primitive, registry),
)*
$(
$ops_suffix => match_operator_arm!(name, Self::Primitives, registry),
)*
_ => None,
}
}
fn match_id_operator(
name: &'static str,
op: &'static str,
registry: &mut async_graphql::registry::Registry,
) -> Option<async_graphql::registry::MetaInputValue>
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
match op {
$(
$nop_suffix => match_id_operator_arm!(name, bool, registry),
)*
$(
$suffix => match_id_operator_arm!(name, Self::Primitive, registry),
)*
$(
$ops_suffix => match_id_operator_arm!(name, Self::Primitives, registry),
)*
_ => None,
}
}
fn parse<T: async_graphql::InputType>(
field_name: &'static str,
obj: &async_graphql::indexmap::IndexMap<async_graphql::Name, async_graphql::Value>,
) -> Result<Option<Self>, async_graphql::InputValueError<T>>
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
$(
let $nop_var: Option<bool> = async_graphql::InputType::parse(obj.get(format!("{}{}", field_name, $operator::$nop(None).graphql_suffix()).as_str()).cloned()).map_err(async_graphql::InputValueError::propagate)?;
)*
$(
let $var: Option<Self::Primitive> = async_graphql::InputType::parse(obj.get(format!("{}{}", field_name, $operator::$op(None).graphql_suffix()).as_str()).cloned()).map_err(async_graphql::InputValueError::propagate)?;
)*
$(
let $ops_var: Option<Self::Primitives> = async_graphql::InputType::parse(obj.get(format!("{}{}", field_name, $operator::$ops(None).graphql_suffix()).as_str()).cloned()).map_err(async_graphql::InputValueError::propagate)?;
)*
let mut none = true;
is_none!(none, {
$($var,)*
});
is_none_range!(none, {
$($ops_var,)*
});
if none {
return Ok(None);
}
Ok(Some(Self([
$(
$operator::$op($var),
)*
$(
$operator::$ops($ops_var),
)*
$(
$operator::$nop($nop_var),
)*
])))
}
fn to_value(
&self,
field_name: &'static str,
map: &mut async_graphql::indexmap::IndexMap<async_graphql::Name, async_graphql::Value>,
) where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
self.0.iter().for_each(|v| {
map.insert(
async_graphql::Name::new(format!("{}{}", field_name, v.graphql_suffix())),
v.to_value(),
);
});
}
fn is_empty(&self) -> bool {
self.0.iter().all(|x| x.is_none())
}
fn merge(&mut self, other: Self) {
self.0.iter_mut().zip(other.0).for_each(|(a, b)| {
a.merge(b);
});
}
fn apply_filter<'q, QB: core::borrow::BorrowMut<sqlx::QueryBuilder<'q, sqlx::Postgres>>>(
&'q self,
field: &str,
mut builder: QB,
) -> Result<(), async_graphql::Error>
where
Self::Primitive:
for<'a> sqlx::Encode<'a, sqlx::Postgres> + sqlx::Type<sqlx::Postgres> + Send + Sync,
{
let builder = builder.borrow_mut();
let mut and = false;
for val in self.0.iter().filter(|x| x.is_some()) {
val.bind(field, builder, &mut and)?;
}
let _ = and;
Ok(())
}
fn pg_type() -> Option<sqlx::postgres::PgTypeInfo>
where
Self::Primitive: sqlx::Type<sqlx::Postgres>,
{
Some(<Self::Primitive as sqlx::Type<sqlx::Postgres>>::type_info())
}
}
};
}
impl<T: Filter> Filter for Box<T> {
type Primitive = <T as Filter>::Primitive;
type Primitives = <T as Filter>::Primitives;
fn match_operator(
name: &'static str,
op: &'static str,
registry: &mut async_graphql::registry::Registry,
) -> Option<async_graphql::registry::MetaInputValue>
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
<T as Filter>::match_operator(name, op, registry)
}
fn parse<I: async_graphql::InputType>(
field_name: &'static str,
obj: &async_graphql::indexmap::IndexMap<async_graphql::Name, async_graphql::Value>,
) -> Result<Option<Self>, async_graphql::InputValueError<I>>
where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
<T as Filter>::parse(field_name, obj).map(|x| x.map(Box::new))
}
fn to_value(
&self,
field_name: &'static str,
map: &mut async_graphql::indexmap::IndexMap<async_graphql::Name, async_graphql::Value>,
) where
Self::Primitive: async_graphql::InputType,
Self::Primitives: async_graphql::InputType + IntoIterator<Item = Self::Primitive>,
{
<T as Filter>::to_value(self, field_name, map)
}
fn apply_filter<'q, QB: core::borrow::BorrowMut<sqlx::QueryBuilder<'q, sqlx::Postgres>>>(
&'q self,
field: &str,
builder: QB,
) -> Result<(), async_graphql::Error>
where
Self::Primitive:
for<'a> sqlx::Encode<'a, sqlx::Postgres> + sqlx::Type<sqlx::Postgres> + Send + Sync,
{
<T as Filter>::apply_filter(self, field, builder)
}
fn is_empty(&self) -> bool {
<T as Filter>::is_empty(self)
}
fn merge(&mut self, other: Self) {
<T as Filter>::merge(self, *other)
}
}
pub trait RootWhere: ComplexFilter + 'static {
type BlockNumber: BlockNumber;
type IdFilter: Filter + Clone;
fn from_id(id: Option<Self::IdFilter>) -> Self
where
Self: Sized;
fn apply<'b, 'ctx: 'b, O>(
&'b self,
ctx: &'ctx async_graphql::Context<'ctx>,
builder: sql::QueryBuilder<'b, O>,
block_number: Self::BlockNumber,
) -> BoxFuture<'b, Result<sql::QueryBuilder<'b, O>, async_graphql::Error>>
where
O: Send + 'b;
fn apply_history<'b, 'ctx: 'b, O>(
&'b self,
ctx: &'ctx async_graphql::Context<'ctx>,
builder: sql::QueryBuilder<'b, O>,
start_block: Self::BlockNumber,
end_block: Self::BlockNumber,
) -> BoxFuture<'b, Result<sql::QueryBuilder<'b, O>, async_graphql::Error>>
where
O: Send + 'b;
}
impl<T: RootWhere> RootWhere for std::sync::Arc<T> {
type BlockNumber = T::BlockNumber;
type IdFilter = T::IdFilter;
fn from_id(id: Option<Self::IdFilter>) -> Self
where
Self: Sized,
{
<T as RootWhere>::from_id(id).into()
}
fn apply<'b, 'ctx: 'b, O>(
&'b self,
ctx: &'ctx async_graphql::Context<'ctx>,
builder: sql::QueryBuilder<'b, O>,
block_number: Self::BlockNumber,
) -> BoxFuture<'b, Result<sql::QueryBuilder<'b, O>, async_graphql::Error>>
where
O: Send + 'b,
{
<T as RootWhere>::apply(self, ctx, builder, block_number)
}
fn apply_history<'b, 'ctx: 'b, O>(
&'b self,
ctx: &'ctx async_graphql::Context<'ctx>,
builder: sql::QueryBuilder<'b, O>,
start_block: Self::BlockNumber,
end_block: Self::BlockNumber,
) -> BoxFuture<'b, Result<sql::QueryBuilder<'b, O>, async_graphql::Error>>
where
O: Send + 'b,
{
<T as RootWhere>::apply_history(self, ctx, builder, start_block, end_block)
}
}
pub trait ComplexFilter {
type Transformer: Transformer;
type NestedIdFilter: Filter;
fn is_empty(&self) -> bool;
fn is_only_filter_by_id(&self) -> bool {
false
}
fn id_filter(&self) -> Option<&Self::NestedIdFilter>;
fn apply_filter<'q, O>(
&'q self,
field: &str,
builder: sql::QueryBuilder<'q, O>,
block_number: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
) -> Result<sql::QueryBuilder<'q, O>, async_graphql::Error>
where
O: Send + 'q;
fn apply_history_filter<'q, O>(
&'q self,
field: &str,
builder: sql::QueryBuilder<'q, O>,
start_block: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
end_block: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
) -> Result<sql::QueryBuilder<'q, O>, async_graphql::Error>
where
O: Send + 'q;
}
impl<T: ComplexFilter> ComplexFilter for Box<T> {
type Transformer = T::Transformer;
type NestedIdFilter = T::NestedIdFilter;
fn is_empty(&self) -> bool {
<T as ComplexFilter>::is_empty(self)
}
fn id_filter(&self) -> Option<&Self::NestedIdFilter> {
<T as ComplexFilter>::id_filter(self)
}
fn apply_filter<'q, O>(
&'q self,
field: &str,
builder: sql::QueryBuilder<'q, O>,
block_number: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
) -> Result<sql::QueryBuilder<'q, O>, async_graphql::Error>
where
O: Send + 'q,
{
<T as ComplexFilter>::apply_filter(self, field, builder, block_number)
}
fn apply_history_filter<'q, O>(
&'q self,
field: &str,
builder: sql::QueryBuilder<'q, O>,
start_block: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
end_block: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
) -> Result<sql::QueryBuilder<'q, O>, async_graphql::Error>
where
O: Send + 'q,
{
<T as ComplexFilter>::apply_history_filter(self, field, builder, start_block, end_block)
}
}
impl<T: ComplexFilter> ComplexFilter for std::sync::Arc<T> {
type Transformer = T::Transformer;
type NestedIdFilter = T::NestedIdFilter;
fn is_empty(&self) -> bool {
<T as ComplexFilter>::is_empty(self)
}
fn id_filter(&self) -> Option<&Self::NestedIdFilter> {
<T as ComplexFilter>::id_filter(self)
}
fn apply_filter<'q, O>(
&'q self,
field: &str,
builder: sql::QueryBuilder<'q, O>,
block_number: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
) -> Result<sql::QueryBuilder<'q, O>, async_graphql::Error>
where
O: Send + 'q,
{
<T as ComplexFilter>::apply_filter(self, field, builder, block_number)
}
fn apply_history_filter<'q, O>(
&'q self,
field: &str,
builder: sql::QueryBuilder<'q, O>,
start_block: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
end_block: <<<Self::Transformer as Transformer>::Cidomap as Cidomap>::Network as Network>::BlockNumber,
) -> Result<sql::QueryBuilder<'q, O>, async_graphql::Error>
where
O: Send + 'q,
{
<T as ComplexFilter>::apply_history_filter(self, field, builder, start_block, end_block)
}
}
pub trait TryMapFilter<T>: Sized {
fn try_map(value: T) -> Result<Self, async_graphql::Error>;
}
impl<T> TryMapFilter<T> for T {
fn try_map(value: T) -> Result<Self, async_graphql::Error> {
Ok(value)
}
}
pub trait ToNestedGraphqlNestedIdFilter {
type Filter: Filter;
fn to_graphql_id_filter(self) -> Self::Filter;
}
impl<T: ToNestedGraphqlNestedIdFilter + Send + Sync + Clone> ToNestedGraphqlNestedIdFilter
for Option<T>
{
type Filter = OptionalNestedIdFilter<NestedIdWrapper<T>>;
fn to_graphql_id_filter(self) -> Self::Filter {
OptionalNestedIdFilter::from(self.map(NestedIdWrapper))
}
}
pub trait ToGraphqlFilter {
type Filter: Filter;
fn to_graphql_filter(self) -> Self::Filter;
}
impl<T> ToGraphqlFilter for Option<T>
where
T: Transformer,
<T::GraphqlInput as GraphqlInputType>::Filter: ToGraphqlFilter,
{
type Filter = <T::GraphqlInput as GraphqlInputType>::Filter;
fn to_graphql_filter(self) -> Self::Filter {
Self::Filter::default()
}
}
impl<T> ToGraphqlFilter for Vec<T>
where
T: Transformer,
<T::GraphqlInput as GraphqlInputType>::Filter: Filter,
{
type Filter = <T::GraphqlInput as GraphqlInputType>::Filter;
fn to_graphql_filter(self) -> Self::Filter {
if self.is_empty() {
Self::Filter::default()
} else {
let _ = self; Self::Filter::default()
}
}
}
pub trait ToDbFilter {
type Filter: std::default::Default;
fn to_db_filter(self) -> Self::Filter;
}
impl<T> ToDbFilter for Option<T>
where
T: Transformer,
{
type Filter = <T::GraphqlInput as GraphqlInputType>::Where;
fn to_db_filter(self) -> Self::Filter {
Self::Filter::default()
}
}
impl<T> ToDbFilter for Vec<T>
where
T: Transformer,
{
type Filter = <T::GraphqlInput as GraphqlInputType>::Where;
fn to_db_filter(self) -> Self::Filter {
if self.is_empty() {
Self::Filter::default()
} else {
let _ = self; Self::Filter::default()
}
}
}
mod base;
pub use base::*;
mod r#enum;
mod event_order;
pub(crate) use event_order::*;
pub use r#enum::*;
use futures::future::BoxFuture;
mod bytea;
pub use bytea::*;
mod relation;
pub(crate) use relation::*;
mod string;
pub use string::*;
mod id;
pub use id::*;
mod nested_id;
pub use nested_id::*;
mod array;
pub use array::*;
use crate::{
graphql::GraphqlInputType,
network::{BlockNumber, Network},
prelude::{Cidomap, Transformer},
sql,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, async_graphql::InputObject)]
pub struct BlockChangedFilter {
#[graphql(name = "number_gte")]
pub number_gte: u64,
}