DNF
A Rust library for building and evaluating DNF (Disjunctive Normal Form) queries — basically OR-ed ANDs.
(age > 18 AND country == "US") OR (premium == true)
Why DNF?
- Type-safe: derive macros generate the boilerplate
- Fast: zero-copy evaluation, minimal allocations
- Flexible: rich operators, custom logic, nested structs
- Portable: serialize queries with serde, parse from strings
Quick Start
use ;
let query = builder
.or
.or
.build;
let user = User ;
assert!;
Validation
The builder API doesn't check field names at compile time. Use validate() to catch typos:
let query = builder
.or // typo!
.? // catches it here
.build;
Or use the parser — it validates automatically:
use QueryBuilder;
let query = ?;
Features
[]
= "0.2" # derive only
= { = "0.2", = ["serde"] } # + serialization
= { = "0.2", = ["parser"] } # + string parsing
| Feature | What it does |
|---|---|
derive |
#[derive(DnfEvaluable)] macro (default) |
serde |
Serialization support |
parser |
Parse queries from strings |
Minimum supported Rust version: 1.80.
Supported Types
| Category | Types |
|---|---|
| Integers | i8–i64, isize, u8–u64, usize |
| Floats | f32, f64 |
| Strings | String, &str, Box<str>, Cow<str> |
| Other | bool |
| Collections | Vec<T>, HashSet<T> |
| Maps | HashMap<String, V>, BTreeMap<String, V> |
| Wrappers | Option<T> |
| Nested | Structs with #[dnf(nested)] |
Operators
| Category | Operators |
|---|---|
| Comparison | == != > < >= <= |
| String | CONTAINS STARTS WITH ENDS WITH (+ NOT variants) |
| Collection | IN ALL OF (+ NOT variants) |
| Range | BETWEEN [min, max] |
| Custom | Op::custom("NAME") |
The builder uses Op::ANY_OF / Op::NOT_ANY_OF; in query strings these are written IN / NOT IN.
Collections & Range
use ;
let q = builder
.or
.or
.build;
Nested Structs
// Query: "address.city" or "offices.city"
Map Fields
HashMap / BTreeMap fields use map-target wrappers on the value side:
let q = builder
.or // has key "author"
.or // tags["status"] == "live"
.build;
Constructors: Value::at_key(k, v), Value::keys(v), Value::values(v).
Custom Field Types
The derive only handles built-in types. For wrappers like struct Score(u32):
impl From<&Score> for Value- Manually
impl DnfEvaluable(or use#[dnf(nested)]ifScorealready implements it)
Custom Operators
let q = builder
.with_custom_op
.or
.build;
Use Cases
- Search filters: let users build complex queries
- Access control: evaluate permission rules
- Rule engines: serialize business logic
- Feature flags: target users with complex conditions
Examples
Runnable examples covering derive, parser, custom operators, collections,
serialization, and HashMap fields live in the dnf/examples/
directory of the repository.
License
MIT OR Apache-2.0