use super::*;
pub(crate) const PROJECTION_CHANGE_NOTIFY_TABLE: &str = "projection_changes";
pub(crate) async fn reject_causal_table_writes_in_tx<DB>(
tx: &mut Transaction<'_, DB>,
tables: &BTreeSet<String>,
) -> Result<(), TableStoreError>
where
DB: SqlxRepoBackend,
for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,
DB::Arguments: IntoArguments<DB>,
for<'q> &'q str: Encode<'q, DB> + Type<DB>,
{
lock_projection_table_ownership_fences_in_tx(tx, tables).await?;
for table in tables {
let mut builder = QueryBuilder::<DB>::new(
"SELECT table_name FROM projection_causal_tables WHERE table_name = ",
);
builder.push_bind(table.as_str());
builder.push(" LIMIT 1");
let row = builder
.build()
.fetch_optional(&mut **tx)
.await
.map_err(|error| {
crate::sqlx_repo::read_model_storage_error(
DB::BACKEND,
"check causal projection ownership",
error,
)
})?;
if row.is_some() {
return Err(TableStoreError::CausalWriteRequired {
table: table.clone(),
});
}
}
Ok(())
}
pub(super) async fn lock_projection_table_ownership_fences_in_tx<DB>(
tx: &mut Transaction<'_, DB>,
tables: &BTreeSet<String>,
) -> Result<(), TableStoreError>
where
DB: SqlxRepoBackend,
for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,
DB::Arguments: IntoArguments<DB>,
for<'q> &'q str: Encode<'q, DB> + Type<DB>,
{
for table in tables {
let mut insert = QueryBuilder::<DB>::new(
"INSERT INTO projection_table_ownership_fences (table_name) VALUES (",
);
insert.push_bind(table.as_str());
insert.push(") ON CONFLICT (table_name) DO NOTHING");
insert.build().execute(&mut **tx).await.map_err(|error| {
crate::sqlx_repo::read_model_storage_error(
DB::BACKEND,
"acquire causal projection ownership fence",
error,
)
})?;
let mut lock = QueryBuilder::<DB>::new(
"SELECT table_name FROM projection_table_ownership_fences WHERE table_name = ",
);
lock.push_bind(table.as_str());
if DB::BACKEND == "postgres" {
lock.push(" FOR UPDATE");
}
if lock
.build()
.fetch_optional(&mut **tx)
.await
.map_err(|error| {
crate::sqlx_repo::read_model_storage_error(
DB::BACKEND,
"lock causal projection ownership fence",
error,
)
})?
.is_none()
{
return Err(TableStoreError::Storage(format!(
"{} causal projection ownership fence `{table}` disappeared",
DB::BACKEND
)));
}
}
Ok(())
}