fix(pi): restore catalog and takeover authority boundaries

This commit is contained in:
SaladDay
2026-08-03 00:38:29 +00:00
parent 26447effa2
commit 9d0e75d56a
10 changed files with 925 additions and 96 deletions
+76
View File
@@ -13,9 +13,85 @@ use super::providers::delete_provider_on_tx;
use crate::database::{lock_conn, Database};
use crate::error::AppError;
use crate::provider::{ProviderAggregate, ProviderMutationInput};
use indexmap::IndexMap;
use rusqlite::params;
impl Database {
pub(crate) fn restore_pi_catalog_snapshot(
&self,
aggregates: &IndexMap<String, ProviderAggregate>,
projections: &[PiProviderProjection],
current_provider: Option<&str>,
) -> Result<(), AppError> {
let mut conn = lock_conn!(self.conn);
let tx = conn
.transaction()
.map_err(|error| AppError::Database(error.to_string()))?;
tx.execute("DELETE FROM pi_provider_projections", [])
.map_err(|error| AppError::Database(error.to_string()))?;
let current_ids = {
let mut statement = tx
.prepare("SELECT id FROM providers WHERE app_type = 'pi'")
.map_err(|error| AppError::Database(error.to_string()))?;
let ids = statement
.query_map([], |row| row.get::<_, String>(0))
.map_err(|error| AppError::Database(error.to_string()))?
.collect::<Result<Vec<_>, _>>()
.map_err(|error| AppError::Database(error.to_string()))?;
ids
};
for provider_id in current_ids
.iter()
.filter(|provider_id| !aggregates.contains_key(provider_id.as_str()))
{
// Only rows created after the snapshot are removed. Updating
// providers which existed in the snapshot preserves dependent
// provider_health history instead of triggering ON DELETE CASCADE.
delete_provider_on_tx(&tx, "pi", provider_id)?;
}
for aggregate in aggregates.values() {
let key = ProviderKey::new("pi", aggregate.provider.id.clone())?;
let mut input = provider_mutation_input(aggregate);
if let Some(meta) = input.meta.as_mut() {
meta.custom_endpoints.clear();
}
let row = ProviderRowUpdate::from_input(&input)?;
let endpoints = aggregate
.endpoints
.values()
.cloned()
.map(NewEndpoint::try_from)
.collect::<Result<Vec<_>, _>>()?;
restore_provider_aggregate_on_tx(
&tx,
&key,
&row,
aggregate.provider.created_at,
aggregate.provider.sort_index,
current_provider == Some(key.id()),
aggregate.provider.in_failover_queue,
&endpoints,
)?;
}
for projection in projections {
tx.execute(
"INSERT INTO pi_provider_projections
(provider_id, provider_key, created_at, updated_at)
VALUES (?1, ?2, ?3, ?4)",
params![
projection.provider_id,
projection.provider_key,
projection.created_at,
projection.updated_at
],
)
.map_err(|error| AppError::Database(error.to_string()))?;
}
tx.commit()
.map_err(|error| AppError::Database(error.to_string()))
}
pub(crate) fn create_pi_catalog_provider(
&self,
input: NewProviderAggregate,
+3
View File
@@ -94,6 +94,9 @@ impl Database {
let transaction = conn
.transaction()
.map_err(|error| AppError::Database(error.to_string()))?;
transaction
.execute("DELETE FROM prompts WHERE app_type = ?1", [app_type])
.map_err(|error| AppError::Database(error.to_string()))?;
{
let mut statement = transaction
.prepare(