Initial commit
This commit is contained in:
commit
c0cfc8eb82
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "ql"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = [ ]
|
||||||
|
serde = [ "dep:serde" ]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1", optional = true, features = [ "derive" ] }
|
|
@ -0,0 +1,33 @@
|
||||||
|
/// A dynamic query structure.
|
||||||
|
pub trait DynamicQuery {
|
||||||
|
type Definition;
|
||||||
|
|
||||||
|
fn filter_ref(&mut self, def: &Self::Definition);
|
||||||
|
|
||||||
|
fn filter(mut self, def: &Self::Definition) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.filter_ref(def);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod macros;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
// just tests that the macro compiles
|
||||||
|
crate::query_def! {
|
||||||
|
Foo(FooDef) {
|
||||||
|
bar: 'dyn (Bar),
|
||||||
|
baz: (bool),
|
||||||
|
bars: 'vec (Bar),
|
||||||
|
bars_by_bazs: 'map (bool, Bar),
|
||||||
|
}
|
||||||
|
|
||||||
|
Bar(BarDef) {
|
||||||
|
baz: (bool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! query_def_type {
|
||||||
|
(@ ($type:ty)) => {
|
||||||
|
$type
|
||||||
|
};
|
||||||
|
(@ 'dyn ($type:ty)) => {
|
||||||
|
$type
|
||||||
|
};
|
||||||
|
(@ 'vec ($type:ty)) => {
|
||||||
|
Vec<$type>
|
||||||
|
};
|
||||||
|
(@ 'map ($key:ty, $value:ty)) => {
|
||||||
|
::std::collections::HashMap<$key, $value>
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! query_def_field {
|
||||||
|
(@dyn $type:ty) => {
|
||||||
|
Option<<$type as $crate::DynamicQuery>::Definition>
|
||||||
|
};
|
||||||
|
(@ ($type:ty)) => {
|
||||||
|
bool
|
||||||
|
};
|
||||||
|
(@ 'dyn ($type:ty)) => {
|
||||||
|
$crate::query_def_field!(@dyn $type)
|
||||||
|
};
|
||||||
|
(@ 'vec ($type:ty)) => {
|
||||||
|
$crate::query_def_field!(@dyn $type)
|
||||||
|
};
|
||||||
|
(@ 'map ($key:ty, $value:ty)) => {
|
||||||
|
$crate::query_def_field!(@dyn $value)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! query_def_filter {
|
||||||
|
// note about this: 'dyn is implied for 'vec and 'map because if the type is not 'dyn, then the
|
||||||
|
// special handling is not necessary in the first place.
|
||||||
|
(@ $query:expr, $value:ident, 'vec ($_type:path)) => {
|
||||||
|
match $query {
|
||||||
|
Some(query) => {
|
||||||
|
if let Some(ref mut value) = $value {
|
||||||
|
for value in value.iter_mut() {
|
||||||
|
value.filter_ref(&query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
*$value = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(@ $query:expr, $value:ident, 'map ($_key:path, $_value:path)) => {
|
||||||
|
match $query {
|
||||||
|
Some(query) => {
|
||||||
|
if let Some(ref mut value) = $value {
|
||||||
|
for (_, value) in value.iter_mut() {
|
||||||
|
value.filter_ref(&query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
*$value = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(@ $query:expr, $value:ident, 'dyn ($($_type:tt)+)) => {
|
||||||
|
if let Some(ref mut value) = $value {
|
||||||
|
if let Some(ref query) = $query {
|
||||||
|
value.filter_ref(&query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(@ $query:expr, $value:ident, ($($_type:tt)+)) => {
|
||||||
|
if !*$query {
|
||||||
|
*$value = None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines a dynamic query structure.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! query_def {
|
||||||
|
(
|
||||||
|
$($vis:vis $data:ident($def:ident) {
|
||||||
|
$(
|
||||||
|
$(#[$field_meta:meta])
|
||||||
|
*
|
||||||
|
$field:ident: $($qualifier:lifetime)? ($($type:tt)+),
|
||||||
|
)+
|
||||||
|
})
|
||||||
|
*
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
|
||||||
|
$vis struct $data {
|
||||||
|
$(
|
||||||
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
|
$(#[$field_meta])
|
||||||
|
*
|
||||||
|
pub $field: Option<$crate::query_def_type!(@ $($qualifier)? ($($type)+))>,
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
|
||||||
|
$vis struct $def {
|
||||||
|
$(
|
||||||
|
#[cfg_attr(feature = "serde", serde(default))]
|
||||||
|
pub $field: $crate::query_def_field!(@ $($qualifier)? ($($type)+)),
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::DynamicQuery for $data {
|
||||||
|
type Definition = $def;
|
||||||
|
|
||||||
|
fn filter_ref(&mut self, def: &Self::Definition) {
|
||||||
|
$(
|
||||||
|
let query = &def.$field;
|
||||||
|
let value = &mut self.$field;
|
||||||
|
$crate::query_def_filter!(@ query, value, $($qualifier)? ($($type)+));
|
||||||
|
)
|
||||||
|
+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
*
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue