Serde
Toql structs usually have a lot of Option
types to make fields selectable with a query.
Let's look how to attribute them with serde for smooth interaction.
This requires the feature serde
for Toql:
[dependencies]
toql = {version = "0.4", features=["serde"]}
Serializing
It's nice to omit unselected fields. This can easily achieved with #[serde(skip_serializing_if = "Option::is_none")]
Serialize example
# #![allow(unused_variables)] #fn main() { use toql::prelude::{Toql, Join}; use serde::Serialize; # #[derive(Toql, Serialize)] # struct Address { # #[toql(key)] # id: u64 # } #[derive(Toql, Serialize)] struct User { #[toql(key)] id: u64, #[serde(skip_serializing_if = "Option::is_none")] age: Option<u8>, #[serde(skip_serializing_if = "Option::is_none")] #[toql(join)] address: Option<Option<Join<Address>>> // Selectable left join } #}
Deserializing
Your server needs deserializing either
- when creating a new item
- or when updating an existing item
Deserialize example:
use toql::prelude::Toql;
#[derive(Toql)]
#[toql(auto_key)]
struct User {
// Serde `default` allows missing field `id` in Json
// Needed typically for insert and auto key
#[serde(default)]
#[toql(key)]
id: u64
// No Serde attribute
// Field must always be present in Json, but may be `null` -> `Option::None`
// Fields that are `None` wont be updated.
name: Option<String>
// Never deserialize expressions
#[serde(skip_deserializing)]
#[toql(sql = "(SELECT COUNT(*) From Book b WHERE b.author_id = ..id)")]
pub number_of_books: Option<u64>,
// See comment below
#[serde(default, deserialize_with="des_double_option")]
address: Option<Option<Join<Address>>>
}
Notice the double Option
on the selectable left join address
.
When deserializing from JSON the following mapping works:
JSON | Rust |
---|---|
undefined | None |
null | Some(None) |
value | Some(Some(value)) |
To make this happen you need a custom deserialization function:
# #![allow(unused_variables)] #fn main() { use serde::{Deserializer, Deserialize}; pub fn des_double_option<'de, T, D>(de: D) -> Result<Option<Option<T>>, D::Error> where T: Deserialize<'de>, D: Deserializer<'de>, { Deserialize::deserialize(de).map(Some) } #}
Now you get the following:
- If you omit address in your JSON
#[serde(default)]
kicks in and you getNone
. - If you send
"addess": null
, you getSome(None)
. - If you send
"address: {"id": 5}"
, you getSome(Some(Join::Key(AddressKey{id:5})))
. - If you send
"address: {"id": 5, ...}"
, you getSome(Some(Join::Entity(Address{id:5, ...})))
.
Toql update will now work as expected.