magnetar/ext_calckey_model/src/user_model.rs

299 lines
8.3 KiB
Rust

use crate::model_ext::{
AliasSourceExt, AliasSuffixExt, CursorPaginationExt, EntityPrefixExt, MagIden, ModelPagination,
};
use crate::{model_ext::SelectColumnsExt, CalckeyDbError, CalckeyModel};
use chrono::{DateTime, Utc};
use ck::{drive_file, follow_request, following, user, user_profile};
use ext_calckey_model_migration::{IntoIden, SelectStatement};
use magnetar_sdk::types::SpanFilter;
use sea_orm::{
ColumnTrait, DbErr, EntityTrait, FromQueryResult, Iden, JoinType, QueryFilter, QueryResult,
QuerySelect,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserData {
pub user: user::Model,
pub profile: Option<user_profile::Model>,
pub avatar: Option<drive_file::Model>,
pub banner: Option<drive_file::Model>,
}
impl FromQueryResult for UserData {
fn from_query_result(res: &QueryResult, prefix: &str) -> Result<Self, DbErr> {
let prefix = if prefix.is_empty() {
user::Entity.base_prefix()
} else {
MagIden::alias(prefix)
};
Ok(UserData {
user: user::Model::from_query_result(res, &prefix.to_string())?,
profile: user_profile::Model::from_query_result_optional(
res,
&prefix.join_str_as_str(PROFILE),
)?,
avatar: drive_file::Model::from_query_result_optional(
res,
&prefix.join_str_as_str(AVATAR),
)?,
banner: drive_file::Model::from_query_result_optional(
res,
&prefix.join_str_as_str(BANNER),
)?,
})
}
}
impl ModelPagination for UserData {
fn id(&self) -> &str {
&self.user.id
}
fn time(&self) -> DateTime<Utc> {
self.user.created_at.into()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserFollowData {
pub follow: following::Model,
pub user: UserData,
}
impl FromQueryResult for UserFollowData {
fn from_query_result(res: &QueryResult, prefix: &str) -> Result<Self, DbErr> {
Ok(UserFollowData {
user: UserData::from_query_result(res, prefix)?,
follow: following::Model::from_query_result(res, prefix)?,
})
}
}
impl ModelPagination for UserFollowData {
fn id(&self) -> &str {
&self.follow.id
}
fn time(&self) -> DateTime<Utc> {
self.follow.created_at.into()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserFollowRequestData {
pub follow_request: follow_request::Model,
pub user: UserData,
}
impl FromQueryResult for UserFollowRequestData {
fn from_query_result(res: &QueryResult, prefix: &str) -> Result<Self, DbErr> {
Ok(UserFollowRequestData {
user: UserData::from_query_result(res, prefix)?,
follow_request: follow_request::Model::from_query_result(res, prefix)?,
})
}
}
impl ModelPagination for UserFollowRequestData {
fn id(&self) -> &str {
&self.follow_request.id
}
fn time(&self) -> DateTime<Utc> {
self.follow_request.created_at.into()
}
}
#[derive(Clone)]
pub struct UserResolveOptions {
pub with_avatar: bool,
pub with_banner: bool,
pub with_profile: bool,
}
const PROFILE: &str = "profile.";
const AVATAR: &str = "avatar.";
const BANNER: &str = "banner.";
#[derive(Clone)]
pub struct UserResolver {
db: CalckeyModel,
}
impl UserResolver {
pub fn new(db: CalckeyModel) -> Self {
Self { db }
}
pub fn resolve(
&self,
q: &mut SelectStatement,
user_tbl: &MagIden,
UserResolveOptions {
with_avatar,
with_banner,
with_profile,
}: &UserResolveOptions,
) {
q.add_aliased_columns::<user::Entity>(user_tbl);
if *with_profile {
let profile_tbl = user_tbl.join_str(PROFILE);
q.add_aliased_columns::<user_profile::Entity>(&profile_tbl);
q.join_columns(
JoinType::LeftJoin,
user::Relation::UserProfile.with_from_alias(user_tbl),
&profile_tbl,
);
}
if *with_avatar {
let avatar_tbl = user_tbl.join_str(AVATAR);
q.add_aliased_columns::<drive_file::Entity>(&avatar_tbl);
q.join_columns(
JoinType::LeftJoin,
user::Relation::DriveFile2.with_from_alias(user_tbl),
&avatar_tbl,
);
}
if *with_banner {
let banner_tbl = user_tbl.join_str(BANNER);
q.add_aliased_columns::<drive_file::Entity>(&banner_tbl);
q.join_columns(
JoinType::LeftJoin,
user::Relation::DriveFile1.with_from_alias(user_tbl),
&banner_tbl,
);
}
}
pub async fn get_follow_requests(
&self,
options: &UserResolveOptions,
followee: &str,
pagination: &SpanFilter,
prev: &mut Option<SpanFilter>,
next: &mut Option<SpanFilter>,
limit: u64,
) -> Result<Vec<UserData>, CalckeyDbError> {
let user_tbl = user::Entity.base_prefix();
let mut select = follow_request::Entity::find().join_as(
JoinType::InnerJoin,
follow_request::Relation::User1.with_to_alias(&user_tbl),
user_tbl.clone().into_iden(),
);
let query = QuerySelect::query(&mut select);
self.resolve(query, &user_tbl, options);
let followers = select
.filter(follow_request::Column::FolloweeId.eq(followee))
.get_paginated_model::<UserFollowRequestData, _, _>(
&self.db.0,
None,
(
follow_request::Column::CreatedAt,
follow_request::Column::Id,
),
pagination,
prev,
next,
limit,
)
.await?
.into_iter()
.map(|u| u.user)
.collect();
Ok(followers)
}
pub async fn get_followees(
&self,
options: &UserResolveOptions,
follower: &str,
pagination: &SpanFilter,
prev: &mut Option<SpanFilter>,
next: &mut Option<SpanFilter>,
limit: u64,
) -> Result<Vec<UserData>, CalckeyDbError> {
let user_tbl = user::Entity.base_prefix();
let mut select = following::Entity::find().join_as(
JoinType::InnerJoin,
following::Relation::User2.with_to_alias(&user_tbl),
user_tbl.clone().into_iden(),
);
let query = QuerySelect::query(&mut select);
self.resolve(query, &user_tbl, options);
let followers = select
.filter(following::Column::FollowerId.eq(follower))
.get_paginated_model::<UserFollowData, _, _>(
&self.db.0,
None,
(following::Column::CreatedAt, following::Column::Id),
pagination,
prev,
next,
limit,
)
.await?
.into_iter()
.map(|u| u.user)
.collect();
Ok(followers)
}
pub async fn get_followers(
&self,
options: &UserResolveOptions,
followee: &str,
pagination: &SpanFilter,
prev: &mut Option<SpanFilter>,
next: &mut Option<SpanFilter>,
limit: u64,
) -> Result<Vec<UserData>, CalckeyDbError> {
let user_tbl = user::Entity.base_prefix();
let mut select = following::Entity::find().join_as(
JoinType::InnerJoin,
following::Relation::User1.with_to_alias(&user_tbl),
user_tbl.clone().into_iden(),
);
let query = QuerySelect::query(&mut select);
self.resolve(query, &user_tbl, options);
let followers = select
.filter(following::Column::FolloweeId.eq(followee))
.get_paginated_model::<UserFollowData, _, _>(
&self.db.0,
None,
(following::Column::CreatedAt, following::Column::Id),
pagination,
prev,
next,
limit,
)
.await?
.into_iter()
.map(|u| u.user)
.collect();
Ok(followers)
}
}