feat: update template

This commit is contained in:
2026-08-19 22:05:49 +08:00
parent 0e674e9d56
commit 5a71093b0c
67 changed files with 2070 additions and 585 deletions

View File

@@ -7,6 +7,7 @@ package sqlc
import (
"context"
"encoding/json"
"time"
)
@@ -85,13 +86,14 @@ func (q *Queries) DeletePost(ctx context.Context, id int32) (int64, error) {
const getPostByID = `-- name: GetPostByID :one
SELECT p.id, p.title, p.cover_id, p.slug, p.content, p.summary, p.status, p.sort, p.published_at, p.created_at, p.updated_at,
f.file_url AS cover,
f.file_url AS cover,
f.file_size AS cover_size,
c.name AS category_name,
c.id AS category_id,
COALESCE(
array_agg(pt.tag_id ORDER BY pt.tag_id) FILTER (WHERE pt.tag_id IS NOT NULL),
ARRAY[]::integer[]
) AS tags
array_agg(pt.tag_id ORDER BY pt.tag_id) FILTER (WHERE pt.tag_id IS NOT NULL),
ARRAY []::integer[]
) AS tags
FROM posts p
LEFT JOIN files f ON f.id = p.cover_id
LEFT JOIN post_category pc ON pc.post_id = p.id
@@ -100,6 +102,7 @@ FROM posts p
WHERE p.id = $1
GROUP BY p.id,
f.file_url,
f.file_size,
c.name,
c.id
LIMIT 1
@@ -118,6 +121,7 @@ type GetPostByIDRow struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
Cover *string `json:"cover"`
CoverSize *int64 `json:"cover_size"`
CategoryName *string `json:"category_name"`
CategoryID *int32 `json:"category_id"`
Tags interface{} `json:"tags"`
@@ -139,6 +143,7 @@ func (q *Queries) GetPostByID(ctx context.Context, id int32) (GetPostByIDRow, er
&i.CreatedAt,
&i.UpdatedAt,
&i.Cover,
&i.CoverSize,
&i.CategoryName,
&i.CategoryID,
&i.Tags,
@@ -146,14 +151,66 @@ func (q *Queries) GetPostByID(ctx context.Context, id int32) (GetPostByIDRow, er
return i, err
}
const getPostsForSitemap = `-- name: GetPostsForSitemap :many
SELECT slug, created_at, updated_at
FROM posts
WHERE status = 1
AND published_at < NOW()
ORDER BY sort DESC, published_at DESC, id DESC
`
type GetPostsForSitemapRow struct {
Slug string `json:"slug"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
}
func (q *Queries) GetPostsForSitemap(ctx context.Context) ([]GetPostsForSitemapRow, error) {
rows, err := q.db.Query(ctx, getPostsForSitemap)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetPostsForSitemapRow{}
for rows.Next() {
var i GetPostsForSitemapRow
if err := rows.Scan(&i.Slug, &i.CreatedAt, &i.UpdatedAt); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getPublicPostBySlug = `-- name: GetPublicPostBySlug :one
SELECT p.id, p.title, p.cover_id, p.slug, p.content, p.summary, p.status, p.sort, p.published_at, p.created_at, p.updated_at,
f.file_url AS cover,
COALESCE(ps.view, 0) AS view
SELECT p.id,
p.title,
p.slug,
p.content,
p.summary,
p.published_at,
f.file_url AS cover,
COALESCE(ps.view_count, 0) AS view_count,
c.code AS category_code,
c.name AS category_name,
COALESCE(t.tags, '[]') AS tags
FROM posts p
LEFT JOIN files f ON f.id = p.cover_id
LEFT JOIN post_stats ps ON ps.post_id = p.id
LEFT JOIN post_category pc ON pc.post_id = p.id
LEFT JOIN categories c ON pc.category_id = c.id
LEFT JOIN LATERAL (
SELECT jsonb_agg(
jsonb_build_object('name', tag.name, 'code', tag.code)
) AS tags
FROM post_tag pt
JOIN tags tag ON tag.id = pt.tag_id
WHERE pt.post_id = p.id
) t ON true
WHERE p.slug = $1
AND p.status = 1
AND p.published_at < NOW()
@@ -161,19 +218,17 @@ LIMIT 1
`
type GetPublicPostBySlugRow struct {
ID int32 `json:"id"`
Title string `json:"title"`
CoverID *int32 `json:"cover_id"`
Slug string `json:"slug"`
Content string `json:"content"`
Summary string `json:"summary"`
Status int16 `json:"status"`
Sort *int32 `json:"sort"`
PublishedAt time.Time `json:"published_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
Cover *string `json:"cover"`
View int32 `json:"view"`
ID int32 `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
Content string `json:"content"`
Summary string `json:"summary"`
PublishedAt time.Time `json:"published_at"`
Cover *string `json:"cover"`
ViewCount int32 `json:"view_count"`
CategoryCode *string `json:"category_code"`
CategoryName *string `json:"category_name"`
Tags json.RawMessage `json:"tags"`
}
// web -------------------------------------------------------
@@ -183,37 +238,31 @@ func (q *Queries) GetPublicPostBySlug(ctx context.Context, slug string) (GetPubl
err := row.Scan(
&i.ID,
&i.Title,
&i.CoverID,
&i.Slug,
&i.Content,
&i.Summary,
&i.Status,
&i.Sort,
&i.PublishedAt,
&i.CreatedAt,
&i.UpdatedAt,
&i.Cover,
&i.View,
&i.ViewCount,
&i.CategoryCode,
&i.CategoryName,
&i.Tags,
)
return i, err
}
const listArchives = `-- name: ListArchives :many
SELECT
p.id,
p.slug,
p.title,
p.published_at,
c."name" AS category_name
FROM
posts p
LEFT JOIN post_category pc ON p.id = pc.post_id
LEFT JOIN categories c ON c.id = pc.category_id
WHERE
p.status = 1
SELECT p.id,
p.slug,
p.title,
p.published_at,
c."name" AS category_name
FROM posts p
LEFT JOIN post_category pc ON p.id = pc.post_id
LEFT JOIN categories c ON c.id = pc.category_id
WHERE p.status = 1
AND p.published_at < NOW()
ORDER BY
p.published_at DESC, p.id DESC
ORDER BY p.published_at DESC, p.id DESC
`
type ListArchivesRow struct {
@@ -251,26 +300,26 @@ func (q *Queries) ListArchives(ctx context.Context) ([]ListArchivesRow, error) {
}
const listCategoryStats = `-- name: ListCategoryStats :many
SELECT
c.id,
c.name,
COUNT(p.id) AS post_count
FROM
categories c
LEFT JOIN post_category pc ON c.id = pc.category_id
LEFT JOIN posts p ON p.id = pc.post_id
AND p.status = 1
AND p.published_at < NOW()
GROUP BY
c.id,
c.sort,
c.name
SELECT c.id,
c.name,
c.code,
COUNT(p.id) AS post_count
FROM categories c
LEFT JOIN post_category pc ON c.id = pc.category_id
LEFT JOIN posts p ON p.id = pc.post_id
AND p.status = 1
AND p.published_at < NOW()
GROUP BY c.id,
c.sort,
c.name,
c.code
ORDER BY c.sort DESC, c.id
`
type ListCategoryStatsRow struct {
ID int32 `json:"id"`
Name string `json:"name"`
Code string `json:"code"`
PostCount int64 `json:"post_count"`
}
@@ -283,7 +332,12 @@ func (q *Queries) ListCategoryStats(ctx context.Context) ([]ListCategoryStatsRow
items := []ListCategoryStatsRow{}
for rows.Next() {
var i ListCategoryStatsRow
if err := rows.Scan(&i.ID, &i.Name, &i.PostCount); err != nil {
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Code,
&i.PostCount,
); err != nil {
return nil, err
}
items = append(items, i)
@@ -309,24 +363,24 @@ WITH paginated_posts AS (
updated_at
FROM posts
ORDER BY sort DESC, published_at DESC, id DESC
LIMIT $1 OFFSET $2
)
LIMIT $1 OFFSET $2)
SELECT p.id, p.title, p.cover_id, p.slug, p.summary, p.status, p.sort, p.published_at, p.created_at, p.updated_at,
f.file_url AS cover,
c.name AS category_name,
c.id AS category_id,
COALESCE(ps.view, 0) AS view,
f.file_url AS cover,
f.file_size AS cover_size,
c.name AS category_name,
c.id AS category_id,
COALESCE(ps.view_count, 0) AS view_count,
COALESCE(
jsonb_agg(
jsonb_build_object(
'id', t.id,
'name', t.name,
'code', t.code
)
ORDER BY t.sort DESC, t.id
) FILTER (WHERE t.id IS NOT NULL),
'[]'::jsonb
) AS tags
jsonb_agg(
jsonb_build_object(
'id', t.id,
'name', t.name,
'code', t.code
)
ORDER BY t.sort DESC, t.id
) FILTER (WHERE t.id IS NOT NULL),
'[]'::jsonb
) AS tags
FROM paginated_posts p
LEFT JOIN files f ON f.id = p.cover_id
LEFT JOIN post_category pc ON pc.post_id = p.id
@@ -345,9 +399,10 @@ GROUP BY p.id,
p.created_at,
p.updated_at,
f.file_url,
f.file_size,
c.name,
c.id,
ps.view
ps.view_count
ORDER BY p.sort DESC, p.published_at DESC, p.id DESC
`
@@ -368,9 +423,10 @@ type ListPostsRow struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
Cover *string `json:"cover"`
CoverSize *int64 `json:"cover_size"`
CategoryName *string `json:"category_name"`
CategoryID *int32 `json:"category_id"`
View int32 `json:"view"`
ViewCount int32 `json:"view_count"`
Tags interface{} `json:"tags"`
}
@@ -396,9 +452,10 @@ func (q *Queries) ListPosts(ctx context.Context, arg ListPostsParams) ([]ListPos
&i.CreatedAt,
&i.UpdatedAt,
&i.Cover,
&i.CoverSize,
&i.CategoryName,
&i.CategoryID,
&i.View,
&i.ViewCount,
&i.Tags,
); err != nil {
return nil, err
@@ -427,21 +484,22 @@ WITH paginated_posts AS (
ORDER BY sort DESC, published_at DESC, id DESC
LIMIT $1 OFFSET $2)
SELECT p.id, p.title, p.cover_id, p.slug, p.summary, p.sort, p.published_at,
f.file_url AS cover,
c.name AS category_name,
c.id AS category_id,
COALESCE(ps.view, 0) AS view,
f.file_url AS cover,
c.name AS category_name,
c.id AS category_id,
c.code AS category_code,
COALESCE(ps.view_count, 0) AS view_count,
COALESCE(
jsonb_agg(
jsonb_build_object(
'id', t.id,
'name', t.name,
'code', t.code
)
ORDER BY t.sort DESC, t.id
) FILTER (WHERE t.id IS NOT NULL),
'[]'::jsonb
) AS tags
jsonb_agg(
jsonb_build_object(
'id', t.id,
'name', t.name,
'code', t.code
)
ORDER BY t.sort DESC, t.id
) FILTER (WHERE t.id IS NOT NULL),
'[]'::jsonb
) AS tags
FROM paginated_posts p
LEFT JOIN files f ON f.id = p.cover_id
LEFT JOIN post_category pc ON pc.post_id = p.id
@@ -459,7 +517,8 @@ GROUP BY p.id,
f.file_url,
c.name,
c.id,
ps.view
c.code,
ps.view_count
ORDER BY p.sort DESC, p.published_at DESC, p.id DESC
`
@@ -479,7 +538,8 @@ type ListPublishedPostsRow struct {
Cover *string `json:"cover"`
CategoryName *string `json:"category_name"`
CategoryID *int32 `json:"category_id"`
View int32 `json:"view"`
CategoryCode *string `json:"category_code"`
ViewCount int32 `json:"view_count"`
Tags interface{} `json:"tags"`
}
@@ -503,7 +563,8 @@ func (q *Queries) ListPublishedPosts(ctx context.Context, arg ListPublishedPosts
&i.Cover,
&i.CategoryName,
&i.CategoryID,
&i.View,
&i.CategoryCode,
&i.ViewCount,
&i.Tags,
); err != nil {
return nil, err
@@ -516,34 +577,141 @@ func (q *Queries) ListPublishedPosts(ctx context.Context, arg ListPublishedPosts
return items, nil
}
const listPublishedPostsWithFilters = `-- name: ListPublishedPostsWithFilters :many
SELECT p.id,
p.title,
p.slug,
p.summary,
p.sort,
p.published_at,
f.file_url AS cover,
c."name" AS category_name,
c.code AS category_code,
COALESCE(t.tags, '[]') AS tags,
COALESCE(ps."view_count", 0) AS view_count
FROM posts p
LEFT JOIN post_category pc ON pc.post_id = p.id
LEFT JOIN categories c ON c.id = pc.category_id
LEFT JOIN post_stats ps ON ps.post_id = p.id
LEFT JOIN files f ON f.id = p.cover_id
LEFT JOIN LATERAL (
SELECT jsonb_agg(
jsonb_build_object('name', tag.name, 'code', tag.code)
) AS tags
FROM post_tag pt
JOIN tags tag ON tag.id = pt.tag_id
WHERE pt.post_id = p.id
) t ON true
WHERE
-- 只显示已发布的文章
p.status = 1
AND p.published_at < NOW()
AND
-- category code 过滤NULL 或空字符串时不过滤)
(
COALESCE($1::text, '') = ''
OR EXISTS (SELECT 1
FROM post_category pc2
JOIN categories c2 ON c2.id = pc2.category_id
WHERE pc2.post_id = p.id
AND c2.code = $1::text)
)
AND
-- tag code 过滤NULL 或空字符串时不过滤)
(
COALESCE($2::text, '') = ''
OR EXISTS (SELECT 1
FROM post_tag pt2
JOIN tags t2 ON t2.id = pt2.tag_id
WHERE pt2.post_id = p.id
AND t2.code = $2::text)
)
ORDER BY p.sort DESC,
p.published_at DESC,
p.id DESC
`
type ListPublishedPostsWithFiltersParams struct {
CategoryCode *string `json:"category_code"`
TagCode *string `json:"tag_code"`
}
type ListPublishedPostsWithFiltersRow struct {
ID int32 `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
Summary string `json:"summary"`
Sort *int32 `json:"sort"`
PublishedAt time.Time `json:"published_at"`
Cover *string `json:"cover"`
CategoryName *string `json:"category_name"`
CategoryCode *string `json:"category_code"`
Tags json.RawMessage `json:"tags"`
ViewCount int32 `json:"view_count"`
}
func (q *Queries) ListPublishedPostsWithFilters(ctx context.Context, arg ListPublishedPostsWithFiltersParams) ([]ListPublishedPostsWithFiltersRow, error) {
rows, err := q.db.Query(ctx, listPublishedPostsWithFilters, arg.CategoryCode, arg.TagCode)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListPublishedPostsWithFiltersRow{}
for rows.Next() {
var i ListPublishedPostsWithFiltersRow
if err := rows.Scan(
&i.ID,
&i.Title,
&i.Slug,
&i.Summary,
&i.Sort,
&i.PublishedAt,
&i.Cover,
&i.CategoryName,
&i.CategoryCode,
&i.Tags,
&i.ViewCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updatePost = `-- name: UpdatePost :execrows
UPDATE posts
SET title = coalesce($1, title),
cover_id = coalesce($2, cover_id),
slug = coalesce($3, slug),
content = coalesce($4, content),
summary = coalesce($5, summary),
status = coalesce($6, status),
sort = coalesce($7, sort),
published_at = coalesce($8, published_at)
WHERE id = $9
cover_id = CASE WHEN $2::boolean THEN $3 ELSE cover_id END,
slug = coalesce($4, slug),
content = coalesce($5, content),
summary = coalesce($6, summary),
status = coalesce($7, status),
sort = coalesce($8, sort),
published_at = coalesce($9, published_at)
WHERE id = $10
`
type UpdatePostParams struct {
Title *string `json:"title"`
CoverID *int32 `json:"cover_id"`
Slug *string `json:"slug"`
Content *string `json:"content"`
Summary *string `json:"summary"`
Status *int16 `json:"status"`
Sort *int32 `json:"sort"`
PublishedAt *time.Time `json:"published_at"`
ID int32 `json:"id"`
Title *string `json:"title"`
UpdateCoverID bool `json:"update_cover_id"`
CoverID *int32 `json:"cover_id"`
Slug *string `json:"slug"`
Content *string `json:"content"`
Summary *string `json:"summary"`
Status *int16 `json:"status"`
Sort *int32 `json:"sort"`
PublishedAt *time.Time `json:"published_at"`
ID int32 `json:"id"`
}
func (q *Queries) UpdatePost(ctx context.Context, arg UpdatePostParams) (int64, error) {
result, err := q.db.Exec(ctx, updatePost,
arg.Title,
arg.UpdateCoverID,
arg.CoverID,
arg.Slug,
arg.Content,