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
//! Export contract — generic over [`RawEventStore`], raw and box-agnostic.
//!
//! Export is a **generic store capability**, defined against
//! [`RawEventStore`] only — it never touches a wire frame or an adapter
//! partition, so it works for the in-memory store, fjall, and a future
//! postgres store alike.
//!
//! Export does **no data manipulation**. `export_stream(id, from)` is a pass
//! through to [`RawEventStore::read_stream`] — it yields the stored
//! [`PersistedEnvelope`](crate::envelope::PersistedEnvelope)s verbatim. The events are not rewritten, the
//! store-local `global_seq` is not stripped, and the stream id is not stamped
//! onto each event. Two facts make that unnecessary:
//!
//! - **The caller supplies the id.** `export_stream(id, …)` is per-stream, so
//! the caller already knows which stream the events belong to — exactly like
//! a read. The stream id never has to ride on each event.
//! - **Import re-appends.** On restore, import writes events through the
//! normal append path, which stamps a fresh `global_seq` itself. The old
//! store-local value simply rides along and is ignored — stripping it at
//! export would be work import redoes for free.
//!
//! Two traits:
//!
//! - [`StreamLister`] — enumerate the stream ids a store holds. The one new
//! store-layer capability export needs; an all-streams export is
//! `list_streams` ∘ `export_stream`.
//! - [`EventExporter`] — open a per-stream export (a raw read).
//!
//! The stream id *is* recorded once per stream — but in the **backup box**
//! (the CBOR default, a later card), as a per-stream section heading, never on
//! the events. A restore reads that heading to route the section back to the
//! right stream; import then ignores each event's `global_seq`. See issue
//! #145 §5.
use Stream;
use Version;
use crate;
use crateEventStream;
use crateStreamKey;
/// Enumerate the stream ids present in a store.
///
/// The generic source of "which streams exist" — needed because a backup of
/// an arbitrary store doesn't know its ids up front, and `export_stream`
/// requires one. Yields the raw stream-id bytes (the form the store holds
/// them in); the caller reconstitutes a typed [`Id`] if it needs one.
///
/// Lazy and async, mirroring [`RawEventStore::read_all`]: a store with many
/// streams streams its ids rather than materializing them all.
///
/// Adapters back this with whatever index already tracks streams (fjall: its
/// `streams` partition; in-memory: its map; postgres: `SELECT DISTINCT`).
/// Export a single stream's events — a raw pass-through read.
///
/// `export_stream(id, from)` reads stream `id` from `from` **inclusive** (the
/// same semantics as [`RawEventStore::read_stream`]: `from = Version::INITIAL`
/// yields the whole stream from v1) up to its current head, then terminates.
/// Each yielded [`PersistedEnvelope`](crate::envelope::PersistedEnvelope) is the stored event **verbatim** — no
/// rewrite, `global_seq` intact, no per-event stream id.
///
/// `from` is inclusive because the type forbids otherwise: [`Version`] is a
/// `NonZeroU64` (minimum 1), so an exclusive `from` could never include v1 and
/// a full export would be impossible. To **resume** after the last exported
/// version `V`, pass `V.next()` (the caller's responsibility, mirroring how a
/// subscription cursor resumes).
///
/// The stream is **pull-based**: it reads as polled, in bounded memory, so a
/// consumer can write events to a file incrementally over any timespan.
///
/// `export_all` (`list_streams` ∘ `export_stream`) and continuous/live export
/// (compose with the never-ending `subscribe` cursor) are consumer-side
/// combinators, not part of this trait. The blanket impl below makes **every**
/// [`RawEventStore`] an `EventExporter` for free.
/// Every [`RawEventStore`] is an [`EventExporter`] — export is just a read.
///
/// `export_stream` forwards to [`RawEventStore::read_stream`] unchanged, so the
/// associated [`ExportStream`](EventExporter::ExportStream) is the adapter's
/// own [`Stream`](RawEventStore::Stream) type: a concrete, monomorphized
/// cursor with no boxing, no dynamic dispatch, and no per-event transform.
/// `Store<S>` forwards [`StreamLister`] to its inner backend (issue #247), so a
/// handle holder can `store.list_streams()` without `.raw()`. `EventExporter`
/// then applies to `Store<S>` via the blanket impl above (`Store<S>` is itself a
/// [`RawEventStore`]).