Module django_query::filtering
source · [−]Expand description
Create filters for Rust objects from query URLs.
Django encodes database queries into URL query strings in a way
that can be frustrating to replicate ad-hoc. The simplest query
parts are things like foo=3
which means the column foo
must
have the exact value 3. More precisely, it means: “apply the
default operator for column foo
, to the contents of that column
for each row, with a right hand side of 3, and only include the
row if the result is true
. The default operator is usually
exact
.
There are three ways Django extends this simple model. Firstly,
it’s possible to specify a different operator than the default
for some columns. Standard Django operators include contains
,
gt
, lt
, in
, iexact
and isnull
. These are written in
the query string as, for example, foo__lt=3
, which filters on
foo < 3
.
Secondly, columns can be multivalued. If in the preceding example
column foo
an array of integers, then foo=3
would mean that
the array must contain 3. In general, for collection valued
columns, a filter is considered to pass if any individual element
passes.
Thirdly, there can be relations between tables. For example, if
the column foo
was actually of some complex type, drawn from a
different table, then it’s possible to filter within foo. Suppose
the table for the type of member foo
has a column bar
, then
our query string could be foo__bar=3
to mean “select all objects
whose member foo
has a member bar
whose value is 3”.
All of the preceding features combine, so it’s possible to end up
with query strings like foo__bar__baz__lt=5
with the meaning
(due to the structure with collections): “include objects within
whose collection for member foo
, one item has a member bar
,
and within that object’s member bar
one item has a member baz
,
and within the collection of integers for that object’s member
baz
one integer is less than 5”.
The main trait in this module is Filterable which has an associated derive macro. Deriving Filterable means it’s possible to construct a OperatorSet for a type. This can be given query strings, and will convert them into boxed Filter objects. The virtual function call overhead is right at the top here, in the call to the filter object, so where possible filtering entire vectors at a time is preferable to reduce overheads (since each call into the boxed Filter incurs overhead, but only one such call is needed to filter an entire collection.)
Example
use django_query::{Filterable, OperatorSet};
#[derive(Filterable)]
struct Bar {
#[django(op(lt))]
a: i32,
}
#[derive(Filterable)]
struct Foo {
#[django(op(lt))]
a: i32,
#[django(traverse)]
b: Bar,
}
let foo = Foo { a: 5, b: Bar { a: 0 } };
let qr = OperatorSet::<Foo>::new();
let filter = qr.create_filter_from_query("b__a__lt=1").unwrap();
assert!(filter.filter_one(&foo));
let filter = qr.create_filter_from_query("b__a__lt=0").unwrap();
assert!(!filter.filter_one(&foo));
Note that self-including types - types that have members of their own type, at some level of indirection - cannot be handled by this crate because of the commitment to monomorphism. It must always be possible to write out all the valid left hand sides that could occur in a filter, and this will in fact be done automatically when a OperatorSet is constructed.
Structs
A collection of filters for a particular type.
Enums
Traits
A wrapper for one field of another type.
An object representing a test for objects to see whether they are included in a given result set.
An object that can make a Filter.
Something that can produce a Meta for itself.
Something that can receive callbacks about the operators a member supports.
A type holding metadata about another type.
Something that can receive callbacks about the members and fields in a Meta.
A type that Django operators can work on.
Take a single simple value and produce a true/false result.
Something that can make an operator instance from a right-hand side.
Functions
Debug print of a Filterable type Q
, showing the supported
queries.