use crate::TViewResult;
pub(crate) fn owned_time_dependent() -> TViewResult<Vec<std::rc::Rc<crate::catalog::TviewMeta>>> {
let entities = crate::catalog::queries::owned_time_dependent()?;
let mut metas = Vec::new();
for entity in entities {
if let Some(meta) = crate::catalog::TviewMeta::load_by_entity(&entity)? {
metas.push(meta);
}
}
Ok(metas)
}
pub(crate) fn refresh_time_dependent(
chosen: &[std::rc::Rc<crate::catalog::TviewMeta>],
) -> TViewResult<Vec<String>> {
let order = crate::cache::graph()?.topo_order;
let mut chosen: Vec<&crate::catalog::TviewMeta> =
chosen.iter().map(std::rc::Rc::as_ref).collect();
chosen.sort_by_key(|meta| {
order
.iter()
.position(|e| *e == meta.entity_name)
.unwrap_or(usize::MAX)
});
let mut refreshed = Vec::new();
for meta in chosen {
if crate::suspend::is_suspended() {
crate::suspend::record_change(&meta.entity_name);
} else {
crate::queue::enqueue_refresh_all(&meta.entity_name);
}
refreshed.push(crate::utils::qualified_relname_from_oid(meta.tview_oid)?);
}
crate::flush::flush_refresh_queue()?;
Ok(refreshed)
}
pub fn rebuild_with_dependents(entities: &[String]) -> TViewResult<Vec<String>> {
let graph = crate::cache::graph()?;
let mut readers: std::collections::HashMap<&str, Vec<&str>> = std::collections::HashMap::new();
for (reader, read) in &graph.children {
for entity in read {
readers.entry(entity).or_default().push(reader);
}
}
let mut order: Vec<String> = Vec::new();
let mut pending: std::collections::VecDeque<&str> =
entities.iter().map(String::as_str).collect();
while let Some(entity) = pending.pop_front() {
if order.iter().any(|e| e == entity) {
continue;
}
pending.extend(readers.get(entity).into_iter().flatten());
order.push(entity.to_string());
}
order.sort_by_key(|e| {
graph
.topo_order
.iter()
.position(|t| t == e)
.unwrap_or(usize::MAX)
});
for entity in &order {
crate::refresh::full::rebuild_one(entity)?;
}
flush_after_rebuilds()?;
Ok(order)
}
pub fn flush_after_rebuilds() -> TViewResult<()> {
crate::flush::flush_refresh_queue()
}
pub(crate) fn ensure_propagation_indexes(
metas: &[std::rc::Rc<crate::catalog::TviewMeta>],
dry_run: bool,
) -> TViewResult<Vec<String>> {
let mut missing = Vec::new();
for meta in metas {
let key = &meta.identity.column;
let mut lookups = meta.plan.lookup_columns();
lookups.remove(key.as_str());
if lookups.is_empty() {
continue;
}
let (schema, table) = crate::ddl::relation_name(meta.tview_oid)?;
let mut recorded = Vec::new();
for column in lookups {
let index = crate::ddl::create::ManagedIndex::propagation(&table, column, key);
let indexed = crate::utils::spi::one::<bool>(
"SELECT EXISTS (SELECT 1 FROM pg_catalog.pg_index i \
JOIN pg_catalog.pg_attribute a \
ON a.attrelid = i.indrelid AND a.attnum = i.indkey[0] \
WHERE i.indrelid = $1 AND a.attname = $2)",
&[
crate::utils::spi::oid(meta.tview_oid),
crate::utils::spi::text(column),
],
)?;
if indexed != Some(true) {
missing.push(index.ddl(&schema, &table));
if !dry_run {
recorded.extend(index.create(&schema, &table)?);
}
} else if !dry_run && index.exists_on(meta.tview_oid)? {
recorded.push(index.name);
}
}
if !recorded.is_empty() {
crate::catalog::indexes::record(meta.tview_oid, &recorded)?;
}
}
Ok(missing)
}
pub fn refresh_all_in_dependency_order() -> TViewResult<Vec<String>> {
let graph = crate::cache::graph()?;
for entity in &graph.topo_order {
crate::refresh::full::rebuild_one(entity)?;
}
flush_after_rebuilds()?;
Ok(graph.topo_order)
}
pub(crate) fn cascade_path(entity: &str) -> TViewResult<Vec<(i32, String, String)>> {
const MAX_DEPTH: i32 = 10;
let graph = crate::cache::graph()?;
let mut rows = vec![(0, entity.to_string(), entity.to_string())];
let mut frontier = vec![vec![entity.to_string()]];
for depth in 1..=MAX_DEPTH {
let mut next = Vec::new();
for path in frontier {
let Some(node) = path.last() else { continue };
let mut embedding: Vec<&String> =
graph.parents.get(node).into_iter().flatten().collect();
embedding.sort();
embedding.dedup();
for parent in embedding.into_iter().filter(|p| !path.contains(p)) {
rows.push((depth, parent.clone(), node.clone()));
let mut longer = path.clone();
longer.push(parent.clone());
next.push(longer);
}
}
frontier = next;
}
rows.sort();
Ok(rows)
}