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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! The enqueue capability an application calls directly, in its own transaction (ADR 0036
//! amendment B): there is no facade type between the caller and the store.
use ;
/// Enqueuing a typed message in the caller's own transaction. A provider (`PostgresOutboxStore`)
/// implements this directly, alongside [`crate::OutboxStore`]; there is no separate handle type
/// to construct.
///
/// `Tx` is the provider's transaction type: `sqlx::Transaction<'_, Postgres>` for
/// `reliar-store-postgres`. It is a **type parameter** precisely so this crate names no storage
/// type, and one implementor may support several.
///
/// Deliberately **not** a method on [`crate::OutboxStore`]: enqueuing takes a transaction handle
/// the claim side never sees, `OutboxStore` is already published, and a GAT `type Tx<'a>` would
/// have to spell `&'a mut Transaction<'c, _>` and reintroduce an invariance problem.
///
/// **Two methods, one call each** (ADR 0037 amendment A): a required
/// [`Self::enqueue_envelope`] that every implementor writes, and a provided [`Self::enqueue`] —
/// the fire-and-forget spelling — built on top of it. An earlier shape tried an `impl
/// Into<Envelope<T>>` parameter so one method covered both a bare `T: Message` and an
/// already-built `Envelope<T>`; that was rejected in favor of a second, explicit method instead
/// — no inference trick, no `Envelope<T>: !Message` invariant to guard.
///
/// **One serialized twin, deliberately absent** (ADR 0036 amendment B.10): a
/// `enqueue_serialized(&mut tx, &SerializedEnvelope)` existed briefly and was cut for having no
/// production caller; re-adding it is additive.
///
/// Renamed from `OutboxStaging` in 0.4.0; `stage` became `enqueue`, and the facade
/// `OutboxPublisher` that briefly wrapped it (0.4.0, never released) was withdrawn before
/// shipping in favor of calling this trait directly.
///
/// A provider implements the trait, then a caller enqueues in its own transaction — shown here
/// against the `test-support` in-memory fake:
/// # use reliar_core::Message;
/// # use reliar_outbox::{InMemoryOutboxStore, InMemoryTransaction, OutboxEnqueue};
/// # #[derive(serde::Serialize, serde::Deserialize)]
/// # struct OrderCreated;
/// # impl Message for OrderCreated {
/// # const TYPE: &'static str = "orders.created";
/// # const VERSION: u16 = 1;
/// # }
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let store = InMemoryOutboxStore::default();
/// let mut tx = InMemoryTransaction;
/// let id = store.enqueue(&mut tx, OrderCreated).await?;
/// assert!(store.record(id).is_some());
/// # Ok(())
/// # }
/// ```