mnesis_store_testing/
row.rs1use core::fmt;
5
6use bytes::Bytes;
7use futures::StreamExt;
8use futures::pin_mut;
9use mnesis::Version;
10use mnesis_store::StreamKey;
11use mnesis_store::envelope::{PendingEnvelope, PersistedEnvelope, pending_envelope};
12use mnesis_store::store::RawEventStore;
13use mnesis_store::value::SchemaVersion;
14
15#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct ConformanceRow {
19 pub version: u64,
20 pub event_type: String,
21 pub schema_version: u32,
22 pub payload: Vec<u8>,
23 pub metadata: Option<Vec<u8>>,
24}
25
26impl ConformanceRow {
27 #[must_use]
29 pub fn new(version: u64, event_type: &str, payload: Vec<u8>) -> Self {
30 Self {
31 version,
32 event_type: event_type.to_owned(),
33 schema_version: 1,
34 payload,
35 metadata: None,
36 }
37 }
38
39 #[must_use]
41 pub const fn with_schema_version(mut self, schema_version: u32) -> Self {
42 self.schema_version = schema_version;
43 self
44 }
45
46 #[must_use]
51 pub fn with_metadata(mut self, metadata: Vec<u8>) -> Self {
52 self.metadata = Some(metadata);
53 self
54 }
55}
56
57#[derive(Debug, Clone, Hash, PartialEq, Eq)]
59pub struct SubId(String);
60
61impl SubId {
62 #[must_use]
63 pub fn new(s: &str) -> Self {
64 Self(s.to_owned())
65 }
66
67 #[must_use]
70 pub fn key(&self) -> StreamKey {
71 StreamKey::from_slice(self.0.as_bytes())
72 }
73}
74
75impl fmt::Display for SubId {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 f.write_str(&self.0)
78 }
79}
80
81impl AsRef<[u8]> for SubId {
82 fn as_ref(&self) -> &[u8] {
83 self.0.as_bytes()
84 }
85}
86
87#[must_use]
90pub fn envelope_for(row: &ConformanceRow) -> PendingEnvelope {
91 let version = Version::new(row.version).expect("row version must be >= 1");
92 let mut staged = pending_envelope(version)
93 .event_type_bytes(Bytes::from(row.event_type.clone().into_bytes()))
94 .expect("valid event type")
95 .payload(row.payload.clone())
96 .schema_version(
97 SchemaVersion::from_u32(row.schema_version).expect("schema_version must be >= 1"),
98 );
99 if let Some(m) = &row.metadata {
100 staged = staged.metadata(m.clone());
101 }
102 staged.build().expect("valid envelope")
103}
104
105#[must_use]
107pub fn row_of(env: &PersistedEnvelope) -> ConformanceRow {
108 ConformanceRow {
109 version: env.version().as_u64(),
110 event_type: env.event_type().to_owned(),
111 schema_version: env.schema_version(),
112 payload: env.payload().to_vec(),
113 metadata: env.metadata().map(<[u8]>::to_vec),
114 }
115}
116
117pub async fn append_rows<S: RawEventStore>(store: &S, id: &StreamKey, rows: &[ConformanceRow]) {
119 if rows.is_empty() {
120 return;
121 }
122 let envs: Vec<PendingEnvelope> = rows.iter().map(envelope_for).collect();
123 store
124 .append(id, None, &envs)
125 .await
126 .unwrap_or_else(|e| panic!("append of {} rows failed: {e:?}", rows.len()));
127}
128
129pub async fn append_event<S: RawEventStore>(
132 store: &S,
133 id: &StreamKey,
134 version: u64,
135 payload: &[u8],
136) {
137 let expected = Version::new(version.saturating_sub(1));
138 let env = envelope_for(&ConformanceRow::new(version, "E", payload.to_vec()));
139 store
140 .append(id, expected, &[env])
141 .await
142 .unwrap_or_else(|e| panic!("append v{version} failed: {e:?}"));
143}
144
145pub async fn drain_stream<S: RawEventStore>(
147 store: &S,
148 id: &StreamKey,
149 from: Version,
150) -> Vec<ConformanceRow> {
151 let stream = store
152 .read_stream(id, from)
153 .await
154 .unwrap_or_else(|e| panic!("read_stream failed: {e:?}"));
155 pin_mut!(stream);
156 let mut out = Vec::new();
157 while let Some(item) = stream.next().await {
158 let env = item.unwrap_or_else(|e| panic!("read_stream item errored: {e:?}"));
159 out.push(row_of(&env));
160 }
161 out
162}
163
164pub async fn drain_all<S: RawEventStore>(
166 store: &S,
167 from: Option<S::AllPosition>,
168) -> Vec<(S::AllPosition, Vec<u8>)> {
169 let stream = store
170 .read_all(from)
171 .await
172 .unwrap_or_else(|e| panic!("read_all failed: {e:?}"));
173 pin_mut!(stream);
174 let mut out = Vec::new();
175 while let Some(item) = stream.next().await {
176 let (pos, env) = item.unwrap_or_else(|e| panic!("read_all item errored: {e:?}"));
177 out.push((pos, env.payload().to_vec()));
178 }
179 out
180}
181
182pub fn assert_strictly_increasing<P: Copy + Ord + fmt::Debug>(positions: &[(P, Vec<u8>)]) {
184 for w in positions.windows(2) {
185 assert!(
186 w[1].0 > w[0].0,
187 "$all positions must be strictly increasing: {:?} then {:?}",
188 w[0].0,
189 w[1].0,
190 );
191 }
192}