use tokio_postgres::Client;
use crate::executor::ApplyError;
pub async fn compute_target_identity(client: &Client) -> Result<String, ApplyError> {
let row = client
.query_one(
"SELECT
current_database(),
inet_server_addr()::text,
inet_server_port(),
current_setting('cluster_name', true),
(SELECT system_identifier::text FROM pg_control_system())",
&[],
)
.await?;
let mut h = blake3::Hasher::new();
h.update(b"pgevolve-target-id-v1\n");
for i in 0..5 {
let s: Option<String> = row.try_get(i).ok();
if let Some(v) = s {
h.update(v.as_bytes());
}
h.update(&[0]);
}
let full = hex::encode(h.finalize().as_bytes());
Ok(full[..16].to_string())
}
pub async fn compute_cluster_target_identity(client: &Client) -> Result<String, ApplyError> {
let row = client
.query_one(
"SELECT system_identifier::text FROM pg_control_system()",
&[],
)
.await?;
let s: String = row.try_get(0)?;
let n: u64 = s
.parse()
.map_err(|_| ApplyError::Internal(format!("unparseable system_identifier: {s}")))?;
Ok(format_cluster_identity(n))
}
fn format_cluster_identity(system_identifier: u64) -> String {
format!("cluster:{system_identifier:016x}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cluster_identity_format() {
let id = format_cluster_identity(12345u64);
assert_eq!(id, "cluster:0000000000003039");
}
#[test]
fn cluster_identity_max_value() {
let id = format_cluster_identity(u64::MAX);
assert_eq!(id, "cluster:ffffffffffffffff");
}
#[test]
fn cluster_identity_zero() {
let id = format_cluster_identity(0);
assert_eq!(id, "cluster:0000000000000000");
}
}