From a658452138b7839133e4bfda93de813966c029ef Mon Sep 17 00:00:00 2001 From: Natty Date: Mon, 8 Jan 2024 20:15:51 +0100 Subject: [PATCH] Refactored aliases --- ext_calckey_model/src/lib.rs | 17 +- ext_calckey_model/src/model_ext.rs | 170 +++++++++---- ext_calckey_model/src/note_model/data.rs | 76 ++++++ .../src/{note_model.rs => note_model/mod.rs} | 230 +++++++----------- ext_calckey_model/src/paginated.rs | 8 +- ext_calckey_model/src/user_model.rs | 46 ++-- src/model/data/note.rs | 5 +- src/model/processing/note.rs | 69 +++--- 8 files changed, 352 insertions(+), 269 deletions(-) create mode 100644 ext_calckey_model/src/note_model/data.rs rename ext_calckey_model/src/{note_model.rs => note_model/mod.rs} (50%) diff --git a/ext_calckey_model/src/lib.rs b/ext_calckey_model/src/lib.rs index b8f267d..46845c8 100644 --- a/ext_calckey_model/src/lib.rs +++ b/ext_calckey_model/src/lib.rs @@ -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(&self, alias: I) -> RelationDef; -} - -impl AliasSourceExt for T { - fn with_alias(&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 { let opt = ConnectOptions::new(config.url) diff --git a/ext_calckey_model/src/model_ext.rs b/ext_calckey_model/src/model_ext.rs index 5a9cd30..50d6b65 100644 --- a/ext_calckey_model/src/model_ext.rs +++ b/ext_calckey_model/src/model_ext.rs @@ -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 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(&mut self, alias: &str) -> &mut Self; + fn add_aliased_columns(&mut self, alias: &MagIden) -> &mut Self; - fn join_columns( + 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( - &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(&mut self, iden: &str) -> &mut Self { + fn add_aliased_columns(&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( - &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( + 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 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 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 EntityPrefixExt for T { @@ -108,11 +173,28 @@ impl 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 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 } } diff --git a/ext_calckey_model/src/note_model/data.rs b/ext_calckey_model/src/note_model/data.rs new file mode 100644 index 0000000..5e47596 --- /dev/null +++ b/ext_calckey_model/src/note_model/data.rs @@ -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, + } + + #[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, + } + + #[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, + pub interaction_user_reaction: Option, + pub user: UserData, + pub reply: Option>, + pub renote: Option>, +} + +impl FromQueryResult for NoteData { + fn from_query_result(res: &QueryResult, prefix: &str) -> Result { + 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), + }) + } +} diff --git a/ext_calckey_model/src/note_model.rs b/ext_calckey_model/src/note_model/mod.rs similarity index 50% rename from ext_calckey_model/src/note_model.rs rename to ext_calckey_model/src/note_model/mod.rs index 8829ca7..0ba0c14 100644 --- a/ext_calckey_model/src/note_model.rs +++ b/ext_calckey_model/src/note_model/mod.rs @@ -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, - } - - #[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, - } - - #[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, - pub interaction_user_reaction: Option, - pub user: UserData, - pub reply: Option>, - pub renote: Option>, -} +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 { - 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) -> 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, pub time_range: Option, pub limit: Option, - pub with_user: bool, pub with_reply_target: bool, pub with_renote_target: bool, pub with_interactions_from: Option, // User ID pub only_pins_from: Option, // 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) -> 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(¬e::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(¬e::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::::filter) .apply_if(options.only_pins_from.as_deref(), |s, _| { s.order_by_desc(Expr::col(( - joined_prefix(¬e::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 { + 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::(prefix); + q.add_aliased_columns::(note_tbl); // Add the note's author - q.add_aliased_columns::(&joined_prefix_str(prefix, USER)); + let user_tbl = note_tbl.join_str(USER); + q.add_aliased_columns::(&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 { - 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(¬e_tbl), + ¬e_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, + ¬e_tbl, options.with_reply_target.then_some(1).unwrap_or_default(), options.with_renote_target.then_some(1).unwrap_or_default(), options, diff --git a/ext_calckey_model/src/paginated.rs b/ext_calckey_model/src/paginated.rs index bb92354..9571b58 100644 --- a/ext_calckey_model/src/paginated.rs +++ b/ext_calckey_model/src/paginated.rs @@ -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 } diff --git a/ext_calckey_model/src/user_model.rs b/ext_calckey_model/src/user_model.rs index 920c177..b8ec42b 100644 --- a/ext_calckey_model/src/user_model.rs +++ b/ext_calckey_model/src/user_model.rs @@ -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 { - 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::(prefix); + q.add_aliased_columns::(user_tbl); if *with_avatar_and_banner { - q.add_aliased_columns::(&joined_prefix_str(prefix, AVATAR)) - .add_aliased_columns::(&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::(&avatar_tbl) + .add_aliased_columns::(&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, ); } } diff --git a/src/model/data/note.rs b/src/model/data/note.rs index f40a1a3..41ce552 100644 --- a/src/model/data/note.rs +++ b/src/model/data/note.rs @@ -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::{ diff --git a/src/model/processing/note.rs b/src/model/processing/note.rs index 28213d4..e830c8b 100644 --- a/src/model/processing/note.rs +++ b/src/model/processing/note.rs @@ -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); impl NoteVisibilityFilterFactory for NoteVisibilityFilterSimple { - fn with_note_and_user_tables(&self, note_tbl: Option) -> 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