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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! # MeterStore
//!
//! Hot/cold tiered store for metering time series: PostgreSQL holds the recent
//! interval window, Apache Iceberg holds the history, and a single explicit
//! timestamp — the *tiering watermark* — separates them.
//!
//! MeterStore is the persistence layer of the [mako](https://github.com/hupe1980/mako)
//! platform. It stores the types defined by the [`metering`] crate; it does not
//! redefine them and it does not compute with them.
//!
//! ## What this crate owns
//!
//! Exactly three things beyond storage mechanics:
//!
//! 1. **Correction versioning** — [`version`], implementing MSCONS's rule that
//! versions are only comparable within a (network operator, month) scope.
//! 2. **The transaction-time axis** — `recorded_at`, giving bitemporality
//! alongside `metering`'s valid time (`from`/`to`).
//! 3. **The tiering boundary** — [`watermark`].
//!
//! Everything else — DST calendars, unit conversion, quality semantics,
//! validation, Ersatzwertbildung — belongs to [`metering`]. Duplicating any of
//! it here would create a second implementation to keep correct, and it would
//! drift.
//!
//! [`planner`] re-exports `metering::calendar` for convenience, so callers get
//! DST-correct local days without depending on both crates directly. The
//! implementation is upstream and there is only one of it.
//!
//! ## The five things a caller usually wants
//!
//! - [`MeterStore::sql`] — DataFusion's own `DataFrame` over a table that spans
//! both tiers. [`MeterStore::query`] returns the same rows plus the boundary
//! they were computed against (P1).
//! - [`MeterStore::series`] — one measuring point as a `metering`
//! `MeasurementSeries`, version-resolved and tier-split.
//! - [`MeterStore::as_of`] — the same queries against a pinned Iceberg snapshot
//! and an optional version ceiling, for a settlement rerun.
//! - [`MeterStore::completeness`] — whether a range holds what the DST-aware
//! calendar says it should, because a missing interval is information rather
//! than an empty set.
//! - [`MeterCatalog`] — several tables in one session, when a deployment holds
//! more than one stream and needs a statement that mentions both.
//!
//! ## What is stored
//!
//! All four Sparten. `value` carries the quantity and `unit` its dimension,
//! because water is metered *and billed* in m³ and gas may sit on either side of
//! the Brennwert conversion — a column named for kilowatt-hours would be wrong
//! for half of them. A unit the commodity cannot be expressed in is refused at
//! the write.
//!
//! Any declared resolution, not only the quarter-hour: completeness asks
//! `metering`'s calendar per day, so one-minute data expects 1 440 intervals on
//! an ordinary day and 1 500 on the 25-hour autumn one.
//!
//! ## Status
//!
//! Pre-alpha, and **unpublished on purpose**: the API is still settling, and
//! integrating against a real workload is what settles it. Encoding, tiering,
//! streaming archival, tier-split query
//! execution, reproducible reads, completeness, multi-table sessions and both
//! serving surfaces are implemented, and checked against an independently
//! implemented reference over generated workloads ([`testkit`]) on real
//! PostgreSQL and a real Iceberg warehouse. The planner's safety properties —
//! that an extracted range never excludes a row the filter admits, and that
//! every instant lands in exactly one tier — are asserted over generated inputs
//! rather than chosen ones.
//!
//! The output is checked to be readable **without this crate** — the files
//! opened by a bare Parquet reader, the published resolution SQL verified
//! against them, and a real **DuckDB** container reading both the Parquet and
//! the Iceberg metadata and agreeing. That is the substance of the open-format
//! claim.
//!
//! Compression against PostgreSQL row storage is measured on real
//! infrastructure — ~109×, comfortably past the >10× the design targets.
//!
//! Serving surfaces: a read-only Iceberg REST façade (`catalog-facade`) for
//! SQL-catalog deployments, and Flight SQL (`flight`) for the one thing an
//! external client cannot assemble for itself — the unified hot + cold view.
//!
//! The cold tier accepts any `Arc<dyn Catalog>`; two are built for you —
//! [`IcebergSqlCatalog`] over the same PostgreSQL as the hot tier, and
//! [`cold::S3TablesCatalog`] over an AWS S3 Tables table bucket
//! (`s3tables`).
//!
//! Not yet done: interop against Spark and Trino, and the query-latency
//! benchmarks, so the p99 targets remain aspirational. Compaction and
//! orphan-file cleanup are blocked on the upstream `iceberg` crate.
//!
//! Full documentation: <https://hupe1980.github.io/meterstore>
//!
//! [`MeterStore::sql`]: crate::session::MeterStore::sql
//! [`MeterStore::query`]: crate::session::MeterStore::query
//! [`MeterStore::series`]: crate::session::MeterStore::series
//! [`MeterStore::as_of`]: crate::session::MeterStore::as_of
//! [`MeterStore::completeness`]: crate::session::MeterStore::completeness
//! [`MeterCatalog`]: crate::session::MeterCatalog
// Doc comments throughout cite `§N`. Those are cross-references between the
// design notes this crate's maintainers keep, not links a reader needs to
// follow: everything required to *use* the crate is in the documentation here,
// and the reasoning behind each decision is written out at
// <https://hupe1980.github.io/meterstore>. The markers exist so that changing a
// behaviour is traceable to the argument it rested on.
/// Arrow, re-exported from DataFusion.
///
/// Sourced through `datafusion` rather than as a direct dependency so the graph
/// cannot contain two incompatible `arrow` versions — a mismatch would make
/// `RecordBatch` and `TableProvider` types mutually unusable. Every module uses
/// `crate::arrow`, never a direct `arrow::` path.
pub use arrow;
pub use S3TablesCatalog;
pub use ;
pub use ;
pub use canonical_obis;
pub use ;
pub use ;
pub use ;
pub use PostgresHot;
pub use ;
pub use ;
pub use Settings;
pub use ;
pub use ;
pub use ;
/// Common imports for working with MeterStore.