Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/buzz-db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ tracing = { workspace = true }
thiserror = { workspace = true }
nostr = { workspace = true }
rand = { workspace = true }
metrics = { workspace = true }

[dev-dependencies]
tokio = { workspace = true }
13 changes: 12 additions & 1 deletion crates/buzz-db/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,17 @@ pub async fn insert_event(
/// Uses `QueryBuilder` for dynamic filter composition — avoids string concatenation
/// while keeping all user values in bind parameters.
pub async fn query_events(pool: &PgPool, q: &EventQuery) -> Result<Vec<StoredEvent>> {
let mut conn = pool.acquire().await?;
query_events_on(&mut conn, q).await
}

/// [`query_events`] on a specific session — the replica-routing path runs
/// follow-up (aux) queries on the exact reader connection whose heartbeat
/// observation proved coverage for the page they annotate.
pub(crate) async fn query_events_on(
conn: &mut sqlx::PgConnection,
q: &EventQuery,
) -> Result<Vec<StoredEvent>> {
// Composite cursor requires both halves.
if q.before_id.is_some() && q.until.is_none() {
return Err(DbError::InvalidData(
Expand Down Expand Up @@ -538,7 +549,7 @@ pub async fn query_events(pool: &PgPool, q: &EventQuery) -> Result<Vec<StoredEve
qb.push_bind(limit_val);
qb.push(" OFFSET ").push_bind(offset_val);

let rows = qb.build().fetch_all(pool).await?;
let rows = qb.build().fetch_all(&mut *conn).await?;

let mut out = Vec::with_capacity(rows.len());
for row in rows {
Expand Down
1,008 changes: 957 additions & 51 deletions crates/buzz-db/src/lib.rs

Large diffs are not rendered by default.

19 changes: 17 additions & 2 deletions crates/buzz-db/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ mod tests {
"push_gateway_delivery_auth_replays",
"push_gateway_delivery_request_replays",
"product_feedback",
"replica_heartbeat",
] {
if normalized[insert_pos..].contains(&format!("'{value}'")) {
globals.insert(value.to_owned());
Expand Down Expand Up @@ -560,7 +561,7 @@ mod tests {
let mut migrations: Vec<_> = MIGRATOR.iter().collect();
migrations.sort_by_key(|migration| migration.version);

assert_eq!(migrations.len(), 25);
assert_eq!(migrations.len(), 26);
assert_eq!(migrations[0].version, 1);
assert_eq!(&*migrations[0].description, "initial schema");
assert!(migrations[0]
Expand Down Expand Up @@ -904,6 +905,20 @@ mod tests {
desired_schema.contains("CREATE TABLE join_policy_acceptances"),
"desired-state schema must include join-policy evidence used by invite claims",
);

// Replica heartbeat (this branch, renumbered to 0026 after
// 0025_relay_invites landed on main): the fence's portable read-side
// observation. A single CHECK'd row makes the token update the
// serialization point (multi-pod commit ordering), and the epoch
// column is what detects token resets — both are load-bearing for
// the routing proof.
assert_eq!(migrations[25].version, 26);
let heartbeat = migrations[25].sql.as_str();
assert!(heartbeat.contains("CREATE TABLE replica_heartbeat"));
assert!(heartbeat.contains("CHECK (id = 1)"));
assert!(heartbeat.contains("epoch"));
assert!(heartbeat.contains("INSERT INTO replica_heartbeat (id) VALUES (1)"));
assert!(heartbeat.contains("_operator_global_tables"));
}

#[test]
Expand Down Expand Up @@ -1146,7 +1161,7 @@ mod tests {
run_migrations(&pool)
.await
.expect("retry succeeds after operator repair");
assert_eq!(applied_versions(&pool).await.last().copied(), Some(25));
assert_eq!(applied_versions(&pool).await.last().copied(), Some(26));
}

#[tokio::test]
Expand Down
Loading
Loading