Files
tranquil-pds/crates/tranquil-db/src/postgres/backlink.rs
T
2026-07-25 08:27:39 +03:00

102 lines
2.9 KiB
Rust

use async_trait::async_trait;
use sqlx::PgPool;
use tranquil_db_traits::{Backlink, BacklinkRepository, DbError};
use tranquil_types::{AtUri, Nsid};
use uuid::Uuid;
use super::col;
use super::column_vec;
use super::user::map_sqlx_error;
pub struct PostgresBacklinkRepository {
pool: PgPool,
}
impl PostgresBacklinkRepository {
pub fn new(pool: PgPool) -> Self {
Self { pool }
}
}
#[async_trait]
impl BacklinkRepository for PostgresBacklinkRepository {
async fn get_backlink_conflicts(
&self,
repo_id: Uuid,
collection: &Nsid,
backlinks: &[Backlink],
) -> Result<Vec<AtUri>, DbError> {
if backlinks.is_empty() {
return Ok(Vec::new());
}
let paths: Vec<&str> = backlinks.iter().map(|b| b.path.as_str()).collect();
let link_tos: Vec<&str> = backlinks.iter().map(|b| b.link_to.as_str()).collect();
let collection_pattern = format!("%/{}/%", collection.as_str());
let results = sqlx::query_scalar!(
r#"
SELECT DISTINCT uri
FROM backlinks
WHERE repo_id = $1
AND uri LIKE $4
AND (path, link_to) IN (SELECT unnest($2::text[]), unnest($3::text[]))
"#,
repo_id,
&paths as &[&str],
&link_tos as &[&str],
collection_pattern
)
.fetch_all(&self.pool)
.await
.map_err(map_sqlx_error)?;
column_vec(results, col::BACKLINKS_URI)
}
async fn add_backlinks(&self, repo_id: Uuid, backlinks: &[Backlink]) -> Result<(), DbError> {
if backlinks.is_empty() {
return Ok(());
}
let uris: Vec<&str> = backlinks.iter().map(|b| b.uri.as_str()).collect();
let paths: Vec<&str> = backlinks.iter().map(|b| b.path.as_str()).collect();
let link_tos: Vec<&str> = backlinks.iter().map(|b| b.link_to.as_str()).collect();
sqlx::query!(
r#"
INSERT INTO backlinks (uri, path, link_to, repo_id)
SELECT unnest($1::text[]), unnest($2::text[]), unnest($3::text[]), $4
ON CONFLICT (uri, path) DO NOTHING
"#,
&uris as &[&str],
&paths as &[&str],
&link_tos as &[&str],
repo_id
)
.execute(&self.pool)
.await
.map_err(map_sqlx_error)?;
Ok(())
}
async fn remove_backlinks_by_uri(&self, uri: &AtUri) -> Result<(), DbError> {
sqlx::query!("DELETE FROM backlinks WHERE uri = $1", uri.as_str())
.execute(&self.pool)
.await
.map_err(map_sqlx_error)?;
Ok(())
}
async fn remove_backlinks_by_repo(&self, repo_id: Uuid) -> Result<(), DbError> {
sqlx::query!("DELETE FROM backlinks WHERE repo_id = $1", repo_id)
.execute(&self.pool)
.await
.map_err(map_sqlx_error)?;
Ok(())
}
}