В своем ответе я буду хранить объект JSON в БД в строковом представлении (схема: TEXT).
Для нашего неподдерживаемого типа нам нужны следующие характеристики: ToSql
, FromSql
, AsExpression
и FromSqlRow
.
Теперь, поскольку нельзя реализовать признак для типа, поступающего из внешнего ящика, его необходимо заключить в один кортеж элемента:
struct MyJsonType(serde_json::Value)
Теперь FromSql
реализация черты:
impl FromSql<Text, DB> for MyJsonType {
fn from_sql(
bytes: Option<&<diesel::sqlite::Sqlite as Backend>::RawValue>,
) -> deserialize::Result<Self> {
let t = <String as FromSql<Text, DB>>::from_sql(bytes)?;
Ok(Self(serde_json::from_str(&t)?))
}
}
И ToSql
Черта реализации:
impl ToSql<Text, DB> for MyJsonType {
fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result {
let s = serde_json::to_string(&self.0)?;
<String as ToSql<Text, DB>>::to_sql(&s, out)
}
}
Теперь остальные черты можно получить с помощью макросов:
#[derive(AsExpression, Debug, Deserialize, Serialize, FromSqlRow)]
#[sql_type = "Text"]
struct MyJsonType(serde_json::Value);
Теперь можно использовать наш новый тип:
#[derive(Debug, Deserialize, Serialize, Queryable, Identifiable)]
#[table_name = "my_table"]
struct Item {
id: i32,
arbitrary_json: MyJsonType
}