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
//! SQLx integration for BO4E identifier types.
//!
//! ## What is implemented
//!
//! When the `sqlx` feature is enabled the following traits are implemented for
//! **all** identifier types (`MaloId`, `MeloId`, `NeloId`, `SrId`, `TrId`,
//! `EicCode`, `MarktpartnerId`, `ObisCode`):
//!
//! | Trait | Effect |
//! |-------|--------|
//! | `sqlx::Type<Postgres>` | maps to PostgreSQL `TEXT` |
//! | `sqlx::Encode<'_, Postgres>` | binds as `&str` (zero-copy) |
//! | `sqlx::Decode<'_, Postgres>` | reads `TEXT`, validates, returns typed ID |
//!
//! ## Usage
//!
//! Use the identifier type directly as a bind parameter or result column:
//!
//! ```rust,ignore
//! use rubo4e::identifiers::{MaloId, MarktpartnerId};
//!
//! // As a query bind parameter:
//! sqlx::query("INSERT INTO malo (id) VALUES ($1)")
//! .bind(&malo_id) // MaloId implements Encode
//! .execute(&pool).await?;
//!
//! // As a result column via try_get:
//! let id: MaloId = row.try_get("malo_id")?;
//! let mp: MarktpartnerId = row.try_get("mp_id")?;
//!
//! // As a struct field in query_as!:
//! #[derive(sqlx::FromRow)]
//! struct MpRow {
//! mp_id: MarktpartnerId, // decoded + validated automatically
//! }
//! let rows: Vec<MpRow> = sqlx::query_as("SELECT mp_id FROM parties")
//! .fetch_all(&pool).await?;
//! ```
//!
//! ## Error behaviour
//!
//! Decoding validates the value using the same rules as `TryFrom<String>`.
//! An invalid value stored in the database (e.g. a MaLo-ID with a wrong check
//! digit) causes `row.try_get(...)` to return `Err(...)` wrapping an
//! [`IdentifierError`](crate::error::IdentifierError).
//!
//! ## `PgHasArrayType`
//!
//! `PgHasArrayType` is **not** implemented — PostgreSQL array columns (`TEXT[]`)
//! are not needed for energy-market identifiers and the blanket impl would pull
//! in additional SQLx internals. If you need array support, implement it locally:
//!
//! ```rust,ignore
//! impl sqlx::postgres::PgHasArrayType for MaloId {
//! fn array_type_info() -> sqlx::postgres::PgTypeInfo {
//! <String as sqlx::postgres::PgHasArrayType>::array_type_info()
//! }
//! }
//! ```
/// Stamps out `sqlx::Type + Encode + Decode` for a newtype that wraps a
/// validated string and implements `TryFrom<String>` + `AsRef<str>`.
use crate;
impl_sqlx_text!;