refactor: remove SocialQueryPort — replaced by SocialQuery + FederationAdminQuery
-319 lines. Legacy SocialQueryPort trait, NoopSocialQueryPort, PanicSocialQueryPort all deleted. Federation repos now implement FederationAdminQuery (single method). get_users uses FederationAdminQuery. All other consumers use unified SocialQuery.
This commit is contained in:
@@ -33,7 +33,7 @@ pub type FederationRepos = (
|
||||
std::sync::Arc<dyn FollowRepository>,
|
||||
std::sync::Arc<dyn ActorRepository>,
|
||||
std::sync::Arc<dyn BlocklistRepository>,
|
||||
std::sync::Arc<dyn domain::ports::SocialQueryPort>,
|
||||
std::sync::Arc<dyn domain::ports::FederationAdminQuery>,
|
||||
std::sync::Arc<dyn RemoteReviewRepository>,
|
||||
std::sync::Arc<dyn domain::ports::RemoteWatchlistRepository>,
|
||||
);
|
||||
|
||||
@@ -275,10 +275,4 @@ impl SocialQuery for CompositeSocialAdapter {
|
||||
.map_err(ap_err)?;
|
||||
Ok(actors.into_iter().map(|a| a.url).collect())
|
||||
}
|
||||
|
||||
async fn list_all_followed_remote_actors(
|
||||
&self,
|
||||
) -> Result<Vec<domain::models::RemoteActorInfo>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
use async_trait::async_trait;
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
models::{PendingFollowerInfo, RemoteActorInfo},
|
||||
ports::SocialQueryPort,
|
||||
value_objects::UserId,
|
||||
models::RemoteActorInfo,
|
||||
ports::FederationAdminQuery,
|
||||
};
|
||||
|
||||
use super::PostgresFederationRepository;
|
||||
|
||||
#[async_trait]
|
||||
impl SocialQueryPort for PostgresFederationRepository {
|
||||
async fn get_accepted_following_urls(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
) -> Result<Vec<String>, DomainError> {
|
||||
let user_id_str = user_id.value().to_string();
|
||||
sqlx::query_scalar::<_, String>(
|
||||
"SELECT remote_actor_url FROM ap_following WHERE local_user_id = $1 AND status = 'accepted'",
|
||||
).bind(&user_id_str).fetch_all(&self.pool).await
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))
|
||||
}
|
||||
|
||||
impl FederationAdminQuery for PostgresFederationRepository {
|
||||
async fn list_all_followed_remote_actors(&self) -> Result<Vec<RemoteActorInfo>, DomainError> {
|
||||
let rows = sqlx::query_as::<_, (String, String, Option<String>)>(
|
||||
"SELECT DISTINCT ar.url, ar.handle, ar.display_name FROM ap_remote_actors ar JOIN ap_following f ON f.remote_actor_url = ar.url WHERE f.status = 'accepted'",
|
||||
@@ -34,49 +22,4 @@ impl SocialQueryPort for PostgresFederationRepository {
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn count_following(&self, user_id: &UserId) -> Result<usize, DomainError> {
|
||||
let uid = user_id.value().to_string();
|
||||
let count: i64 = sqlx::query_scalar(
|
||||
"SELECT COUNT(*) FROM ap_following WHERE local_user_id = $1 AND status = 'accepted'",
|
||||
)
|
||||
.bind(&uid)
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))?;
|
||||
Ok(count as usize)
|
||||
}
|
||||
|
||||
async fn count_accepted_followers(&self, user_id: &UserId) -> Result<usize, DomainError> {
|
||||
let uid = user_id.value().to_string();
|
||||
let count: i64 = sqlx::query_scalar(
|
||||
"SELECT COUNT(*) FROM ap_followers WHERE local_user_id = $1 AND status = 'accepted'",
|
||||
)
|
||||
.bind(&uid)
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))?;
|
||||
Ok(count as usize)
|
||||
}
|
||||
|
||||
async fn get_pending_followers(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
) -> Result<Vec<PendingFollowerInfo>, DomainError> {
|
||||
let uid = user_id.value().to_string();
|
||||
let rows = sqlx::query_as::<_, (String, String, Option<String>, Option<String>)>(
|
||||
"SELECT ar.url, ar.handle, ar.display_name, ar.avatar_url FROM ap_followers f JOIN ap_remote_actors ar ON ar.url = f.remote_actor_url WHERE f.local_user_id = $1 AND f.status = 'pending'",
|
||||
).bind(&uid).fetch_all(&self.pool).await.map_err(|e| DomainError::InfrastructureError(e.to_string()))?;
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
.map(
|
||||
|(url, handle, display_name, avatar_url)| PendingFollowerInfo {
|
||||
url,
|
||||
handle,
|
||||
display_name,
|
||||
avatar_url,
|
||||
},
|
||||
)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
use async_trait::async_trait;
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
models::{PendingFollowerInfo, RemoteActorInfo},
|
||||
ports::SocialQueryPort,
|
||||
value_objects::UserId,
|
||||
models::RemoteActorInfo,
|
||||
ports::FederationAdminQuery,
|
||||
};
|
||||
|
||||
use super::SqliteFederationRepository;
|
||||
|
||||
#[async_trait]
|
||||
impl SocialQueryPort for SqliteFederationRepository {
|
||||
async fn get_accepted_following_urls(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
) -> Result<Vec<String>, DomainError> {
|
||||
let user_id_str = user_id.value().to_string();
|
||||
sqlx::query_scalar::<_, String>(
|
||||
"SELECT remote_actor_url FROM ap_following WHERE local_user_id = ? AND status = 'accepted'",
|
||||
).bind(&user_id_str).fetch_all(&self.pool).await
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))
|
||||
}
|
||||
|
||||
impl FederationAdminQuery for SqliteFederationRepository {
|
||||
async fn list_all_followed_remote_actors(&self) -> Result<Vec<RemoteActorInfo>, DomainError> {
|
||||
let rows = sqlx::query_as::<_, (String, String, Option<String>)>(
|
||||
"SELECT DISTINCT ar.url, ar.handle, ar.display_name
|
||||
@@ -40,56 +28,4 @@ impl SocialQueryPort for SqliteFederationRepository {
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn count_following(&self, user_id: &UserId) -> Result<usize, DomainError> {
|
||||
let uid = user_id.value().to_string();
|
||||
let count: i64 = sqlx::query_scalar(
|
||||
"SELECT COUNT(*) FROM ap_following WHERE local_user_id = ? AND status = 'accepted'",
|
||||
)
|
||||
.bind(&uid)
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))?;
|
||||
Ok(count as usize)
|
||||
}
|
||||
|
||||
async fn count_accepted_followers(&self, user_id: &UserId) -> Result<usize, DomainError> {
|
||||
let uid = user_id.value().to_string();
|
||||
let count: i64 = sqlx::query_scalar(
|
||||
"SELECT COUNT(*) FROM ap_followers WHERE local_user_id = ? AND status = 'accepted'",
|
||||
)
|
||||
.bind(&uid)
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))?;
|
||||
Ok(count as usize)
|
||||
}
|
||||
|
||||
async fn get_pending_followers(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
) -> Result<Vec<PendingFollowerInfo>, DomainError> {
|
||||
let uid = user_id.value().to_string();
|
||||
let rows = sqlx::query_as::<_, (String, String, Option<String>, Option<String>)>(
|
||||
"SELECT ar.url, ar.handle, ar.display_name, ar.avatar_url
|
||||
FROM ap_followers f
|
||||
JOIN ap_remote_actors ar ON ar.url = f.remote_actor_url
|
||||
WHERE f.local_user_id = ? AND f.status = 'pending'",
|
||||
)
|
||||
.bind(&uid)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(|e| DomainError::InfrastructureError(e.to_string()))?;
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
.map(
|
||||
|(url, handle, display_name, avatar_url)| PendingFollowerInfo {
|
||||
url,
|
||||
handle,
|
||||
display_name,
|
||||
avatar_url,
|
||||
},
|
||||
)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use chrono::Utc;
|
||||
use domain::ports::SocialQueryPort;
|
||||
use domain::ports::FederationAdminQuery;
|
||||
use k_ap::ActorRepository;
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
@@ -79,30 +79,6 @@ async fn setup_db(pool: &SqlitePool) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_accepted_following_urls_returns_only_accepted() {
|
||||
let pool = SqlitePool::connect(":memory:").await.unwrap();
|
||||
setup_db(&pool).await;
|
||||
let repo = SqliteFederationRepository::new(pool.clone());
|
||||
let user_id = uuid::Uuid::new_v4();
|
||||
|
||||
sqlx::query(
|
||||
"INSERT INTO ap_following (local_user_id, remote_actor_url, follow_activity_id, status)
|
||||
VALUES (?, 'https://other.social/users/alice', 'act1', 'accepted'),
|
||||
(?, 'https://other.social/users/bob', 'act2', 'pending')",
|
||||
)
|
||||
.bind(user_id.to_string())
|
||||
.bind(user_id.to_string())
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let uid = domain::value_objects::UserId::from_uuid(user_id);
|
||||
let urls = repo.get_accepted_following_urls(&uid).await.unwrap();
|
||||
assert_eq!(urls.len(), 1);
|
||||
assert_eq!(urls[0], "https://other.social/users/alice");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_all_followed_remote_actors_deduplicates() {
|
||||
let pool = SqlitePool::connect(":memory:").await.unwrap();
|
||||
|
||||
Reference in New Issue
Block a user