use serde_json::{Map, Value as JsonValue};
use nodedb_types::DatabaseId;
use crate::control::security::identity::AuthenticatedIdentity;
use crate::control::state::SharedState;
use super::super::super::result::{DdlError, DdlResult};
use super::gate::require_tenant_admin;
use super::support::{ddl_err, text_rows};
struct LineageRow {
database_id: DatabaseId,
name: String,
as_of_lsn: u64,
clone_created_at_lsn: u64,
}
pub fn show_database_lineage(
state: &SharedState,
identity: &AuthenticatedIdentity,
name: &str,
) -> Result<Vec<DdlResult>, DdlError> {
require_tenant_admin(identity, "show database lineage")?;
let catalog = state.credentials.catalog();
let start_id = catalog
.get_database_id_by_name(name)
.map_err(|e| ddl_err("XX000", format!("catalog lookup failed: {e}")))?
.ok_or_else(|| ddl_err("3D000", format!("database '{name}' does not exist")))?;
let mut lineage: Vec<LineageRow> = Vec::new();
let mut current_id = start_id;
let max_hops = nodedb_types::MAX_CLONE_DEPTH + 2;
for _ in 0..max_hops {
let desc = catalog
.get_database(current_id)
.map_err(|e| ddl_err("XX000", format!("catalog read failed: {e}")))?
.ok_or_else(|| {
ddl_err(
"XX000",
format!("database id {} descriptor missing", current_id.as_u64()),
)
})?;
let (as_of_lsn, clone_created_at_lsn) = match &desc.parent_clone {
Some(p) => (p.as_of_lsn, desc.created_at_lsn),
None => (0u64, 0u64),
};
lineage.push(LineageRow {
database_id: current_id,
name: desc.name.clone(),
as_of_lsn,
clone_created_at_lsn,
});
match desc.parent_clone {
Some(p) => {
current_id = p.source_db_id;
}
None => break,
}
}
let columns = vec![
"database_id".to_string(),
"name".to_string(),
"as_of_lsn".to_string(),
"clone_created_at_lsn".to_string(),
];
let mut rows: Vec<Map<String, JsonValue>> = Vec::new();
for row in lineage {
let mut m = Map::new();
m.insert(
"database_id".to_string(),
JsonValue::String(row.database_id.as_u64().to_string()),
);
m.insert("name".to_string(), JsonValue::String(row.name));
m.insert(
"as_of_lsn".to_string(),
JsonValue::String(row.as_of_lsn.to_string()),
);
m.insert(
"clone_created_at_lsn".to_string(),
JsonValue::String(row.clone_created_at_lsn.to_string()),
);
rows.push(m);
}
Ok(text_rows(columns, rows))
}