Announcing Diesel — A Safe, Extensible ORM and Query Builder for Rust
I’m pleased to announce the release of version 0.1 of Diesel, a new ORM and Query builder for Rust. Diesel gets rid of the boilerplate for database interaction and eliminates runtime errors, without sacrificing performance.
Diesel provides an expressive query builder, similar to projects like Arel and Squeel, but utilizes Rust’s type system to ensure a query is correct at compile time. It also provides code generation to read queries into structs and make it dead simple for other CRUD operations.
What Does it Look Like?
Here’s an example of what some code from crates.io looks like when ported over to Diesel:
let versions = Version::belonging_to(krate)
let downloads = try!(version_downloads
.filter(date.gt(now - 90.days()))
This is ultimately going to execute this query:
SELECT version_downloads.* FROM version_downloads
WHERE date > NOW() - '90 days'::interval
AND version_id = ANY(SELECT id FROM versions
WHERE crate_id = 1
ORDER BY num DESC
ORDER BY date;
What Makes Diesel Different?
Truly Type Safe
Diesel takes advantage of Rust’s type system to catch errors at compile time, rather than a database error at runtime. Some of what it can catch includes:
- Reading a column into the wrong type (e.g. `VarChar` into `i32` or a nullable column into anything other than an `Option`)
- Referencing a column that isn’t on the table you’re querying
- Treating the right side of a left join as non-nullable
- Mixing aggregate and non-aggregate expressions in the same select statement
- And much more. We have a ton of tests to ensure these fail to compile!
Designed for Performance
Our query builder performs no boxing or allocations by default. This means that while your code can feel high level, the compiler can optimize away and inline almost all of it.
We make extensive use of unit structs to make this happen, meaning many queries have a size of zero. Since a zero-sized type can contain no useful runtime information, this means that the construction of the query is guaranteed to get eliminated by the compiler, resulting in code as fast as if you’d hand rolled it. And don’t worry, we have tests for this, too.
Extensible at its Core
No ORM can anticipate every use case, which is why we’ve made sure it’s easy for other crates or your code to add support for new things. I’ve maintained the Active Record gem for quite some time now, and have applied the lessons learned there to our design.
Have a custom SQL function? Making it possible to use it with the query builder is a one-liner. It took 15 minutes and 100 lines of code to write a separate crate for full text search support. All sorts of extensions can be plugged right in. They can take full advantage of the same static guarantees that we have for the core framework.
What’s in Version 0.1?
We are by no means feature complete, in fact we’ve already identified a hole in the API to fill, but in the initial release we support all standard CRUD operations, basic joins without repeating the same ON clause, a wide array of predicates for filtering, and a DSL for constructing any sort of moderately complex query.
We’re at the point where I’m ready for people to really start tearing into this thing. There’s still iteration happening, but the core has proven to be a joy to use, and stable enough to release to the world.
Diesel only supports PostgreSQL for the time being, and I hope to add support for other databases in the future.
Version 0.2! There’s still several low hanging fruit for filling out our API, and some inconsistencies that I’d like to correct sooner rather than later. Beyond that, there’s some less easy things that I’d like to tackle, like what the JSON and HStore data types should look like.
Have problems or questions? Come ask! I’m happy to help, and I’m looking to find the use cases that I’ve missed. I can’t wait to see what you build with it.