#diesel #proc-macro #jsonb #postgresql #derive #serialization #procedural

macro diesel-json-derive

Macro crate implementing the proc macro for diesel-json-derive

2 releases

0.1.1 May 20, 2024
0.1.0 May 20, 2024

#343 in Procedural macros

Download history 3/week @ 2024-07-29 8/week @ 2024-09-23 77/week @ 2024-10-14 1125/week @ 2024-10-21 134/week @ 2024-10-28 169/week @ 2024-11-04

1,505 downloads per month

MIT license

10KB
68 lines

diesel-json-derive

NOTE: This is under active development. No guarantees for stability or usability. You probably want diesel_json instead. Please also note that this currently expects postgres. Pull requests to support other backends are welcome.

diesel_json_derive

What's this? This is a procedural macro that automatically derives ToSql and FromSql for Diesel's Jsonb type.

Consider a table like

CREATE TABLE foo (
  id TEXT PRIMARY KEY,
  bar JSONB NOT NULL
);

which is in Rust can be represented as as (does not compile!):

#[derive(Debug, Queryable, Identifiable, Insertable, AsChangeset, Selectable)]
#[diesel(table_name = crate::schema::foo)]
#[diesel(check_for_backend(diesel::pg::Pg))]
#[diesel(primary_key(id))]
struct Foo {
    id: String,
    bar: Bar,
}

struct Bar {
    x: i32,
}

In order to make Bar be represented as a jsonb blob you will need to implement the diesel::deserialize::FromSql and diesel::deserialize::FromSql traits, e.g. like this:

impl ToSql<Jsonb, Pg> for Foo {
    fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result {
        out.write_all(&[1])?;
        serde_json::to_writer(out, &self)?;
        Ok(serialize::IsNull::No)
    }
}

impl FromSql<Jsonb, Pg> for Foo {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        let bytes = bytes.as_bytes();
        if bytes[0] != 1 {
            return Err("Unsupported JSONB encoding version".into());
        }
        serde_json::from_slice(&bytes[1..]).map_err(|_| "Invalid Json".into())
    }
}

This gets tedious quickly so this create does it for you. So with this crate you can write:

use diesel::sql_types::Jsonb;
use diesel::{FromSqlRow, AsExpression};
use diesel_json_derive::DieselJsonb;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, AsExpression, FromSqlRow, DieselJsonb)]
#[diesel(sql_type = Jsonb)]
struct Bar {
    x: i32,
}

diesel_json_derive vs ## diesel_json

The diesel_json crate solves the same problem but uses a wrapper type for it. This has the disadvantage that this type needs to be used when matching for example. This crate does not have this disadvantage.

License: MIT

Dependencies

~230–670KB
~16K SLoC