use crate::TViewResult;
use crate::catalog::TviewMeta;
use pgrx::datum::DatumWithOid;
use pgrx::prelude::*;
pub fn refresh_bulk(entity: &str, pks: &[i64]) -> TViewResult<()> {
if pks.is_empty() {
return Ok(());
}
crate::metrics::metrics_api::record_view_recomputes(pks.len() as u64);
let meta =
TviewMeta::load_by_entity(entity)?.ok_or_else(|| crate::TViewError::MetadataNotFound {
entity: entity.to_string(),
})?;
let qi_view = crate::utils::qualified_relname_from_oid(meta.view_oid)?;
let qi_tv = crate::utils::qualified_relname_from_oid(meta.tview_oid)?;
let pk_col = format!("pk_{entity}");
let col_names = crate::utils::get_view_columns_by_oid(meta.view_oid)?;
if col_names.is_empty() {
return Ok(());
}
let col_list = super::column_list(&col_names);
let qi_pk = crate::utils::quote_identifier(&pk_col);
let source_sql = format!("SELECT {col_list} FROM {qi_view} WHERE {qi_pk} = ANY($1)");
let conflict = format!(
"ON CONFLICT ({qi_pk}) {}",
super::upsert_conflict_action(&qi_tv, &col_names, &pk_col, None)
);
let delete_sql = format!(
"DELETE FROM {qi_tv} t \
WHERE t.{qi_pk} = ANY($1) \
AND NOT EXISTS (SELECT 1 FROM {qi_view} v WHERE v.{qi_pk} = t.{qi_pk}) \
RETURNING t.{qi_pk}::text, to_jsonb(t.*)->>'id'"
);
let batch = crate::config::batch_size();
for chunk in pks.chunks(batch) {
super::lock_rows(&qi_tv, &pk_col, chunk)?;
super::run_counted_upsert(
entity,
&qi_tv,
&col_list,
&source_sql,
&conflict,
&[unsafe {
DatumWithOid::new(
chunk.to_vec(),
PgOid::BuiltIn(PgBuiltInOids::INT8ARRAYOID).value(),
)
}],
)?;
super::run_journaled_delete(
entity,
&delete_sql,
&[unsafe {
DatumWithOid::new(
chunk.to_vec(),
PgOid::BuiltIn(PgBuiltInOids::INT8ARRAYOID).value(),
)
}],
)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_refresh_bulk_empty() {
assert!(refresh_bulk("test", &[]).is_ok());
}
}