diesel-derive-newtype

derive newtype for diesel traits

Latest version: 2.2.0 registry icon
Maintenance score
15
Safety score
100
Popularity score
73
Check your open source dependency risks. Get immediate insight about security, stability and licensing risks.
Security
  Vulnerabilities
Version Suggest Low Medium High Critical
2.2.0 0 0 0 0 0
2.1.2 0 0 0 0 0
2.1.1 0 0 0 0 0
2.1.0 0 0 0 0 0
2.0.1 0 0 0 0 0
2.0.0 0 0 0 0 0
1.0.2 0 0 0 0 0
1.0.1 0 0 0 0 0
1.0.0 0 0 0 0 0
0.1.2 0 0 0 0 0
0.1.1 0 0 0 0 0
0.1.0 0 0 0 0 0

Stability
Latest release:

2.2.0 - This version may not be safe as it has not been updated for a long time. Find out if your coding project uses this component and get notified of any reported security vulnerabilities with Meterian-X Open Source Security Platform

Licensing

Maintain your licence declarations and avoid unwanted licences to protect your IP the way you intended.

Apache-2.0   -   Apache License 2.0

Not a wildcard

Not proprietary

OSI Compliant


MIT   -   MIT License

Not a wildcard

Not proprietary

OSI Compliant



diesel-derive-newtype

Easy-peasy support of newtypes inside of Diesel.

Rust Crates.io Version

Status

diesel-derive-newtype is small and basically complete -- except for some features that aren't supported by Diesel (see "limitations", below). Additionally, I don't use diesel on a daily basis any more, so most maintenance comes from bug reports or PRs, please open them!

Installation

diesel-derive-newtype supports Diesel according to its major version -- 0.x through 1.x support the corresponding diesel versions, 2.0 supports diesel 2.0, and 2.1 supports 2.1. Generally new versions of diesel-derive-newtype are released when compilation or tests are observed to fail with a newer version of diesel, so newer versions of diesel than the released version of diesel-derive-newtype may work. Bug reports and PRs welcome.

New features are only developed for the currently supported version of Diesel.

[dependencies]
diesel-derive-newtype = "2.1.0"

for Diesel 2.0.x you have to tell cargo not to upgrade diesel-derive-newtype:

[dependencies]
diesel-derive-newtype = "~ 2.0.0"

And for Diesel 1.x:

[dependencies]
diesel-derive-newtype = "1.0"

#[derive(DieselNewType)]

This crate exposes a single custom-derive macro DieselNewType which implements ToSql, FromSql, FromSqlRow, Queryable, AsExpression and QueryId for the single-field tuple struct (NewType) it is applied to.

The goal of this project is that:

  • derive(DieselNewType) should be enough for you to use newtypes anywhere you would use their underlying types within Diesel. (plausibly successful)
  • Should get the same compile-time guarantees when using your newtypes as expression elements in Diesel as you do in other rust code (depends on your desires, see Limitations, below.)

Example

This implementation:

#[macro_use]
extern crate diesel_derive_newtype;

#[derive(DieselNewType)] // Doesn't need to be on its own line
#[derive(Debug, Hash, PartialEq, Eq)] // required by diesel
struct MyId(i64);

Allows you to use the MyId struct inside your entities as though they were the underlying type:

table! {
    my_items {
        id -> Integer,
        val -> Integer,
    }
}

#[derive(Debug, PartialEq, Identifiable, Queryable)]
struct MyItem {
    id: MyId,
    val: u8,
}

Oooohhh. Ahhhh.

See the tests for a more complete example.

Limitations

The DieselNewtype derive does not create new database types, or Diesel serialization types. That is, if you have a MyId(i64), this will use Diesel's underlying BigInt type, which means that even though your newtypes can be used anywhere the underlying type can be used, the underlying types, or any other newtypes of the same underlying type, can be used as well.

At a certain point everything does become bits on the wire, so if we didn't do it this way then Diesel would have to do it somewhere else, and this is reasonable default behavior (it's pretty debuggable), but I'm investigating auto-generating new proxy types as well to make it impossible to construct an insert statement using a tuple or a mis-typed struct.

Here's an example of that this type-hole looks like:

#[derive(Debug, Hash, PartialEq, Eq, DieselNewType)]
struct OneId(i64);

#[derive(Debug, Hash, PartialEq, Eq, DieselNewType)]
struct OtherId(i64);

#[derive(Debug, Clone, PartialEq, Identifiable, Insertable, Queryable)]
#[diesel(table_name = my_entities)]
pub struct MyEntity {
    id: OneId,
    val: i32,
}

fn darn(conn: &Connection) {
    // shouldn't allow constructing the wrong type, but does
    let OtherId: Vec<OtherId> = my_entities
        .select(id)
        .filter(id.eq(OtherId(1)))  // shouldn't allow filtering by wrong type
        .execute(conn).unwrap();
}

See tests/should-not-compile.rs for the things I think should fail to compile.

I believe that the root cause of this is that Diesel implements the various expression methods for types that implement AsExpression, based on the SQL type, not caring about self and other's Rust type matching. That seems like a pretty good decision in general, but it is a bit unfortunate here.

I hope to find a solution that doesn't involve implementing every *Expression trait manually with an extra bound, but for now you have to keep in mind that the Diesel methods basically auto-transmute your data into the underlying SQL type.

Releasing

This workflow uses:

Run, note that we always release patch releases unless diesel has got a new release:

cargo readme > README.md
git diff --exit-code --quiet README.* || (git add README.* && git commit -m "chore: Update README")
cargo release patch

License

diesel-derive-newtype is licensed under either of

at your option.

Patches and bug reports welcome!