use crate::models::builders::content::CategoryIdUpdate;
use crate::models::{Content, ContentKind, CreateContentParams, UpdateContentParams};
use chrono::Utc;
use sqlx::PgPool;
use std::sync::Arc;
use systemprompt_identifiers::{CategoryId, ContentId, SourceId};
use super::queries;
pub async fn create(
pool: &Arc<PgPool>,
params: &CreateContentParams,
) -> Result<Content, sqlx::Error> {
let id = ContentId::new(uuid::Uuid::new_v4().to_string());
let now = Utc::now();
sqlx::query_as!(
Content,
r#"
INSERT INTO markdown_content (
id, slug, title, description, body, author,
published_at, keywords, kind, image, category_id, source_id,
version_hash, links, updated_at, public
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
ON CONFLICT (slug) DO UPDATE SET
title = EXCLUDED.title,
description = EXCLUDED.description,
body = EXCLUDED.body,
author = EXCLUDED.author,
published_at = EXCLUDED.published_at,
keywords = EXCLUDED.keywords,
kind = EXCLUDED.kind,
image = EXCLUDED.image,
category_id = EXCLUDED.category_id,
source_id = EXCLUDED.source_id,
version_hash = EXCLUDED.version_hash,
links = EXCLUDED.links,
updated_at = EXCLUDED.updated_at,
public = EXCLUDED.public
RETURNING id as "id: ContentId", slug, title, description, body, author,
published_at, keywords, kind, image,
category_id as "category_id: CategoryId",
source_id as "source_id: SourceId",
version_hash, public, COALESCE(links, '[]'::jsonb) as "links!",
updated_at
"#,
id.as_str(),
params.slug,
params.title,
params.description,
params.body,
params.author,
params.published_at,
params.keywords,
params.kind.as_str(),
params.image,
params.category_id.as_ref().map(CategoryId::as_str),
params.source_id.as_str(),
params.version_hash,
params.links,
now,
params.public
)
.fetch_one(&**pool)
.await
}
pub async fn update(
pool: &Arc<PgPool>,
params: &UpdateContentParams,
) -> Result<Content, sqlx::Error> {
let now = Utc::now();
let current = queries::get_by_id(pool, ¶ms.id).await?;
let current_ref = current.as_ref();
let category_id_value: Option<String> = match ¶ms.category_id {
CategoryIdUpdate::Set(cat) => Some(cat.as_str().to_string()),
CategoryIdUpdate::Clear => None,
CategoryIdUpdate::Unchanged => {
current_ref.and_then(|c| c.category_id.as_ref().map(|cat| cat.as_str().to_string()))
},
};
let kind_value: String = params.kind.clone().unwrap_or_else(|| {
current_ref.map_or_else(
|| ContentKind::Article.as_str().to_string(),
|c| c.kind.clone(),
)
});
let public_value: bool = params
.public
.unwrap_or_else(|| current_ref.is_some_and(|c| c.public));
let author_value: String = params
.author
.clone()
.unwrap_or_else(|| current_ref.map_or_else(String::new, |c| c.author.clone()));
let published_at_value = params
.published_at
.unwrap_or_else(|| current_ref.map_or_else(Utc::now, |c| c.published_at));
let links_value = params.links.clone().unwrap_or_else(|| {
current_ref.map_or_else(|| serde_json::Value::Array(vec![]), |c| c.links.clone())
});
sqlx::query_as!(
Content,
r#"
UPDATE markdown_content
SET title = $1, description = $2, body = $3, keywords = $4,
image = $5, version_hash = $6, updated_at = $7,
category_id = $8, kind = $9, public = $10,
author = $11, published_at = $12, links = $13
WHERE id = $14
RETURNING id as "id: ContentId", slug, title, description, body, author,
published_at, keywords, kind, image,
category_id as "category_id: CategoryId",
source_id as "source_id: SourceId",
version_hash, public, COALESCE(links, '[]'::jsonb) as "links!",
updated_at
"#,
params.title,
params.description,
params.body,
params.keywords,
params.image,
params.version_hash,
now,
category_id_value,
kind_value,
public_value,
author_value,
published_at_value,
links_value,
params.id.as_str()
)
.fetch_one(&**pool)
.await
}
pub async fn delete(pool: &Arc<PgPool>, id: &ContentId) -> Result<(), sqlx::Error> {
sqlx::query!("DELETE FROM markdown_content WHERE id = $1", id.as_str())
.execute(&**pool)
.await?;
Ok(())
}
pub async fn delete_by_source(
pool: &Arc<PgPool>,
source_id: &SourceId,
) -> Result<u64, sqlx::Error> {
let result = sqlx::query!(
"DELETE FROM markdown_content WHERE source_id = $1",
source_id.as_str()
)
.execute(&**pool)
.await?;
Ok(result.rows_affected())
}