unobtanium/criterium
1
0
Fork
You've already forked criterium
0
A little framework for dynamic database queries
  • Rust 100%
Slatian 23eece321f
All checks were successful
Cargo Audit / Audit (push) Successful in -3m5s
Cargo Build and Test / Build and Test (push) Successful in -2m46s
Cargo Fmt / Check_Rust_Formatting (push) Successful in -3m9s
Version bump to 3.1.3
2026年01月17日 14:17:26 +01:00
.forgejo/workflows Add reuse linting to build and test workflow 2025年12月20日 19:10:41 +01:00
LICENSES Make project reuse 3.3 compliant 2025年08月01日 17:32:56 +02:00
src Switch has and has not subqueries to IN and NOT IN instead of EXISTS 2026年01月09日 18:22:00 +01:00
.gitignore Make project reuse 3.3 compliant 2025年08月01日 17:32:56 +02:00
Cargo.lock cargo update 2026年01月17日 14:12:46 +01:00
Cargo.toml Version bump to 3.1.3 2026年01月17日 14:17:26 +01:00
Concepts.md Make project reuse 3.3 compliant 2025年08月01日 17:32:56 +02:00
README.md Use new header layout in README.md 2025年08月15日 11:50:14 +02:00
REUSE.toml Make project reuse 3.3 compliant 2025年08月01日 17:32:56 +02:00
rustfmt.toml Make project reuse 3.3 compliant 2025年08月01日 17:32:56 +02:00
Serde.md Make project reuse 3.3 compliant 2025年08月01日 17:32:56 +02:00

Criterium

Documentation | Codeberg

Criterium is a mini-framework to make implementing dynamic conditions and database queries easier.

It does so by supplying the needed datastructures that can be compiled to SQL and a list of values or directly matched against a given value.

Multiple Criteria can also be combined using Boolean logic (chains).

Dynamic also means configurable, Criterium integrates itself with Serde.

It currently integrates with rusqlite.

How does it work?

Also see the concepts document.

Usually when building database query one starts out with a relatively simple function:

fn fetch_bookmark_information(is_favorite: Option<bool>,name_contains: Option<String>,tags: Vec<String>,but_not_tags: Vec<String>,// ...
)-> Vec<Bookmark>;

But as you can see even from this simple example: This won't scale very well and writing the SQL generation for that by hand is a tedious nightmare (even when switching over to structs).

And most of the time one doesn't even need all the options available. This is where Criterium comes in.

With Criterium you have an enum that describes all the possible queries for a datatype.

enum BookmarkCriterium{IsFavorite(BooleanCriterium),Name(StringCriterium),HasTag(StringCriterium),// ...
}implToRusqliteQueryforBookmarkCriterium{fn get_sql_where(&self)-> String {matchself{Self::IsFavorite(c)=>c.get_sql_where("favorite".to_string()),Self::Name(c)=>c.get_sql_where("name".to_string()),}}fn get_where_values(&self)-> Vec<Value>{matchself{Self::IsFavorite(c)=>c.get_where_values(),Self::Name(c)=>c.get_where_values(),}}}

Note: Not all of the datatypes of the example are implemented yet, but it should be pretty straigtforward to implement them outside of Criterium.

Multiple of these are then combined using a CriteriumChain:

letchain_builder: CriteriumChainBuilder<BookmarkCriterium>=CriteriumChainBuilder::and(true);chain_builder.add_criterium(BookmarkCriterium::IsFavorite(true.into()));chain_builder.add_criterium(BookmarkCriterium::HasTag("tag".into()));chain_builder.add_criterium(BookmarkCriterium::HasTag(StringCriterium::HasPrefix("useful:")));chain_builder.add_criterium(BookmarkCriterium::Name(StringCriterium::Contains("foo")));letbookmarks=database.query_bookmarks(chain_builder.to_chain());

While at first glance this looks more verbose (it is) this can be assembled on the fly and is more flexible (Noticed how I snug a prefix match on a tag in there?).

The SQL in the background simply has a WHERE with the output of the chain.get_sql_where() concatenated after and the values taken from chain.get_where_values(), you only have to provide the values your Criterium relies on in the SQL query.

As you can tell this is useful when there are a lot of things to query for, and also pretty opinioated, it may oe may not fit your project.

Isn't that an Object Relational Model (ORM) like in django?

Yes, kind of. But very lightweight and barebones ... and the compiler can verify most of it for you.

Feature Flags

By default all integrations that require external crates are disabled. More integrations to come soonishTM.

  • rusqlite - Enables rusqlite integration (compiling criteria to SQL)
  • chrono - Enables chrono integration (passing a DateTime in place of a number)
  • serde - Enables serializing and deserializing criteium-chains and default criteria using serde.
  • full - Enable all features, useful for building documentation, for dependencies you should explicitly enable all features you need.

What is in here?

Note: If you are reding this from the rust domunetation, the links are broken.

  • boolean - A Criterium for matching boolean values.
  • number - A Criterium for matching numbers.
  • string - A Criterium for matching text.
  • search - A Criterium for integrating full text search capabilities.
  • chain - A Criterium for connecting other criteria with boolean operators
    • builder.rs - A builder struct to make it easier to construct chains.
    • rusqlite.rs - Rusqlite integration.
  • rusqlite.rs - Traits for integrating with rusqlite.

License

Criterium is licensed under the LGPL-3.0-only license.

The project aims to be compliant with version 3.3 of the reuse specification.