1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! mako's BO4E boundary: the gate every payload crosses, the structural rules
//! the standard states, and the typed columns a stored document is indexed by.
//!
//! BO4E is deliberately permissive — nearly every field is `Option`, even
//! `Betrag.wert` — so it enforces almost nothing on its own. mako's answer is
//! not to distrust it but to divide the labour:
//!
//! | Layer | Module | What it decides |
//! |---|---|---|
//! | **Gate** | [`gate`] | Is this payload the BO it claims, typed, in-schema, and structurally sound? |
//! | **Rules** | [`conformance`] | The two BO4E-stated rules `rubo4e`'s own validators do not cover; the rest delegate to `.validate()`. |
//! | **Columns** | [`columns`] | Which fields of the stored document are queryable, and with what vocabulary. |
//!
//! One call runs the first two:
//!
//! ```
//! use mako_markt::bo4e;
//! use rubo4e::current::Marktlokation;
//!
//! let payload = serde_json::json!({ "marktlokationsId": "51238696781" });
//! let malo: Marktlokation = bo4e::decode(payload).expect("a valid Marktlokation");
//! assert_eq!(malo.marktlokations_id.as_deref(), Some("51238696781"));
//! ```
//!
//! Everything mako *emits* crosses the same rules on the way out
//! ([`ensure_conformant`]), so mako never ships a document it would refuse to
//! accept.
pub use ;
pub use Bo4eConformance;
// Re-exported so a caller rendering a rejection does not need its own `rubo4e`
// dependency just to name the failure type.
pub use ;
pub use ValidationFailure;
use Marktlokation;
/// The BO4E schema version every payload mako stores is interpreted under.
///
/// Derived from the linked `rubo4e` rather than written down: mako parses every
/// payload with its own generated types regardless of what a request claims, so
/// the version a row is stamped with is the server's fact, not the client's.
///
/// The column is **provenance, not a migration mechanism** — nothing branches
/// on it. A schema flip means regenerating `rubo4e` and reading existing rows
/// under the new types, which works because unknown fields survive in
/// `_additional`. What the stamp buys is the ability to tell which rows have
/// not been rewritten yet.
pub const SCHEMA_VERSION: &str = SCHEMA_VERSION;
/// The BO4E schema version, as an owned `String`, for `serde` defaults and
/// row construction.
/// The BO4E schema **series** — the `YYYYMM` prefix, without the patch level.
///
/// This is the granularity at which rubo4e exposes a module, and the right key
/// for deciding whether a stored payload is readable: BO4E ships patch releases
/// *inside* a series and every one of them deserializes into the same types.
pub const SCHEMA_SERIES: &str = SCHEMA_SERIES;
/// Is `stored` a payload version this build can read?
///
/// True for **any** release in the current series. Matching the full triple
/// instead rejects a payload from a producer one BO4E patch ahead that mako
/// reads perfectly — and rejected every payload at all when rubo4e 0.10
/// corrected the wire spelling.
///
/// # The `v` is tolerated on input and never written
///
/// BO4E prefixes its git *tags* with a `v`; the `_version` field inside a
/// payload never has one. A stored value carrying it is read rather than
/// refused; what mako *writes* is always [`SCHEMA_VERSION`].