5 unstable releases
0.2.0 | Apr 15, 2023 |
---|---|
0.1.0 | Apr 4, 2023 |
0.0.5 | Dec 5, 2022 |
0.0.3 |
|
0.0.2 | Jun 11, 2022 |
#221 in Data structures
215 downloads per month
Used in mock-store
36KB
966 lines
STATUS Still experimental. In version 0.y.z, breaking changes will occur in .y, and additions/fixes in .z. Once it reaches x.y.z, it will follow SemVer best practices.
tl;dr - modql is a normalized declarative model and store agnostic query language.
Overview
One modql representation is joql, which is the JSON serialization of this model.
modql
has the joql deserializer to build the filter, and provides the raw construct to make them directly from Rust types.
In short, modql
allows to express of a store model-specific filter and include rules which can be implemented for various store. For example, it can express:
- Filter & include all of the
Ticket
- with the
title
containing"hello"
or"welcome"
(<< Filters) - with the
done
flagtrue
- and fetch only the property
id
,title
and thedone
properties. (<< Includes, not implemented yet)
- with the
Json example
The JSON/joql representation of this would be something like:
{
$filters: {
"title": {$containsIn: ["hello", "welcome"]},
"done": true, // equivalent: "done": {$eq: true}
},
$includes: { // not implemented yet
"id": true,
"title": true,
"done": true,
}
}
Rust types
On the Rust side, this can be expressed like this:
use modql::filter::{FilterGroups, FilterNode, OpValString};
fn main() -> anyhow::Result<()> {
println!("->> hello! {}", 111);
let filter_nodes: Vec<FilterNode> = vec![
(
"title",
OpValString::ContainsIn(vec!["Hello".to_string(), "welcome".to_string()]),
)
.into(),
("done", true).into(),
];
let filter_groups: FilterGroups = filter_nodes.into();
println!("filter_groups:\n{filter_groups:#?}");
Ok(())
}
Then, a Model or Store layer can get the filter_groups, and serialize to their DSL (i.e. SQL for database)
The Filter structure is as followed:
FilterGroups
is the top level and is a group ofFilterGroup
.FilterGroup
are intended to be executed asOR
between them.FilterGroup
contains a vector ofFilterNode
that are intended to be executed asAND
FilterNode
contains acontext_path
(not used yet),name
which is the property name that the value will come from, and aVec<OpVal>
, which is the Operator Value.OpVal
is an enum for type specificOpVal[Type]
likeOpValString
that contains the specific operation for this type with the associated pattern value.
FilterNodes macro
A convenient FilterNodes
implements the various functions to get the into
FilterNode
FilterGroups
use modql::filter::{FilterGroups, FilterNodes, OpValBool, OpValString, OpValsBool, OpValsString};
#[derive(FilterNodes)]
struct MyFilter {
done: Option<OpValsBool>,
name: Option<OpValsString>,
}
let filter = MyFilter {
done: Some(OpValBool::Eq(true).into()),
name: Some(
vec![
OpValString::Contains("Hello".to_string()),
OpValString::Contains("welcome".to_string()),
]
.into(),
),
};
let filter_groups: FilterGroups = filter.into();
println!("filter_groups:\n{filter_groups:#?}");
- And the side to implement the filter against a specific data interface (e.g., sql, file system, S3, ...),
which uses the
FilterNode
,OrGroups
,OpVal
(which is a enum containingStringOpVal
orInOpval
)
Dependencies
~0.8–1.5MB
~35K SLoC