use sqlx::PgConnection;
use super::{SOURCE_DEFINITIONS, SourceDefinition};
use crate::Result;
#[derive(Debug, Clone, sqlx::FromRow)]
pub struct SnapshotPage {
pub last_key: Option<String>,
pub fetched: i64,
pub written: i64,
}
pub async fn lock_sources(connection: &mut PgConnection) -> Result<()> {
let tables = SOURCE_DEFINITIONS
.iter()
.map(|definition| definition.table)
.collect::<Vec<_>>()
.join(", ");
sqlx::query(sqlx::AssertSqlSafe(format!(
"LOCK TABLE {tables} IN SHARE MODE"
)))
.execute(connection)
.await?;
Ok(())
}
pub async fn write_snapshot_page(
connection: &mut PgConnection,
definition: &SourceDefinition,
after: Option<&str>,
limit: i64,
) -> Result<SnapshotPage> {
let assignments = definition
.columns
.iter()
.filter(|column| **column != definition.key)
.map(|column| format!("{column} = EXCLUDED.{column}"))
.collect::<Vec<_>>()
.join(", ");
let sql = format!(
"WITH page AS (
SELECT entity_key, row FROM {view}
WHERE $1::text IS NULL OR entity_key > $1
ORDER BY entity_key LIMIT $2
), written AS (
INSERT INTO {target}
SELECT populated.* FROM page
CROSS JOIN LATERAL jsonb_populate_record(NULL::{target}, page.row) AS populated
WHERE reporting_row_retained($3, page.row)
ON CONFLICT ({key}) DO UPDATE SET {assignments}
RETURNING 1
)
SELECT MAX(entity_key) AS last_key, COUNT(*) AS fetched,
(SELECT COUNT(*) FROM written) AS written
FROM page",
view = definition.view,
target = definition.target,
key = definition.key,
);
Ok(sqlx::query_as(sqlx::AssertSqlSafe(sql))
.bind(after)
.bind(limit)
.bind(definition.table)
.fetch_one(connection)
.await?)
}