199 lines
5.8 KiB
Rust
199 lines
5.8 KiB
Rust
use async_trait::async_trait;
|
|
use chrono::NaiveDateTime;
|
|
use content::post::PostBlock;
|
|
use serde_json::json;
|
|
use sqlx::types::Json;
|
|
use uuid::Uuid;
|
|
|
|
use crate::{
|
|
content::{
|
|
self,
|
|
post::{CreatePostData, PostRepository, PostWithAuthor, UpdatePostData},
|
|
Error,
|
|
},
|
|
cursor::CursorList,
|
|
};
|
|
|
|
use super::Database;
|
|
|
|
#[async_trait]
|
|
impl PostRepository for Database {
|
|
async fn list_posts_in_collection(
|
|
&self,
|
|
site: &Uuid,
|
|
collection: &Uuid,
|
|
from: Option<NaiveDateTime>,
|
|
limit: i64,
|
|
) -> Result<CursorList<PostWithAuthor, NaiveDateTime>, Error> {
|
|
let posts = sqlx::query_as!(
|
|
PostWithAuthor,
|
|
r#"SELECT
|
|
COALESCE(users.display_name,users.name) as author_display_name,
|
|
users.name as author_username,
|
|
pages.slug,
|
|
pages.title,
|
|
pages.description,
|
|
pages.tags,
|
|
pages.blocks as "blocks!: Json<Vec<PostBlock>>",
|
|
pages.created_at,
|
|
pages.modified_at,
|
|
pages.published,
|
|
pages.collections
|
|
FROM pages
|
|
JOIN
|
|
users ON author = users.id
|
|
WHERE
|
|
pages.site = $1
|
|
AND $2 = ANY(collections)
|
|
AND pages.deleted_at IS NULL
|
|
AND published = true
|
|
AND pages.created_at <= $3
|
|
ORDER BY created_at DESC
|
|
LIMIT $4
|
|
"#,
|
|
site,
|
|
collection,
|
|
from.unwrap_or_else(|| NaiveDateTime::MAX),
|
|
limit
|
|
)
|
|
.fetch_all(&self.pool)
|
|
.await?;
|
|
|
|
Ok(CursorList::new(posts, limit as usize))
|
|
}
|
|
|
|
async fn get_post_from_url(
|
|
&self,
|
|
site: &str,
|
|
slug: &str,
|
|
) -> Result<PostWithAuthor, content::Error> {
|
|
let post = sqlx::query_as!(
|
|
PostWithAuthor,
|
|
r#"SELECT
|
|
COALESCE(users.display_name,users.name) as author_display_name,
|
|
users.name as author_username,
|
|
pages.slug,
|
|
pages.title,
|
|
pages.description,
|
|
pages.tags,
|
|
pages.blocks as "blocks!: Json<Vec<PostBlock>>",
|
|
pages.created_at,
|
|
pages.modified_at,
|
|
pages.published,
|
|
pages.collections
|
|
FROM pages
|
|
JOIN
|
|
sites ON site = sites.id
|
|
JOIN
|
|
users ON author = users.id
|
|
WHERE
|
|
slug = $1
|
|
AND sites.name = $2
|
|
AND pages.deleted_at IS NULL
|
|
AND sites.deleted_at IS NULL"#,
|
|
slug,
|
|
site
|
|
)
|
|
.fetch_one(&self.pool)
|
|
.await
|
|
.map_err(|e| match e {
|
|
sqlx::Error::RowNotFound => Error::NotFound,
|
|
_ => e.into(),
|
|
})?;
|
|
Ok(post)
|
|
}
|
|
|
|
async fn create_post(
|
|
&self,
|
|
owner: &Uuid,
|
|
site: &Uuid,
|
|
data: CreatePostData,
|
|
) -> Result<(), Error> {
|
|
sqlx::query!(
|
|
"INSERT INTO pages (id, author, site, slug, title, description, tags, blocks, collections, published)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
|
|
Uuid::now_v7(),
|
|
owner,
|
|
site,
|
|
data.slug,
|
|
data.title,
|
|
data.description.unwrap_or_else(|| "".to_string()),
|
|
&data.tags,
|
|
json!(data.blocks),
|
|
&data.collections,
|
|
data.published
|
|
).execute(&self.pool).await.map_err(|err| match err {
|
|
sqlx::Error::Database(dberr) if dberr.constraint() == Some("pages_site_slug_unique") => {
|
|
Error::IdentifierNotAvailable
|
|
}
|
|
_ => err.into(),
|
|
})?;
|
|
Ok(())
|
|
}
|
|
|
|
async fn update_post(
|
|
&self,
|
|
owner: &Uuid,
|
|
site: &Uuid,
|
|
slug: &str,
|
|
data: UpdatePostData,
|
|
) -> Result<(), Error> {
|
|
let result = sqlx::query!(
|
|
"UPDATE pages SET title = COALESCE($1, title), description = COALESCE($2, description), tags = COALESCE($3, tags), blocks = COALESCE($4, blocks), collections = COALESCE($8, collections), published = COALESCE($9, published) WHERE author = $5 AND site = $6 AND slug = $7 AND deleted_at IS NULL",
|
|
data.title,
|
|
data.description,
|
|
data.tags.as_deref(),
|
|
data.blocks.map(|x| json!(x)),
|
|
owner,
|
|
site,
|
|
slug,
|
|
data.collections.as_deref(),
|
|
data.published
|
|
)
|
|
.execute(&self.pool).await.map_err(|err| match err {
|
|
sqlx::Error::Database(dberr) if dberr.constraint() == Some("pages_site_slug_unique") => {
|
|
Error::IdentifierNotAvailable
|
|
}
|
|
_ => err.into(),
|
|
})?;
|
|
|
|
if result.rows_affected() == 0 {
|
|
return Err(Error::NotFound);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn delete_post(
|
|
&self,
|
|
owner: &Uuid,
|
|
site: &Uuid,
|
|
slug: &str,
|
|
soft_delete: bool,
|
|
) -> Result<(), Error> {
|
|
let result = if soft_delete {
|
|
sqlx::query!(
|
|
"UPDATE pages SET deleted_at = NOW() WHERE author = $1 AND site = $2 AND slug = $3 AND deleted_at IS NULL",
|
|
owner,
|
|
site,
|
|
slug
|
|
).execute(&self.pool).await?
|
|
} else {
|
|
sqlx::query!(
|
|
"DELETE FROM pages WHERE author = $1 AND site = $2 AND slug = $3",
|
|
owner,
|
|
site,
|
|
slug
|
|
)
|
|
.execute(&self.pool)
|
|
.await?
|
|
};
|
|
|
|
if result.rows_affected() == 0 {
|
|
return Err(Error::NotFound);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|