Refactored aliases
ci/woodpecker/push/ociImagePush Pipeline is running Details

This commit is contained in:
Natty 2024-01-08 20:15:51 +01:00
parent 3b1eab8069
commit a658452138
Signed by: natty
GPG Key ID: BF6CB659ADEE60EC
8 changed files with 352 additions and 269 deletions

View File

@ -15,11 +15,10 @@ use chrono::Utc;
use ext_calckey_model_migration::{Migrator, MigratorTrait};
use futures_util::StreamExt;
use redis::IntoConnectionInfo;
use sea_orm::sea_query::IntoIden;
use sea_orm::ActiveValue::Set;
use sea_orm::{
ColumnTrait, ConnectOptions, DatabaseConnection, DbErr, EntityTrait, QueryFilter, RelationDef,
RelationTrait, TransactionTrait,
ColumnTrait, ConnectOptions, DatabaseConnection, DbErr, EntityTrait, QueryFilter,
TransactionTrait,
};
use serde::{Deserialize, Serialize};
use std::future::Future;
@ -44,18 +43,6 @@ pub enum CalckeyDbError {
DbError(#[from] DbErr),
}
trait AliasSourceExt {
fn with_alias<I: IntoIden>(&self, alias: I) -> RelationDef;
}
impl<T: RelationTrait> AliasSourceExt for T {
fn with_alias<I: IntoIden>(&self, alias: I) -> RelationDef {
let mut def = self.def();
def.from_tbl = def.from_tbl.alias(alias);
def
}
}
impl CalckeyModel {
pub async fn new(config: ConnectorConfig) -> Result<Self, CalckeyDbError> {
let opt = ConnectOptions::new(config.url)

View File

@ -1,21 +1,70 @@
use ext_calckey_model_migration::{Alias, Expr, IntoIden, SelectExpr, SelectStatement, TableRef};
use sea_orm::{ColumnTrait, Condition, EntityTrait, Iden, Iterable, JoinType, RelationDef};
use ext_calckey_model_migration::{
Alias, Expr, IntoIden, Quote, SelectExpr, SelectStatement, TableRef,
};
use sea_orm::{
ColumnTrait, Condition, DynIden, EntityTrait, Iden, Iterable, JoinType, RelationDef,
RelationTrait,
};
use std::fmt::Write;
#[derive(Clone)]
pub enum MagIden {
DynIden(DynIden),
Alias(Alias),
}
impl MagIden {
pub fn alias(alias: &str) -> MagIden {
Self::Alias(Alias::new(alias))
}
}
impl From<DynIden> for MagIden {
fn from(value: DynIden) -> Self {
Self::DynIden(value)
}
}
impl Iden for MagIden {
fn prepare(&self, s: &mut dyn Write, q: Quote) {
match self {
MagIden::DynIden(di) => di.prepare(s, q),
MagIden::Alias(a) => a.prepare(s, q),
}
}
fn quoted(&self, q: Quote) -> String {
match self {
MagIden::DynIden(di) => di.quoted(q),
MagIden::Alias(a) => a.quoted(q),
}
}
fn to_string(&self) -> String {
match self {
MagIden::DynIden(di) => di.to_string(),
MagIden::Alias(a) => a.to_string(),
}
}
fn unquoted(&self, s: &mut dyn Write) {
match self {
MagIden::DynIden(di) => di.unquoted(s),
MagIden::Alias(a) => a.unquoted(s),
}
}
}
pub(crate) trait SelectColumnsExt {
fn add_aliased_columns<T: EntityTrait>(&mut self, alias: &str) -> &mut Self;
fn add_aliased_columns<T: EntityTrait>(&mut self, alias: &MagIden) -> &mut Self;
fn join_columns<I: IntoIden>(
fn join_columns(&mut self, join: JoinType, rel: RelationDef, alias: &MagIden) -> &mut Self;
fn join_columns_on(
&mut self,
join: JoinType,
rel: RelationDef,
alias: I,
) -> &mut Self;
fn join_columns_on<I: IntoIden>(
&mut self,
join: JoinType,
rel: RelationDef,
alias: I,
alias: &MagIden,
condition: Condition,
) -> &mut Self;
}
@ -41,17 +90,15 @@ pub(crate) fn join_columns_default(rel: RelationDef) -> Condition {
}
impl SelectColumnsExt for SelectStatement {
fn add_aliased_columns<T: EntityTrait>(&mut self, iden: &str) -> &mut Self {
fn add_aliased_columns<T: EntityTrait>(&mut self, iden: &MagIden) -> &mut Self {
for col in T::Column::iter() {
let column: &T::Column = &col;
let alias = format!("{}{}", iden, col.to_string());
let column_ref = Expr::col((Alias::new(iden), column.as_column_ref().1));
let alias = iden.join(&col);
let column_ref = iden.col(column.as_column_ref().1);
self.expr(SelectExpr {
expr: col.select_as(column_ref),
alias: Some(Alias::new(&alias).into_iden()),
alias: Some(alias.into_iden()),
window: None,
});
}
@ -59,48 +106,66 @@ impl SelectColumnsExt for SelectStatement {
self
}
fn join_columns<I: IntoIden>(
&mut self,
join: JoinType,
mut rel: RelationDef,
alias: I,
) -> &mut Self {
let alias = alias.into_iden();
rel.to_tbl = rel.to_tbl.alias(alias);
fn join_columns(&mut self, join: JoinType, mut rel: RelationDef, alias: &MagIden) -> &mut Self {
rel.to_tbl = rel.to_tbl.alias(alias.clone().into_iden());
self.join(join, rel.to_tbl.clone(), join_columns_default(rel));
self
}
fn join_columns_on<I: IntoIden>(
fn join_columns_on(
&mut self,
join: JoinType,
mut rel: RelationDef,
alias: I,
alias: &MagIden,
condition: Condition,
) -> &mut Self {
let alias = alias.into_iden();
rel.to_tbl = rel.to_tbl.alias(alias);
rel.to_tbl = rel.to_tbl.alias(alias.clone().into_iden());
self.join(join, rel.to_tbl.clone(), condition);
self
}
}
pub(crate) fn joined_prefix_str(prefix: &str, suffix: &str) -> String {
format!("{prefix}{suffix}")
pub trait AliasColumnExt {
fn col(&self, col: impl IntoIden) -> Expr;
}
pub(crate) fn joined_prefix_alias(prefix: &str, suffix: &str) -> Alias {
Alias::new(joined_prefix_str(prefix, suffix))
impl<T: Iden + ?Sized> AliasColumnExt for T {
fn col(&self, col: impl IntoIden) -> Expr {
Expr::col((Alias::new(self.to_string()).into_iden(), col.into_iden()))
}
}
pub(crate) fn joined_prefix(prefix: &str, suffix: &str) -> impl IntoIden {
joined_prefix_alias(prefix, suffix).into_iden()
pub trait AliasSuffixExt {
fn join(&self, suffix: &dyn Iden) -> MagIden;
fn join_str(&self, suffix: &str) -> MagIden;
fn join_as_str(&self, suffix: &dyn Iden) -> String;
fn join_str_as_str(&self, suffix: &str) -> String;
}
impl<T: Iden + ?Sized> AliasSuffixExt for T {
fn join(&self, suffix: &dyn Iden) -> MagIden {
MagIden::alias(&self.join_as_str(suffix))
}
fn join_str(&self, suffix: &str) -> MagIden {
MagIden::alias(&self.join_str_as_str(suffix))
}
fn join_as_str(&self, suffix: &dyn Iden) -> String {
format!("{}{}", self.to_string(), suffix.to_string())
}
fn join_str_as_str(&self, suffix: &str) -> String {
format!("{}{}", self.to_string(), suffix)
}
}
pub(crate) trait EntityPrefixExt {
fn base_prefix_str(&self) -> String;
fn base_prefix_alias(&self) -> Alias;
fn base_prefix(&self) -> impl IntoIden;
fn base_prefix(&self) -> MagIden;
}
impl<T: EntityTrait> EntityPrefixExt for T {
@ -108,11 +173,28 @@ impl<T: EntityTrait> EntityPrefixExt for T {
format!("{}.", self.table_name())
}
fn base_prefix_alias(&self) -> Alias {
Alias::new(self.base_prefix_str())
}
fn base_prefix(&self) -> impl IntoIden {
self.base_prefix_alias().into_iden()
fn base_prefix(&self) -> MagIden {
MagIden::alias(&self.base_prefix_str())
}
}
pub trait AliasSourceExt {
fn with_from_alias(&self, alias: &MagIden) -> RelationDef;
fn with_alias(&self, from: &MagIden, to: &MagIden) -> RelationDef;
}
impl<T: RelationTrait> AliasSourceExt for T {
fn with_from_alias(&self, alias: &MagIden) -> RelationDef {
let mut def = self.def();
def.from_tbl = def.from_tbl.alias(Alias::new(alias.clone().to_string()));
def
}
fn with_alias(&self, from: &MagIden, to: &MagIden) -> RelationDef {
let mut def = self.def();
def.from_tbl = def.from_tbl.alias(from.clone().into_iden());
def.to_tbl = def.to_tbl.alias(to.clone().into_iden());
def
}
}

View File

@ -0,0 +1,76 @@
use crate::model_ext::{AliasSuffixExt, EntityPrefixExt, MagIden};
use crate::note_model::{INTERACTION_REACTION, INTERACTION_RENOTE, RENOTE, REPLY, USER};
use crate::user_model::UserData;
use ck::note;
use ext_calckey_model_migration::IntoIden;
use sea_orm::sea_query::Alias;
use sea_orm::Iden;
use sea_orm::{DbErr, FromQueryResult, QueryResult};
use serde::{Deserialize, Serialize};
pub mod sub_interaction_renote {
use sea_orm::{DeriveColumn, EnumIter, FromQueryResult};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, FromQueryResult, Serialize, Deserialize)]
pub struct Model {
pub renotes: Option<i64>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Renotes,
}
}
pub mod sub_interaction_reaction {
use sea_orm::{DeriveColumn, EnumIter, FromQueryResult};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, FromQueryResult, Serialize, Deserialize)]
pub struct Model {
pub reaction_name: Option<String>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
ReactionName,
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NoteData {
pub note: note::Model,
pub interaction_user_renote: Option<sub_interaction_renote::Model>,
pub interaction_user_reaction: Option<sub_interaction_reaction::Model>,
pub user: UserData,
pub reply: Option<Box<NoteData>>,
pub renote: Option<Box<NoteData>>,
}
impl FromQueryResult for NoteData {
fn from_query_result(res: &QueryResult, prefix: &str) -> Result<Self, DbErr> {
let prefix = if prefix.is_empty() {
note::Entity.base_prefix()
} else {
MagIden::alias(&prefix)
};
Ok(NoteData {
note: note::Model::from_query_result(res, &prefix.to_string())?,
interaction_user_renote: sub_interaction_renote::Model::from_query_result_optional(
res,
&prefix.join_str_as_str(INTERACTION_RENOTE),
)?,
interaction_user_reaction: sub_interaction_reaction::Model::from_query_result_optional(
res,
&prefix.join_str_as_str(INTERACTION_REACTION),
)?,
user: UserData::from_query_result(res, &prefix.join_str_as_str(USER))?,
reply: NoteData::from_query_result_optional(res, &prefix.join_str_as_str(REPLY))?
.map(Box::new),
renote: NoteData::from_query_result_optional(res, &prefix.join_str_as_str(RENOTE))?
.map(Box::new),
})
}
}

View File

@ -1,61 +1,23 @@
pub mod data;
use ext_calckey_model_migration::SelectStatement;
use sea_orm::sea_query::{Alias, Asterisk, Expr, IntoIden, Query, SelectExpr, SimpleExpr};
use sea_orm::sea_query::{Asterisk, Expr, IntoIden, Query, SelectExpr, SimpleExpr};
use sea_orm::{
Condition, DbErr, EntityName, EntityTrait, FromQueryResult, Iden, JoinType, QueryFilter,
QueryOrder, QueryResult, QuerySelect, QueryTrait, Select,
Condition, CursorTrait, EntityName, EntityTrait, Iden, JoinType, QueryFilter, QueryOrder,
QuerySelect, QueryTrait, Select,
};
use serde::{Deserialize, Serialize};
use ck::{note, note_reaction, user, user_note_pining};
use data::{sub_interaction_reaction, sub_interaction_renote, NoteData};
use magnetar_sdk::types::SpanFilter;
use crate::model_ext::{
join_columns_default, joined_prefix, joined_prefix_alias, joined_prefix_str, EntityPrefixExt,
join_columns_default, AliasColumnExt, AliasSourceExt, AliasSuffixExt, EntityPrefixExt, MagIden,
SelectColumnsExt,
};
use crate::paginated::PaginatedModel;
use crate::user_model::{UserData, UserResolver};
use crate::{AliasSourceExt, CalckeyDbError, CalckeyModel};
pub mod sub_interaction_renote {
use sea_orm::{DeriveColumn, EnumIter, FromQueryResult};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, FromQueryResult, Serialize, Deserialize)]
pub struct Model {
pub renotes: Option<i64>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Renotes,
}
}
pub mod sub_interaction_reaction {
use sea_orm::{DeriveColumn, EnumIter, FromQueryResult};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, FromQueryResult, Serialize, Deserialize)]
pub struct Model {
pub reaction_name: Option<String>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
ReactionName,
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NoteData {
pub note: note::Model,
pub interaction_user_renote: Option<sub_interaction_renote::Model>,
pub interaction_user_reaction: Option<sub_interaction_reaction::Model>,
pub user: UserData,
pub reply: Option<Box<NoteData>>,
pub renote: Option<Box<NoteData>>,
}
use crate::user_model::{UserResolveOptions, UserResolver};
use crate::{CalckeyDbError, CalckeyModel};
const PIN: &str = "pin.";
const INTERACTION_REACTION: &str = "interaction.reaction.";
@ -64,37 +26,13 @@ const USER: &str = "user.";
const REPLY: &str = "reply.";
const RENOTE: &str = "renote.";
impl FromQueryResult for NoteData {
fn from_query_result(res: &QueryResult, prefix: &str) -> Result<Self, DbErr> {
let fallback = format!("{}.", note::Entity.table_name());
let prefix = if prefix.is_empty() { &fallback } else { prefix };
Ok(NoteData {
note: note::Model::from_query_result(res, prefix)?,
interaction_user_renote: sub_interaction_renote::Model::from_query_result_optional(
res,
&joined_prefix_str(prefix, INTERACTION_RENOTE),
)?,
interaction_user_reaction: sub_interaction_reaction::Model::from_query_result_optional(
res,
&joined_prefix_str(prefix, INTERACTION_REACTION),
)?,
user: UserData::from_query_result(res, &joined_prefix_str(prefix, USER))?,
reply: NoteData::from_query_result_optional(res, &joined_prefix_str(prefix, REPLY))?
.map(Box::new),
renote: NoteData::from_query_result_optional(res, &joined_prefix_str(prefix, RENOTE))?
.map(Box::new),
})
}
}
pub struct NoteResolver {
db: CalckeyModel,
user_resolver: UserResolver,
}
pub trait NoteVisibilityFilterFactory: Send + Sync {
fn with_note_and_user_tables(&self, note: Option<Alias>) -> SimpleExpr;
fn with_note_and_user_tables(&self, note: &dyn Iden) -> SimpleExpr;
}
pub struct NoteResolveOptions {
@ -102,45 +40,39 @@ pub struct NoteResolveOptions {
pub visibility_filter: Box<dyn NoteVisibilityFilterFactory>,
pub time_range: Option<SpanFilter>,
pub limit: Option<u64>,
pub with_user: bool,
pub with_reply_target: bool,
pub with_renote_target: bool,
pub with_interactions_from: Option<String>, // User ID
pub only_pins_from: Option<String>, // User ID
pub user_options: UserResolveOptions,
}
trait SelectNoteInteractionsExt {
fn add_sub_select_interaction_reaction(
&mut self,
source_note_alias: &str,
alias: &str,
note_tbl: &MagIden,
user_id: &str,
) -> &mut Self;
fn add_sub_select_interaction_renote(
&mut self,
source_note_alias: &str,
alias: &str,
user_id: &str,
) -> &mut Self;
fn add_sub_select_interaction_renote(&mut self, note_tbl: &MagIden, user_id: &str)
-> &mut Self;
}
impl SelectNoteInteractionsExt for SelectStatement {
fn add_sub_select_interaction_reaction(
&mut self,
iden: &str,
prefix_alias: &str,
note_tbl: &MagIden,
user_id: &str,
) -> &mut Self {
let note_id_col = Expr::col((Alias::new(iden), note::Column::Id));
let column = sub_interaction_reaction::Column::ReactionName;
let alias = format!("{}{}", prefix_alias, column.to_string());
let note_id_col = note_tbl.col(note::Column::Id);
let alias = note_tbl
.join_str(INTERACTION_REACTION)
.join(&sub_interaction_reaction::Column::ReactionName);
let sub_query = Query::select()
.expr(SelectExpr {
expr: Expr::col(note_reaction::Column::Reaction).into(),
alias: Some(Alias::new(alias).into_iden()),
alias: Some(alias.into_iden()),
window: None,
})
.from(note_reaction::Entity)
@ -155,28 +87,26 @@ impl SelectNoteInteractionsExt for SelectStatement {
fn add_sub_select_interaction_renote(
&mut self,
iden: &str,
prefix_alias: &str,
note_tbl: &MagIden,
user_id: &str,
) -> &mut Self {
let note_id_col = Expr::col((Alias::new(iden), note::Column::Id));
let renote_note_tbl = joined_prefix_alias(prefix_alias, "note");
let column = sub_interaction_renote::Column::Renotes;
let alias = format!("{}{}", prefix_alias, column.to_string());
let interaction_tbl_prefix = note_tbl.join_str(INTERACTION_RENOTE);
let renote_note_tbl = interaction_tbl_prefix.join_str("note");
let alias = interaction_tbl_prefix.join(&sub_interaction_renote::Column::Renotes);
let sub_query = Query::select()
.expr(SelectExpr {
expr: Expr::count(Expr::col(Asterisk)),
alias: Some(Alias::new(alias).into_iden()),
alias: Some(alias.into_iden()),
window: None,
})
.from_as(note::Entity, renote_note_tbl.clone())
.from_as(note::Entity, renote_note_tbl.clone().into_iden())
.cond_where(
Expr::col((renote_note_tbl.clone(), note::Column::RenoteId)).eq(note_id_col),
renote_note_tbl
.col(note::Column::RenoteId)
.eq(note_tbl.col(note::Column::Id)),
)
.and_where(Expr::col((renote_note_tbl.clone(), note::Column::UserId)).eq(user_id))
.and_where(renote_note_tbl.col(note::Column::UserId).eq(user_id))
.take()
.into_sub_query_statement();
@ -186,7 +116,7 @@ impl SelectNoteInteractionsExt for SelectStatement {
}
fn ids_into_expr(ids: &Vec<String>) -> SimpleExpr {
let id_col = Expr::col((note::Entity.base_prefix(), note::Column::Id));
let id_col = note::Entity.base_prefix().col(note::Column::Id);
if ids.len() == 1 {
id_col.eq(&ids[0])
@ -207,11 +137,11 @@ impl NoteResolver {
let select = self.resolve(options);
let visibility_filter = options
.visibility_filter
.with_note_and_user_tables(Some(note::Entity.base_prefix_alias()));
.with_note_and_user_tables(&note::Entity.base_prefix());
let time_filter = options
.time_range
.as_ref()
.and_then(note::Model::range_into_expr);
.and_then(note::Entity::range_into_expr);
let id_filter = options.ids.as_ref().map(ids_into_expr);
let notes = select
@ -232,11 +162,11 @@ impl NoteResolver {
let select = self.resolve(options);
let visibility_filter = options
.visibility_filter
.with_note_and_user_tables(Some(note::Entity.base_prefix_alias()));
.with_note_and_user_tables(&note::Entity.base_prefix());
let time_filter = options
.time_range
.as_ref()
.and_then(note::Model::range_into_expr);
.and_then(note::Entity::range_into_expr);
let id_filter = options.ids.as_ref().map(ids_into_expr);
let notes = select
@ -245,7 +175,7 @@ impl NoteResolver {
.apply_if(time_filter, Select::<note::Entity>::filter)
.apply_if(options.only_pins_from.as_deref(), |s, _| {
s.order_by_desc(Expr::col((
joined_prefix(&note::Entity.base_prefix_str(), PIN),
note::Entity.base_prefix().into_iden().join_str(PIN),
user_note_pining::Column::CreatedAt,
)))
})
@ -257,59 +187,70 @@ impl NoteResolver {
Ok(notes)
}
/*
pub async fn get_children(&self, options: &NoteResolveOptions) -> Select<note::Entity> {
let max_breadth: usize = 10;
let nth_child = Alias::new("nth_child");
let mut select = Query::select();
select.distinct();
select.columns([Alias::new("id")]);
select.from(cte);
select.and_where(Expr::col(nth_child).lt(max_breadth))
}
*/
fn attach_note(
&self,
q: &mut SelectStatement,
prefix: &str,
note_tbl: &MagIden,
reply_depth: usize,
renote_depth: usize,
options: &NoteResolveOptions,
user_resolver: &UserResolver,
) {
q.add_aliased_columns::<note::Entity>(prefix);
q.add_aliased_columns::<note::Entity>(note_tbl);
// Add the note's author
q.add_aliased_columns::<user::Entity>(&joined_prefix_str(prefix, USER));
let user_tbl = note_tbl.join_str(USER);
q.add_aliased_columns::<user::Entity>(&user_tbl);
q.join_columns(
JoinType::LeftJoin,
note::Relation::User.with_alias(Alias::new(prefix).into_iden()),
joined_prefix(prefix, USER),
note::Relation::User.with_from_alias(note_tbl),
&user_tbl,
);
// user_resolver.resolve(q, &user_tbl, &options.user_options);
// Interactions like renotes or reactions from the specified user
if let Some(user_id) = &options.with_interactions_from {
q.add_sub_select_interaction_reaction(
prefix,
&joined_prefix_str(prefix, INTERACTION_REACTION),
user_id,
);
q.add_sub_select_interaction_renote(
prefix,
&joined_prefix_str(prefix, INTERACTION_RENOTE),
user_id,
);
q.add_sub_select_interaction_reaction(note_tbl, user_id);
q.add_sub_select_interaction_renote(note_tbl, user_id);
}
// Recursively attach reply parents
if reply_depth > 0 {
let reply_tbl = note_tbl.join_str(REPLY);
let visibility_filter = options
.visibility_filter
.with_note_and_user_tables(Some(joined_prefix_alias(prefix, REPLY)));
let mut rel = note::Relation::SelfRef2.with_alias(Alias::new(prefix).into_iden());
rel.to_tbl = rel.to_tbl.alias(joined_prefix_alias(prefix, REPLY));
.with_note_and_user_tables(&reply_tbl);
let condition = Condition::all()
.add(join_columns_default(rel))
.add(join_columns_default(
note::Relation::SelfRef2.with_alias(note_tbl, &reply_tbl),
))
.add(visibility_filter);
q.join_columns_on(
JoinType::LeftJoin,
note::Relation::SelfRef2.with_alias(Alias::new(prefix).into_iden()),
joined_prefix(prefix, REPLY),
note::Relation::SelfRef2.with_from_alias(note_tbl),
&reply_tbl,
condition,
);
self.attach_note(
q,
&joined_prefix_str(prefix, REPLY),
&reply_tbl,
reply_depth - 1,
renote_depth,
options,
@ -319,24 +260,25 @@ impl NoteResolver {
// Recursively attach renote/quote targets
if renote_depth > 0 {
let renote_tbl = note_tbl.join_str(RENOTE);
let visibility_filter = options
.visibility_filter
.with_note_and_user_tables(Some(joined_prefix_alias(prefix, RENOTE)));
let mut rel = note::Relation::SelfRef1.with_alias(Alias::new(prefix).into_iden());
rel.to_tbl = rel.to_tbl.alias(joined_prefix_alias(prefix, RENOTE));
.with_note_and_user_tables(&renote_tbl);
let condition = Condition::all()
.add(join_columns_default(rel))
.add(join_columns_default(
note::Relation::SelfRef1.with_alias(note_tbl, &renote_tbl),
))
.add(visibility_filter);
q.join_columns_on(
JoinType::LeftJoin,
note::Relation::SelfRef1.with_alias(Alias::new(prefix).into_iden()),
joined_prefix(prefix, RENOTE),
note::Relation::SelfRef1.with_from_alias(note_tbl),
&renote_tbl,
condition,
);
self.attach_note(
q,
&joined_prefix_str(prefix, RENOTE),
&renote_tbl,
reply_depth,
renote_depth - 1,
options,
@ -346,30 +288,24 @@ impl NoteResolver {
}
pub fn resolve(&self, options: &NoteResolveOptions) -> Select<note::Entity> {
let prefix = note::Entity.base_prefix_str();
let note_tbl = note::Entity.base_prefix();
let mut select = Query::select();
select.from_as(note::Entity, Alias::new(&prefix));
select.from_as(note::Entity, note_tbl.clone().into_iden());
if let Some(pins_user) = &options.only_pins_from {
select
.join_columns(
JoinType::InnerJoin,
note::Relation::UserNotePining.with_alias(Alias::new(&prefix)),
joined_prefix(&prefix, PIN),
note::Relation::UserNotePining.with_from_alias(&note_tbl),
&note_tbl.join_str(PIN),
)
.and_where(
Expr::col((
joined_prefix(&prefix, PIN),
user_note_pining::Column::UserId,
))
.eq(pins_user),
);
.and_where(note_tbl.col(user_note_pining::Column::UserId).eq(pins_user));
}
self.attach_note(
&mut select,
&prefix,
&note_tbl,
options.with_reply_target.then_some(1).unwrap_or_default(),
options.with_renote_target.then_some(1).unwrap_or_default(),
options,

View File

@ -54,7 +54,7 @@ pub trait PaginatedModel: 'static {
}
}
impl PaginatedModel for ck::note::Model {
impl PaginatedModel for ck::note::Entity {
fn time_column() -> impl Iden {
ck::note::Column::CreatedAt
}
@ -64,7 +64,7 @@ impl PaginatedModel for ck::note::Model {
}
}
impl PaginatedModel for ck::user::Model {
impl PaginatedModel for ck::user::Entity {
fn time_column() -> impl Iden {
ck::user::Column::CreatedAt
}
@ -74,7 +74,7 @@ impl PaginatedModel for ck::user::Model {
}
}
impl PaginatedModel for ck::following::Model {
impl PaginatedModel for ck::following::Entity {
fn time_column() -> impl Iden {
ck::following::Column::CreatedAt
}
@ -84,7 +84,7 @@ impl PaginatedModel for ck::following::Model {
}
}
impl PaginatedModel for ck::follow_request::Model {
impl PaginatedModel for ck::follow_request::Entity {
fn time_column() -> impl Iden {
ck::follow_request::Column::CreatedAt
}

View File

@ -1,11 +1,9 @@
use crate::model_ext::EntityPrefixExt;
use crate::{
model_ext::{joined_prefix, joined_prefix_str, SelectColumnsExt},
AliasSourceExt, CalckeyModel,
};
use ck::{drive_file, follow_request, following, user};
use ext_calckey_model_migration::{Alias, SelectStatement};
use sea_orm::{DbErr, FromQueryResult, JoinType, QueryResult};
use crate::model_ext::{AliasSourceExt, AliasSuffixExt, EntityPrefixExt, MagIden};
use crate::{model_ext::SelectColumnsExt, CalckeyModel};
use ck::{drive_file, user};
use ext_calckey_model_migration::{IntoIden, SelectStatement};
use sea_orm::sea_query::Alias;
use sea_orm::{DbErr, FromQueryResult, Iden, JoinType, QueryResult};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -24,18 +22,21 @@ const BANNER: &str = "banner.";
impl FromQueryResult for UserData {
fn from_query_result(res: &QueryResult, prefix: &str) -> Result<Self, DbErr> {
let fallback = user::Entity.base_prefix_str();
let prefix = if prefix.is_empty() { &fallback } else { prefix };
let prefix = if prefix.is_empty() {
user::Entity.base_prefix()
} else {
MagIden::alias(prefix)
};
Ok(UserData {
user: user::Model::from_query_result(res, prefix)?,
user: user::Model::from_query_result(res, &prefix.to_string())?,
avatar: drive_file::Model::from_query_result_optional(
res,
&joined_prefix_str(prefix, AVATAR),
&prefix.join_str_as_str(AVATAR),
)?,
banner: drive_file::Model::from_query_result_optional(
res,
&joined_prefix_str(prefix, BANNER),
&prefix.join_str_as_str(BANNER),
)?,
})
}
@ -53,26 +54,29 @@ impl UserResolver {
pub fn resolve(
&self,
q: &mut SelectStatement,
prefix: &str,
user_tbl: &MagIden,
UserResolveOptions {
with_avatar_and_banner,
}: &UserResolveOptions,
) {
q.add_aliased_columns::<user::Entity>(prefix);
q.add_aliased_columns::<user::Entity>(user_tbl);
if *with_avatar_and_banner {
q.add_aliased_columns::<drive_file::Entity>(&joined_prefix_str(prefix, AVATAR))
.add_aliased_columns::<drive_file::Entity>(&joined_prefix_str(prefix, BANNER));
let avatar_tbl = user_tbl.join_str(AVATAR);
let banner_tbl = user_tbl.join_str(BANNER);
q.add_aliased_columns::<drive_file::Entity>(&avatar_tbl)
.add_aliased_columns::<drive_file::Entity>(&banner_tbl);
q.join_columns(
JoinType::LeftJoin,
user::Relation::DriveFile2.with_alias(Alias::new(prefix)),
joined_prefix(prefix, AVATAR),
user::Relation::DriveFile2.with_from_alias(user_tbl),
&avatar_tbl,
)
.join_columns(
JoinType::LeftJoin,
user::Relation::DriveFile1.with_alias(Alias::new(prefix)),
joined_prefix(prefix, BANNER),
user::Relation::DriveFile1.with_from_alias(user_tbl),
&banner_tbl,
);
}
}

View File

@ -1,8 +1,7 @@
use magnetar_calckey_model::ck;
use magnetar_calckey_model::note_model::sub_interaction_renote;
use magnetar_calckey_model::note_model::data::sub_interaction_renote;
use magnetar_sdk::types::note::{
NoteDetailExt, NoteSelfContextExt, PackNoteMaybeAttachments, PackNoteMaybeFull, PackPollBase,
ReactionPair,
NoteDetailExt, NoteSelfContextExt, PackNoteMaybeFull, PackPollBase, ReactionPair,
};
use magnetar_sdk::types::user::PackUserBase;
use magnetar_sdk::types::{

View File

@ -12,14 +12,15 @@ use futures_util::future::{try_join_all, BoxFuture};
use futures_util::{FutureExt, StreamExt, TryFutureExt, TryStreamExt};
use magnetar_calckey_model::ck::sea_orm_active_enums::NoteVisibilityEnum;
use magnetar_calckey_model::emoji::EmojiTag;
use magnetar_calckey_model::note_model::{
sub_interaction_reaction, sub_interaction_renote, NoteData, NoteResolveOptions,
NoteVisibilityFilterFactory,
use magnetar_calckey_model::model_ext::AliasColumnExt;
use magnetar_calckey_model::note_model::data::{
sub_interaction_reaction, sub_interaction_renote, NoteData,
};
use magnetar_calckey_model::note_model::{NoteResolveOptions, NoteVisibilityFilterFactory};
use magnetar_calckey_model::poll::PollResolver;
use magnetar_calckey_model::sea_orm::prelude::Expr;
use magnetar_calckey_model::sea_orm::sea_query::{Alias, IntoIden, PgFunc, Query, SimpleExpr};
use magnetar_calckey_model::sea_orm::{ActiveEnum, ColumnTrait, IntoSimpleExpr};
use magnetar_calckey_model::sea_orm::sea_query::{IntoIden, PgFunc, Query, SimpleExpr};
use magnetar_calckey_model::sea_orm::{ActiveEnum, ColumnTrait, Iden, IntoSimpleExpr};
use magnetar_calckey_model::user_model::UserResolveOptions;
use magnetar_calckey_model::{ck, CalckeyDbError};
use magnetar_common::util::{parse_reaction, RawReaction};
use magnetar_sdk::mmm::Token;
@ -43,22 +44,12 @@ use super::user::UserShapedData;
pub struct NoteVisibilityFilterSimple(Option<String>);
impl NoteVisibilityFilterFactory for NoteVisibilityFilterSimple {
fn with_note_and_user_tables(&self, note_tbl: Option<Alias>) -> SimpleExpr {
let note_tbl_name =
note_tbl.map_or_else(|| ck::note::Entity.into_iden(), |a| a.into_iden());
let note_visibility = Expr::col((note_tbl_name.clone(), ck::note::Column::Visibility));
let note_mentions = Expr::col((note_tbl_name.clone(), ck::note::Column::Mentions));
let note_reply_user_id = Expr::col((note_tbl_name.clone(), ck::note::Column::ReplyUserId));
let note_visible_user_ids =
Expr::col((note_tbl_name.clone(), ck::note::Column::VisibleUserIds));
let note_user_id = Expr::col((note_tbl_name, ck::note::Column::UserId));
let is_public = note_visibility
.clone()
fn with_note_and_user_tables(&self, note_tbl: &dyn Iden) -> SimpleExpr {
let is_public = note_tbl
.col(ck::note::Column::Visibility)
.eq(NoteVisibilityEnum::Public.as_enum())
.or(note_visibility
.clone()
.or(note_tbl
.col(ck::note::Column::Visibility)
.eq(NoteVisibilityEnum::Home.as_enum()));
let Some(user_id_str) = &self.0 else {
@ -67,30 +58,34 @@ impl NoteVisibilityFilterFactory for NoteVisibilityFilterSimple {
let self_user_id = SimpleExpr::Constant(user_id_str.into());
let is_self = note_user_id.clone().eq(self_user_id.clone());
let is_self = note_tbl
.col(ck::note::Column::UserId)
.eq(self_user_id.clone());
let is_visible_specified = {
let either_specified_or_followers = note_visibility
.clone()
let either_specified_or_followers = note_tbl
.col(ck::note::Column::Visibility)
.eq(NoteVisibilityEnum::Specified.as_enum())
.or(note_visibility
.clone()
.eq(NoteVisibilityEnum::Followers.as_enum()))
.into_simple_expr();
.or(note_tbl
.col(ck::note::Column::Visibility)
.eq(NoteVisibilityEnum::Followers.as_enum()));
let mentioned_or_specified = self_user_id
.clone()
.eq(PgFunc::any(note_mentions.into_simple_expr()))
.or(self_user_id.eq(PgFunc::any(note_visible_user_ids)));
.eq(PgFunc::any(
note_tbl.col(ck::note::Column::Mentions).into_simple_expr(),
))
.or(self_user_id.eq(PgFunc::any(note_tbl.col(ck::note::Column::VisibleUserIds))));
either_specified_or_followers.and(mentioned_or_specified)
};
let is_visible_followers = {
note_visibility
note_tbl
.col(ck::note::Column::Visibility)
.eq(NoteVisibilityEnum::Followers.as_enum())
.and(
note_user_id.in_subquery(
note_tbl.col(ck::note::Column::UserId).in_subquery(
Query::select()
.column(ck::following::Column::FolloweeId)
.from(ck::following::Entity)
@ -98,7 +93,7 @@ impl NoteVisibilityFilterFactory for NoteVisibilityFilterSimple {
.to_owned(),
),
)
.or(note_reply_user_id.eq(user_id_str))
.or(note_tbl.col(ck::note::Column::ReplyUserId).eq(user_id_str))
};
is_self
@ -584,7 +579,9 @@ impl NoteModel {
)),
time_range: None,
limit: None,
with_user: self.with_context,
user_options: UserResolveOptions {
with_avatar_and_banner: self.with_context,
},
with_reply_target: self.with_context,
with_renote_target: self.with_context,
with_interactions_from: self
@ -620,7 +617,9 @@ impl NoteModel {
)),
time_range: None,
limit: None,
with_user: self.with_context,
user_options: UserResolveOptions {
with_avatar_and_banner: self.with_context,
},
with_reply_target: self.with_context,
with_renote_target: self.with_context,
with_interactions_from: self