Skip to content

Commit f08a2d6

Browse files
committed
refactor(catalog,event): migrate serialization from serde to zerompk with schema-evolution attributes
Replace serde Serialize/Deserialize derives with zerompk ToMessagePack/ FromMessagePack across all catalog entry types and event-plane types. Every struct gains `#[msgpack(map)]` for named-field encoding and `#[msgpack(default)]` on optional/defaultable fields, enabling safe forward and backward-compatible schema evolution as new fields are added. Removes the serde dependency from all affected modules; test helpers that previously used serde_json for roundtrip assertions are updated to use zerompk directly.
1 parent 5ffaab4 commit f08a2d6

27 files changed

Lines changed: 203 additions & 623 deletions

File tree

nodedb/src/control/catalog_entry/entry.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
//! it (the apply / post_apply / tests modules use exhaustive
77
//! matches).
88
9-
use serde::{Deserialize, Serialize};
10-
119
use crate::control::security::catalog::{
1210
StoredCollection, StoredMaterializedView, StoredRlsPolicy,
1311
auth_types::{
@@ -21,9 +19,7 @@ use crate::control::security::catalog::{
2119
use crate::event::cdc::stream_def::ChangeStreamDef;
2220
use crate::event::scheduler::types::ScheduleDef;
2321

24-
#[derive(
25-
Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
26-
)]
22+
#[derive(Debug, Clone, zerompk::ToMessagePack, zerompk::FromMessagePack)]
2723
pub enum CatalogEntry {
2824
// ── Collection ─────────────────────────────────────────────────
2925
/// Upsert a collection record. Used by CREATE COLLECTION and by

nodedb/src/control/security/catalog/auth_types.rs

Lines changed: 24 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
//! Authentication and authorization type definitions for redb catalog storage.
22
33
/// Serializable user record for redb storage.
4-
#[derive(
5-
serde::Serialize,
6-
serde::Deserialize,
7-
zerompk::ToMessagePack,
8-
zerompk::FromMessagePack,
9-
Debug,
10-
Clone,
11-
)]
4+
#[derive(zerompk::ToMessagePack, zerompk::FromMessagePack, Debug, Clone)]
5+
#[msgpack(map)]
126
pub struct StoredUser {
137
pub user_id: u64,
148
pub username: String,
@@ -20,31 +14,25 @@ pub struct StoredUser {
2014
pub is_superuser: bool,
2115
pub is_active: bool,
2216
/// True if this is a service account (no password, API key auth only).
23-
#[serde(default)]
17+
#[msgpack(default)]
2418
pub is_service_account: bool,
2519
/// Unix timestamp (seconds) when the user was created.
26-
#[serde(default)]
20+
#[msgpack(default)]
2721
pub created_at: u64,
2822
/// Unix timestamp (seconds) when the user was last modified.
29-
#[serde(default)]
23+
#[msgpack(default)]
3024
pub updated_at: u64,
3125
/// Unix timestamp (seconds) when the password expires. 0 = no expiry.
32-
#[serde(default)]
26+
#[msgpack(default)]
3327
pub password_expires_at: u64,
3428
/// MD5 hash for pgwire MD5 auth: `md5(password + username)` as hex.
35-
#[serde(default)]
29+
#[msgpack(default)]
3630
pub md5_hash: String,
3731
}
3832

3933
/// Serializable API key record for redb storage.
40-
#[derive(
41-
serde::Serialize,
42-
serde::Deserialize,
43-
zerompk::ToMessagePack,
44-
zerompk::FromMessagePack,
45-
Debug,
46-
Clone,
47-
)]
34+
#[derive(zerompk::ToMessagePack, zerompk::FromMessagePack, Debug, Clone)]
35+
#[msgpack(map)]
4836
pub struct StoredApiKey {
4937
/// Unique key identifier (used as prefix in the token).
5038
pub key_id: String,
@@ -62,19 +50,12 @@ pub struct StoredApiKey {
6250
pub created_at: u64,
6351
/// Permission scope restriction. Empty = inherit all user permissions.
6452
/// Format: ["read:collection_name", "write:collection_name", ...]
65-
#[serde(default)]
53+
#[msgpack(default)]
6654
pub scope: Vec<String>,
6755
}
6856

6957
/// Serializable tenant record for redb storage.
70-
#[derive(
71-
serde::Serialize,
72-
serde::Deserialize,
73-
zerompk::ToMessagePack,
74-
zerompk::FromMessagePack,
75-
Debug,
76-
Clone,
77-
)]
58+
#[derive(zerompk::ToMessagePack, zerompk::FromMessagePack, Debug, Clone)]
7859
pub struct StoredTenant {
7960
pub tenant_id: u32,
8061
pub name: String,
@@ -83,14 +64,8 @@ pub struct StoredTenant {
8364
}
8465

8566
/// Serializable audit entry for redb storage.
86-
#[derive(
87-
serde::Serialize,
88-
serde::Deserialize,
89-
zerompk::ToMessagePack,
90-
zerompk::FromMessagePack,
91-
Debug,
92-
Clone,
93-
)]
67+
#[derive(zerompk::ToMessagePack, zerompk::FromMessagePack, Debug, Clone)]
68+
#[msgpack(map)]
9469
pub struct StoredAuditEntry {
9570
pub seq: u64,
9671
pub timestamp_us: u64,
@@ -99,19 +74,12 @@ pub struct StoredAuditEntry {
9974
pub source: String,
10075
pub detail: String,
10176
/// SHA-256 hash of the previous entry (hex). Empty for first entry.
102-
#[serde(default)]
77+
#[msgpack(default)]
10378
pub prev_hash: String,
10479
}
10580

10681
/// Serializable custom role for redb storage.
107-
#[derive(
108-
serde::Serialize,
109-
serde::Deserialize,
110-
zerompk::ToMessagePack,
111-
zerompk::FromMessagePack,
112-
Debug,
113-
Clone,
114-
)]
82+
#[derive(zerompk::ToMessagePack, zerompk::FromMessagePack, Debug, Clone)]
11583
pub struct StoredRole {
11684
pub name: String,
11785
pub tenant_id: u32,
@@ -121,14 +89,7 @@ pub struct StoredRole {
12189
}
12290

12391
/// Serializable permission grant for redb storage.
124-
#[derive(
125-
serde::Serialize,
126-
serde::Deserialize,
127-
zerompk::ToMessagePack,
128-
zerompk::FromMessagePack,
129-
Debug,
130-
Clone,
131-
)]
92+
#[derive(zerompk::ToMessagePack, zerompk::FromMessagePack, Debug, Clone)]
13293
pub struct StoredPermission {
13394
/// What the grant applies to: "cluster", "tenant:1", "collection:1:users"
13495
pub target: String,
@@ -141,14 +102,7 @@ pub struct StoredPermission {
141102
}
142103

143104
/// Serializable ownership record.
144-
#[derive(
145-
serde::Serialize,
146-
serde::Deserialize,
147-
zerompk::ToMessagePack,
148-
zerompk::FromMessagePack,
149-
Debug,
150-
Clone,
151-
)]
105+
#[derive(zerompk::ToMessagePack, zerompk::FromMessagePack, Debug, Clone)]
152106
pub struct StoredOwner {
153107
/// "collection", "index"
154108
pub object_type: String,
@@ -159,14 +113,7 @@ pub struct StoredOwner {
159113
}
160114

161115
/// Serializable blacklist entry for redb storage.
162-
#[derive(
163-
Debug,
164-
Clone,
165-
serde::Serialize,
166-
serde::Deserialize,
167-
zerompk::ToMessagePack,
168-
zerompk::FromMessagePack,
169-
)]
116+
#[derive(Debug, Clone, zerompk::ToMessagePack, zerompk::FromMessagePack)]
170117
pub struct StoredBlacklistEntry {
171118
/// Blacklist entry key: `"user:{user_id}"` or `"ip:{addr_or_cidr}"`.
172119
pub key: String,
@@ -183,21 +130,15 @@ pub struct StoredBlacklistEntry {
183130
}
184131

185132
/// Serializable JIT-provisioned auth user record for redb storage.
186-
#[derive(
187-
Debug,
188-
Clone,
189-
serde::Serialize,
190-
serde::Deserialize,
191-
zerompk::ToMessagePack,
192-
zerompk::FromMessagePack,
193-
)]
133+
#[derive(Debug, Clone, zerompk::ToMessagePack, zerompk::FromMessagePack)]
134+
#[msgpack(map)]
194135
pub struct StoredAuthUser {
195136
/// Unique identifier (from JWT `sub` or `user_id` claim).
196137
pub id: String,
197138
/// Username (display name).
198139
pub username: String,
199140
/// Email address (from JWT `email` claim).
200-
#[serde(default)]
141+
#[msgpack(default)]
201142
pub email: String,
202143
/// Tenant this user belongs to.
203144
pub tenant_id: u32,
@@ -210,13 +151,13 @@ pub struct StoredAuthUser {
210151
/// Whether this user is active (can authenticate).
211152
pub is_active: bool,
212153
/// Account status: active, suspended, banned, restricted, read_only.
213-
#[serde(default = "default_status")]
154+
#[msgpack(default = "default_status")]
214155
pub status: String,
215156
/// Whether this user was externally provisioned (no local password).
216-
#[serde(default = "default_true")]
157+
#[msgpack(default = "default_true")]
217158
pub is_external: bool,
218159
/// Last synced JWT claims (for claim sync on each request).
219-
#[serde(default)]
160+
#[msgpack(default)]
220161
pub synced_claims: std::collections::HashMap<String, String>,
221162
}
222163

nodedb/src/control/security/catalog/collection_constraints.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,41 @@ use crate::bridge::expr_eval::SqlExpr;
1919

2020
/// Extended field definition supporting DEFAULT, VALUE, ASSERT, and TYPE constraints.
2121
#[derive(Debug, Clone, Serialize, Deserialize, ToMessagePack, FromMessagePack)]
22+
#[msgpack(map)]
2223
pub struct FieldDefinition {
2324
pub name: String,
2425
/// Type constraint: "int", "float", "string", etc. Empty = any.
2526
#[serde(default)]
27+
#[msgpack(default)]
2628
pub field_type: String,
2729
/// Default expression (evaluated when field is missing on insert).
2830
#[serde(default)]
31+
#[msgpack(default)]
2932
pub default_expr: String,
3033
/// Computed value expression (evaluated on every read, not stored).
3134
#[serde(default)]
35+
#[msgpack(default)]
3236
pub value_expr: String,
3337
/// Assertion expression (must evaluate to true for writes to succeed).
3438
#[serde(default)]
39+
#[msgpack(default)]
3540
pub assert_expr: String,
3641
/// Whether the field is read-only (cannot be set by user).
3742
#[serde(default)]
43+
#[msgpack(default)]
3844
pub readonly: bool,
3945
/// Sequence name for auto-generated values on INSERT.
4046
#[serde(default)]
47+
#[msgpack(default)]
4148
pub sequence_name: Option<String>,
4249
/// If true, this field is a stored generated column (materialized on write).
4350
/// `value_expr` contains the serialized SqlExpr for write-time evaluation.
4451
#[serde(default)]
52+
#[msgpack(default)]
4553
pub is_generated: bool,
4654
/// Column names this generated column depends on (for UPDATE recomputation).
4755
#[serde(default)]
56+
#[msgpack(default)]
4857
pub generated_deps: Vec<String>,
4958
}
5059

nodedb/src/control/security/catalog/column_stats.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
//! Column statistics for query optimizer (ANALYZE).
22
3-
use serde::{Deserialize, Serialize};
4-
53
use super::types::{COLUMN_STATS, SystemCatalog, catalog_err};
64

75
/// Per-column statistics collected by ANALYZE.
86
///
97
/// Stored in redb under `_system.column_stats` with key `"{tenant_id}:{collection}:{column}"`.
108
/// Used by DataFusion's cost-based optimizer for cardinality estimation.
11-
#[derive(
12-
Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
13-
)]
9+
#[derive(Debug, Clone, zerompk::ToMessagePack, zerompk::FromMessagePack)]
1410
pub struct StoredColumnStats {
1511
pub tenant_id: u32,
1612
pub collection: String,

nodedb/src/control/security/catalog/dependencies.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,7 @@
66
use super::types::{DEPENDENCIES, SystemCatalog, catalog_err};
77

88
/// A single dependency edge: the source object references the target.
9-
#[derive(
10-
Debug,
11-
Clone,
12-
serde::Serialize,
13-
serde::Deserialize,
14-
zerompk::ToMessagePack,
15-
zerompk::FromMessagePack,
16-
PartialEq,
17-
Eq,
18-
)]
9+
#[derive(Debug, Clone, zerompk::ToMessagePack, zerompk::FromMessagePack, PartialEq, Eq)]
1910
pub struct Dependency {
2011
/// Type of referenced object: "function", "collection".
2112
pub target_type: String,
@@ -24,14 +15,7 @@ pub struct Dependency {
2415
}
2516

2617
/// All dependencies for a source object.
27-
#[derive(
28-
Debug,
29-
Clone,
30-
serde::Serialize,
31-
serde::Deserialize,
32-
zerompk::ToMessagePack,
33-
zerompk::FromMessagePack,
34-
)]
18+
#[derive(Debug, Clone, zerompk::ToMessagePack, zerompk::FromMessagePack)]
3519
pub struct DependencyList {
3620
pub deps: Vec<Dependency>,
3721
}

0 commit comments

Comments
 (0)