From 0ffbcb7471034af48570d6d28e0b2a5a58913f9e Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Fri, 24 Jan 2025 15:12:40 +0100 Subject: [PATCH] join lateral --- src/backend/api/instance.rs | 9 +++- src/backend/database/instance.rs | 74 +++++++++++--------------------- src/backend/database/mod.rs | 4 +- src/common/article.rs | 3 +- src/common/instance.rs | 12 ++++-- src/frontend/api/instance.rs | 8 +--- 6 files changed, 47 insertions(+), 63 deletions(-) diff --git a/src/backend/api/instance.rs b/src/backend/api/instance.rs index c98a435..cbb1f34 100644 --- a/src/backend/api/instance.rs +++ b/src/backend/api/instance.rs @@ -7,11 +7,16 @@ use crate::{ }, common::{ instance::{ - DbInstance, FollowInstanceParams, GetInstanceParams, InstanceView, InstanceView2, + DbInstance, + FollowInstanceParams, + GetInstanceParams, + InstanceView, + InstanceView2, UpdateInstanceParams, }, user::LocalUserView, - ResolveObjectParams, SuccessResponse, + ResolveObjectParams, + SuccessResponse, }, }; use activitypub_federation::{config::Data, fetch::object_id::ObjectId}; diff --git a/src/backend/database/instance.rs b/src/backend/database/instance.rs index e687565..2a3e211 100644 --- a/src/backend/database/instance.rs +++ b/src/backend/database/instance.rs @@ -5,14 +5,14 @@ use crate::{ IbisContext, }, federation::objects::{ - articles_collection::DbArticleCollection, instance_collection::DbInstanceCollection, + articles_collection::DbArticleCollection, + instance_collection::DbInstanceCollection, }, utils::error::MyResult, }, common::{ - article::DbArticle, instance::{DbInstance, InstanceView, InstanceView2}, - newtypes::{ArticleId, CommentId, InstanceId}, + newtypes::{CommentId, InstanceId}, user::DbPerson, }, }; @@ -21,20 +21,9 @@ use activitypub_federation::{ fetch::{collection_id::CollectionId, object_id::ObjectId}, }; use chrono::{DateTime, Utc}; -use diesel::{ - associations::HasTable, - define_sql_function, - deserialize::{self, FromSql}, - insert_into, - pg::{Pg, PgValue}, - sql_types::Record, - update, AsChangeset, ExpressionMethods, Insertable, JoinOnDsl, NullableExpressionMethods, - QueryDsl, RunQueryDsl, -}; +use diesel::*; use std::{fmt::Debug, ops::DerefMut}; -use super::array_agg; - #[derive(Debug, Clone, Insertable, AsChangeset)] #[diesel(table_name = instance, check_for_backend(diesel::pg::Pg))] pub struct DbInstanceForm { @@ -151,26 +140,28 @@ impl DbInstance { pub fn list(context: &Data) -> MyResult> { let mut conn = context.db_pool.get()?; - // select instance, array_agg(article) from instance left join article on instance.id=article.instance_id group by instance.id; - let res: Vec<_> = instance::table - .left_join(article::table.on(instance::id.eq(article::instance_id))) - .select(( - instance::all_columns, - //array_agg(article::all_columns) - diesel::dsl::sql::>( - "array_agg(article.*)", - ), - )) - .group_by(instance::id) - // TODO: throws invalid trait bound - .get_results::<(DbInstance, Vec)>(conn.deref_mut())?; - Ok(res - .into_iter() - .map(|x| InstanceView { - instance: x.0, - articles: x.1, - }) - .collect()) + let res: Vec<_> = sql_query( + "SELECT + instance, + array_agg(a) as articles + FROM + instance + CROSS JOIN LATERAL ( + SELECT + title + FROM + article + WHERE + instance.id = article.instance_id + GROUP BY + article.id + LIMIT 5) a + GROUP BY + id;", + ) + .select(InstanceView::as_select()) + .get_results::(conn.deref_mut())?; + Ok(res) } /// Read the instance where an article is hosted, based on a comment id. @@ -188,16 +179,3 @@ impl DbInstance { .get_result(conn.deref_mut())?) } } - -define_sql_function!(fn array_agg(expr: T) -> Array); - -// https://github.com/diesel-rs/diesel/discussions/3826 -impl FromSql, Pg> for DbArticle { - fn from_sql(value: PgValue<'_>) -> deserialize::Result { - //let mut bytes = value.as_bytes(); - //let res: (i32,) = FromSql::, Pg>::from_sql(value)?; - - //Ok(Label1 { id: res.0 }) - todo!() - } -} diff --git a/src/backend/database/mod.rs b/src/backend/database/mod.rs index 7509ca3..4492e81 100644 --- a/src/backend/database/mod.rs +++ b/src/backend/database/mod.rs @@ -4,7 +4,9 @@ use crate::backend::{ }; use diesel::{ r2d2::{ConnectionManager, Pool}, - PgConnection, QueryDsl, RunQueryDsl, + PgConnection, + QueryDsl, + RunQueryDsl, }; use std::ops::DerefMut; diff --git a/src/common/article.rs b/src/common/article.rs index af9f8cf..6c86045 100644 --- a/src/common/article.rs +++ b/src/common/article.rs @@ -5,6 +5,7 @@ use super::{ user::DbPerson, }; use chrono::{DateTime, Utc}; +use diesel::QueryableByName; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use uuid::Uuid; @@ -39,7 +40,7 @@ pub struct DbArticleView { pub latest_version: EditVersion, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, QueryableByName)] #[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Identifiable))] #[cfg_attr(feature = "ssr", diesel(table_name = article, check_for_backend(diesel::pg::Pg), belongs_to(DbInstance, foreign_key = instance_id)))] pub struct DbArticle { diff --git a/src/common/instance.rs b/src/common/instance.rs index 7771c05..5c1f847 100644 --- a/src/common/instance.rs +++ b/src/common/instance.rs @@ -4,13 +4,15 @@ use super::{ user::{DbPerson, LocalUserView}, }; use chrono::{DateTime, Utc}; +use diesel::QueryableByName; use serde::{Deserialize, Serialize}; use smart_default::SmartDefault; use url::Url; #[cfg(feature = "ssr")] use { crate::backend::{ - database::schema::instance, federation::objects::articles_collection::DbArticleCollection, + database::schema::instance, + federation::objects::articles_collection::DbArticleCollection, federation::objects::instance_collection::DbInstanceCollection, }, activitypub_federation::fetch::{collection_id::CollectionId, object_id::ObjectId}, @@ -18,7 +20,7 @@ use { doku::Document, }; -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, QueryableByName)] #[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Identifiable))] #[cfg_attr(feature = "ssr", diesel(table_name = instance, check_for_backend(diesel::pg::Pg)))] pub struct DbInstance { @@ -52,10 +54,12 @@ impl DbInstance { } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "ssr", derive(Queryable))] -#[cfg_attr(feature = "ssr", diesel(table_name = article, check_for_backend(diesel::pg::Pg)))] +#[cfg_attr(feature = "ssr", derive(Queryable, QueryableByName))] +#[cfg_attr(feature = "ssr", diesel(check_for_backend(diesel::pg::Pg)))] pub struct InstanceView { + #[diesel(embed)] pub instance: DbInstance, + #[diesel(embed)] pub articles: Vec, } diff --git a/src/frontend/api/instance.rs b/src/frontend/api/instance.rs index a5fcbe5..3ef2e2a 100644 --- a/src/frontend/api/instance.rs +++ b/src/frontend/api/instance.rs @@ -1,13 +1,7 @@ use super::{result_to_option, ApiClient}; use crate::common::{ article::{DbArticle, SearchArticleParams}, - instance::{ - DbInstance, - FollowInstanceParams, - InstanceView2, - SiteView, - UpdateInstanceParams, - }, + instance::{DbInstance, FollowInstanceParams, InstanceView2, SiteView, UpdateInstanceParams}, Notification, ResolveObjectParams, SuccessResponse,