chore: rewritten relation-related queries
This commit is contained in:
parent
9cf461c7c4
commit
934d8ca8ef
5 changed files with 59 additions and 72 deletions
|
@ -1,6 +1,6 @@
|
|||
use std::{collections::BTreeSet, sync::Arc};
|
||||
|
||||
use sea_orm::{DatabaseConnection, DbErr};
|
||||
use sea_orm::{DatabaseConnection, DbErr, QuerySelect, SelectColumns};
|
||||
|
||||
use crate::{config::Config, model};
|
||||
use uriproxy::UriClass;
|
||||
|
@ -52,8 +52,19 @@ impl Context {
|
|||
// TODO maybe we could provide a more descriptive error...
|
||||
let pkey = actor.private_key.as_deref().ok_or_else(|| DbErr::RecordNotFound("application private key".into()))?.to_string();
|
||||
|
||||
let relay_sinks = model::relation::Entity::followers(&actor.id, &db).await?.ok_or_else(|| DbErr::RecordNotFound(actor.id.clone()))?;
|
||||
let relay_sources = model::relation::Entity::following(&actor.id, &db).await?.ok_or_else(|| DbErr::RecordNotFound(actor.id.clone()))?;
|
||||
let relay_sinks = crate::Query::related(None, Some(actor.internal), false)
|
||||
.select_only()
|
||||
.select_column(crate::model::actor::Column::Id)
|
||||
.into_tuple::<String>()
|
||||
.all(&db)
|
||||
.await?;
|
||||
|
||||
let relay_sources = crate::Query::related(Some(actor.internal), None, false)
|
||||
.select_only()
|
||||
.select_column(crate::model::actor::Column::Id)
|
||||
.into_tuple::<String>()
|
||||
.all(&db)
|
||||
.await?;
|
||||
|
||||
let relay = Relays {
|
||||
sources: BTreeSet::from_iter(relay_sources),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use sea_orm::{entity::prelude::*, QuerySelect, SelectColumns};
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "relations")]
|
||||
|
@ -84,66 +84,3 @@ impl Related<super::instance::Entity> for Entity {
|
|||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl Entity {
|
||||
// TODO this is 2 queries!!! can it be optimized down to 1?
|
||||
pub async fn followers(uid: &str, db: &impl ConnectionTrait) -> Result<Option<Vec<String>>, DbErr> {
|
||||
let Some(internal_id) = super::actor::Entity::ap_to_internal(uid, db).await?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let out = Entity::find()
|
||||
.join(
|
||||
sea_orm::JoinType::InnerJoin,
|
||||
Entity::belongs_to(super::actor::Entity)
|
||||
.from(Column::Follower)
|
||||
.to(super::actor::Column::Internal)
|
||||
.into()
|
||||
)
|
||||
.filter(Column::Accept.is_not_null())
|
||||
.filter(Column::Following.eq(internal_id))
|
||||
.select_only()
|
||||
.select_column(super::actor::Column::Id)
|
||||
.into_tuple::<String>()
|
||||
.all(db)
|
||||
.await?;
|
||||
|
||||
Ok(Some(out))
|
||||
}
|
||||
|
||||
// TODO this is 2 queries!!! can it be optimized down to 1?
|
||||
pub async fn following(uid: &str, db: &impl ConnectionTrait) -> Result<Option<Vec<String>>, DbErr> {
|
||||
let Some(internal_id) = super::actor::Entity::ap_to_internal(uid, db).await?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let out = Entity::find()
|
||||
.join(
|
||||
sea_orm::JoinType::InnerJoin,
|
||||
Entity::belongs_to(super::actor::Entity)
|
||||
.from(Column::Following)
|
||||
.to(super::actor::Column::Internal)
|
||||
.into()
|
||||
)
|
||||
.filter(Column::Accept.is_not_null())
|
||||
.filter(Column::Follower.eq(internal_id))
|
||||
.select_only()
|
||||
.select_column(super::actor::Column::Id)
|
||||
.into_tuple::<String>()
|
||||
.all(db)
|
||||
.await?;
|
||||
|
||||
Ok(Some(out))
|
||||
}
|
||||
|
||||
// TODO this is 3 queries!!! can it be optimized down to 1?
|
||||
pub fn is_following(follower: i64, following: i64) -> sea_orm::Selector<sea_orm::SelectGetableTuple<i64>> {
|
||||
Entity::find()
|
||||
.filter(Column::Accept.is_not_null())
|
||||
.filter(Column::Follower.eq(follower))
|
||||
.filter(Column::Following.eq(following))
|
||||
.select_only()
|
||||
.select_column(Column::Internal)
|
||||
.into_tuple::<i64>()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,4 +70,37 @@ impl Query {
|
|||
|
||||
select
|
||||
}
|
||||
|
||||
pub fn related(from: Option<i64>, to: Option<i64>, pending: bool) -> Select<model::relation::Entity> {
|
||||
let mut condition = Condition::all();
|
||||
|
||||
if let Some(from) = from {
|
||||
condition = condition.add(model::relation::Column::Follower.eq(from));
|
||||
}
|
||||
|
||||
if let Some(to) = to {
|
||||
condition = condition.add(model::relation::Column::Following.eq(to));
|
||||
}
|
||||
|
||||
if !pending {
|
||||
condition = condition.add(model::relation::Column::Accept.is_not_null());
|
||||
}
|
||||
|
||||
let mut select = model::relation::Entity::find()
|
||||
.join(
|
||||
sea_orm::JoinType::InnerJoin,
|
||||
model::relation::Entity::belongs_to(model::actor::Entity)
|
||||
.from(model::relation::Column::Follower)
|
||||
.to(model::actor::Column::Internal)
|
||||
.into()
|
||||
)
|
||||
.filter(condition)
|
||||
.select_only();
|
||||
|
||||
for column in model::actor::Column::iter() {
|
||||
select = select.select_column_as(column, format!("{}{}", model::actor::Entity.table_name(), column.to_string()));
|
||||
}
|
||||
|
||||
select
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use apb::target::Addressed;
|
||||
use sea_orm::{ActiveValue::{NotSet, Set}, ConnectionTrait, DbErr, EntityTrait};
|
||||
use sea_orm::{ActiveValue::{NotSet, Set}, ConnectionTrait, DbErr, EntityTrait, QuerySelect, SelectColumns};
|
||||
|
||||
use crate::traits::fetch::Fetcher;
|
||||
|
||||
|
@ -126,9 +126,15 @@ async fn expand_addressing(targets: Vec<String>, tx: &impl ConnectionTrait) -> R
|
|||
// only used for groups anyway??
|
||||
if target.ends_with("/followers") {
|
||||
let target_id = target.replace("/followers", "");
|
||||
let mut followers = crate::model::relation::Entity::followers(&target_id, tx)
|
||||
let target_internal = crate::model::actor::Entity::ap_to_internal(&target_id, tx)
|
||||
.await?
|
||||
.unwrap_or_else(Vec::new);
|
||||
.ok_or_else(|| DbErr::RecordNotFound(target_id.clone()))?;
|
||||
let mut followers = crate::Query::related(None, Some(target_internal), false)
|
||||
.select_only()
|
||||
.select_column(crate::model::actor::Column::Id)
|
||||
.into_tuple::<String>()
|
||||
.all(tx)
|
||||
.await?;
|
||||
if followers.is_empty() { // stuff with zero addressing will never be seen again!!! TODO
|
||||
followers.push(target_id);
|
||||
}
|
||||
|
|
|
@ -43,8 +43,8 @@ pub async fn view(
|
|||
// TODO these two queries are fast because of indexes but still are 2 subqueries for each
|
||||
// user GET, not even parallelized... should maybe add these as joins on the main query? so
|
||||
// that it's one roundtrip only
|
||||
let followed_by_me = model::relation::Entity::is_following(my_id, internal_uid).any(ctx.db()).await?;
|
||||
let following_me = model::relation::Entity::is_following(internal_uid, my_id).any(ctx.db()).await?;
|
||||
let followed_by_me = upub::Query::related(Some(my_id), Some(internal_uid), false).any(ctx.db()).await?;
|
||||
let following_me = upub::Query::related(Some(internal_uid), Some(my_id), false).any(ctx.db()).await?;
|
||||
(Some(followed_by_me), Some(following_me))
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue