diff --git a/crates/buzz-db/src/event.rs b/crates/buzz-db/src/event.rs index 27a616c618f..b09265a4478 100644 --- a/crates/buzz-db/src/event.rs +++ b/crates/buzz-db/src/event.rs @@ -1687,6 +1687,27 @@ impl Db { Ok(result) } + /// Backfill `d_tag` for existing NIP-33 events (kind 30000–39999) that have `d_tag IS NULL`. + /// + /// Idempotent — safe to call on every startup. No-ops when all rows are already populated. + /// Runs a single UPDATE touching only NIP-33 rows with NULL d_tag. + #[datastore_span(name = "backfill_d_tags", system = "postgresql")] + pub async fn backfill_d_tags(&self) -> Result { + let result = sqlx::query( + "UPDATE events \ + SET d_tag = COALESCE( \ + (SELECT elem->>1 FROM jsonb_array_elements(tags) AS elem \ + WHERE elem->>0 = 'd' LIMIT 1), \ + '' \ + ) \ + WHERE kind BETWEEN 30000 AND 39999 AND d_tag IS NULL \ + AND community_write_allowed(community_id)", + ) + .execute(&self.pool) + .await?; + Ok(result.rows_affected()) + } + /// Soft-delete NIP-29 discovery events for a channel created by a specific relay pubkey. #[datastore_span(name = "soft_delete_discovery_events", system = "postgresql")] pub async fn soft_delete_discovery_events( diff --git a/crates/buzz-db/src/lib.rs b/crates/buzz-db/src/lib.rs index 36ec2870e97..cb7bb8f8af3 100644 --- a/crates/buzz-db/src/lib.rs +++ b/crates/buzz-db/src/lib.rs @@ -1138,33 +1138,6 @@ impl Db { } } } - - /// Ensures monthly partitions exist for the next N months. - #[datastore_span(name = "ensure_future_partitions", system = "postgresql")] - pub async fn ensure_future_partitions(&self, months_ahead: u32) -> Result<()> { - partition::ensure_future_partitions(&self.pool, months_ahead).await - } - - /// Backfill `d_tag` for existing NIP-33 events (kind 30000–39999) that have `d_tag IS NULL`. - /// - /// Idempotent — safe to call on every startup. No-ops when all rows are already populated. - /// Runs a single UPDATE touching only NIP-33 rows with NULL d_tag. - #[datastore_span(name = "backfill_d_tags", system = "postgresql")] - pub async fn backfill_d_tags(&self) -> Result { - let result = sqlx::query( - "UPDATE events \ - SET d_tag = COALESCE( \ - (SELECT elem->>1 FROM jsonb_array_elements(tags) AS elem \ - WHERE elem->>0 = 'd' LIMIT 1), \ - '' \ - ) \ - WHERE kind BETWEEN 30000 AND 39999 AND d_tag IS NULL \ - AND community_write_allowed(community_id)", - ) - .execute(&self.pool) - .await?; - Ok(result.rows_affected()) - } } #[cfg(test)] diff --git a/crates/buzz-db/src/partition.rs b/crates/buzz-db/src/partition.rs index b3803f1b34c..ba252f71f4a 100644 --- a/crates/buzz-db/src/partition.rs +++ b/crates/buzz-db/src/partition.rs @@ -2,11 +2,13 @@ //! //! Call `ensure_future_partitions` on startup and monthly via cron. +use buzz_datastore_tracing::datastore_span; use chrono::{Datelike, TimeZone, Utc}; use sqlx::{PgPool, Row}; use tracing::info; use crate::error::{DbError, Result}; +use crate::Db; /// Tables that may be partition-managed. Allowlist prevents DDL injection. const PARTITIONED_TABLES: &[&str] = &["events", "delivery_log"]; @@ -55,6 +57,14 @@ pub async fn ensure_future_partitions(pool: &PgPool, months_ahead: u32) -> Resul Ok(()) } +impl Db { + /// Ensures monthly partitions exist for the next N months. + #[datastore_span(name = "ensure_future_partitions", system = "postgresql")] + pub async fn ensure_future_partitions(&self, months_ahead: u32) -> Result<()> { + ensure_future_partitions(&self.pool, months_ahead).await + } +} + /// Validate that a partition suffix is digits and underscores only. fn validate_partition_suffix(suffix: &str) -> bool { !suffix.is_empty() && suffix.chars().all(|c| c.is_ascii_digit() || c == '_')