pub trait Schema {
// Required method
fn schema() -> Value;
// Provided method
fn schema_without_null() -> Value { ... }
}Expand description
The JSON schema of a type, which describes exactly what serde writes for it.
The store registers the schema of every event with EventSourcingDB, which from then on rejects events whose data does not match it. A registered schema can not change, so the rules by which a schema is derived do not change either: a type derives the same schema in every version of the kit.
Event derives the schema of an event. Derive Schema for
a type within the data of an event, such as a nested struct:
use architecturekit::{Event, Schema};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Schema)]
struct Address {
city: String,
}
#[derive(Serialize, Deserialize, Event)]
#[event(type = "io.eventsourcingdb.library.reader-registered")]
#[serde(rename_all = "camelCase")]
struct ReaderRegistered {
full_name: String,
address: Address,
#[serde(skip_serializing_if = "Option::is_none")]
nickname: Option<String>,
}
assert_eq!(
ReaderRegistered::schema(),
serde_json::json!({
"type": "object",
"properties": {
"fullName": { "type": "string" },
"address": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"],
"additionalProperties": false
},
"nickname": { "type": "string" }
},
"required": ["fullName", "address"],
"additionalProperties": false
})
);The rules:
- A struct with named fields is an object with the fields serde writes:
named as
renameandrename_allsay, and without the fields marked withskiporskip_serializing. A field withskip_serializing_ifis optional, all others are required, and no other fields are allowed. A newtype struct, and a struct marked withtransparent, is described like the value it wraps. - A
boolis a boolean, an integer type an integer, anf32or anf64a number, and aString, astror achara string. - A
Vec, aVecDeque, a slice, aHashSetand aBTreeSetis an array, and an array[T; N]an array of exactlyNitems. AHashMapand aBTreeMapis an object whose values all have the same schema. - An
Optionmay also be null, unless it is the type of an optional field, which serde leaves out instead of writing null. ABox, anRc, anArc, aCowand a reference are described like what they hold. - A chrono
DateTimeis a string in the date-time format, aserde_json::Numbera number, and aserde_json::Valueallows any value.
A value that may be null is an Option, such as an Option<Vec<_>> or an
Option<HashMap<_, _>>, since serde never writes a Vec or a HashMap as
null. A Vec<u8> is an array of integers, since that is what serde writes
for it.
The schema of an enum, a union, a unit struct, a tuple struct with several
fields, a struct marked with tag, content, into or remote, and a
field marked with flatten, serialize_with or with can not be derived,
since serde writes them differently than their types describe. Deriving it
fails to compile; implement Schema by hand instead. The same applies to a
recursive type, whose schema panics on deriving it.
EventSourcingDB currently reads every number in the data of an event as a 64-bit float, which holds an integer exactly only if its magnitude is at most 2^53-1. A larger integer is stored changed, without an error. To keep a 64-bit integer exact, write it as a string, in a type that describes itself as a string.
Implementing Schema by hand is how a type describes itself further, for
example with a pattern:
use architecturekit::Schema;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
#[derive(Serialize, Deserialize)]
struct Country(String);
impl Schema for Country {
fn schema() -> Value {
json!({ "type": "string", "pattern": "^[A-Z]{2}$" })
}
}Required Methods§
Provided Methods§
Sourcefn schema_without_null() -> Value
fn schema_without_null() -> Value
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".