Files
blog-server/internal/db/sqlc/post.sql.go
2026-08-19 22:05:49 +08:00

729 lines
20 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: post.sql
package sqlc
import (
"context"
"encoding/json"
"time"
)
const countPosts = `-- name: CountPosts :one
SELECT COUNT(*)
FROM posts
`
func (q *Queries) CountPosts(ctx context.Context) (int64, error) {
row := q.db.QueryRow(ctx, countPosts)
var count int64
err := row.Scan(&count)
return count, err
}
const countPublishedPosts = `-- name: CountPublishedPosts :one
SELECT COUNT(*)
FROM posts
WHERE status = 1
AND published_at < NOW()
`
func (q *Queries) CountPublishedPosts(ctx context.Context) (int64, error) {
row := q.db.QueryRow(ctx, countPublishedPosts)
var count int64
err := row.Scan(&count)
return count, err
}
const createPost = `-- name: CreatePost :one
INSERT INTO posts(title, cover_id, slug, content, summary, status, sort, published_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING id
`
type CreatePostParams 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"`
}
func (q *Queries) CreatePost(ctx context.Context, arg CreatePostParams) (int32, error) {
row := q.db.QueryRow(ctx, createPost,
arg.Title,
arg.CoverID,
arg.Slug,
arg.Content,
arg.Summary,
arg.Status,
arg.Sort,
arg.PublishedAt,
)
var id int32
err := row.Scan(&id)
return id, err
}
const deletePost = `-- name: DeletePost :execrows
DELETE
FROM posts
WHERE id = $1
`
func (q *Queries) DeletePost(ctx context.Context, id int32) (int64, error) {
result, err := q.db.Exec(ctx, deletePost, id)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
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_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
FROM posts p
LEFT JOIN files f ON f.id = p.cover_id
LEFT JOIN post_category pc ON pc.post_id = p.id
LEFT JOIN categories c ON c.id = pc.category_id
LEFT JOIN post_tag pt ON pt.post_id = p.id
WHERE p.id = $1
GROUP BY p.id,
f.file_url,
f.file_size,
c.name,
c.id
LIMIT 1
`
type GetPostByIDRow 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"`
CoverSize *int64 `json:"cover_size"`
CategoryName *string `json:"category_name"`
CategoryID *int32 `json:"category_id"`
Tags interface{} `json:"tags"`
}
func (q *Queries) GetPostByID(ctx context.Context, id int32) (GetPostByIDRow, error) {
row := q.db.QueryRow(ctx, getPostByID, id)
var i GetPostByIDRow
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.CoverSize,
&i.CategoryName,
&i.CategoryID,
&i.Tags,
)
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.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()
LIMIT 1
`
type GetPublicPostBySlugRow struct {
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 -------------------------------------------------------
func (q *Queries) GetPublicPostBySlug(ctx context.Context, slug string) (GetPublicPostBySlugRow, error) {
row := q.db.QueryRow(ctx, getPublicPostBySlug, slug)
var i GetPublicPostBySlugRow
err := row.Scan(
&i.ID,
&i.Title,
&i.Slug,
&i.Content,
&i.Summary,
&i.PublishedAt,
&i.Cover,
&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
AND p.published_at < NOW()
ORDER BY p.published_at DESC, p.id DESC
`
type ListArchivesRow struct {
ID int32 `json:"id"`
Slug string `json:"slug"`
Title string `json:"title"`
PublishedAt time.Time `json:"published_at"`
CategoryName *string `json:"category_name"`
}
func (q *Queries) ListArchives(ctx context.Context) ([]ListArchivesRow, error) {
rows, err := q.db.Query(ctx, listArchives)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListArchivesRow{}
for rows.Next() {
var i ListArchivesRow
if err := rows.Scan(
&i.ID,
&i.Slug,
&i.Title,
&i.PublishedAt,
&i.CategoryName,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listCategoryStats = `-- name: ListCategoryStats :many
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"`
}
func (q *Queries) ListCategoryStats(ctx context.Context) ([]ListCategoryStatsRow, error) {
rows, err := q.db.Query(ctx, listCategoryStats)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListCategoryStatsRow{}
for rows.Next() {
var i ListCategoryStatsRow
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Code,
&i.PostCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listPosts = `-- name: ListPosts :many
WITH paginated_posts AS (
-- 第一步:先精准查出当前页需要的文章 ID
SELECT id,
title,
cover_id,
slug,
summary,
status,
sort,
published_at,
created_at,
updated_at
FROM posts
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.status, p.sort, p.published_at, p.created_at, p.updated_at,
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
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
LEFT JOIN categories c ON c.id = pc.category_id
LEFT JOIN post_stats ps ON ps.post_id = p.id
LEFT JOIN post_tag pt ON pt.post_id = p.id
LEFT JOIN tags t ON t.id = pt.tag_id
GROUP BY 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,
f.file_size,
c.name,
c.id,
ps.view_count
ORDER BY p.sort DESC, p.published_at DESC, p.id DESC
`
type ListPostsParams struct {
Limit int32 `json:"limit"`
Offset int32 `json:"offset"`
}
type ListPostsRow struct {
ID int32 `json:"id"`
Title string `json:"title"`
CoverID *int32 `json:"cover_id"`
Slug string `json:"slug"`
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"`
CoverSize *int64 `json:"cover_size"`
CategoryName *string `json:"category_name"`
CategoryID *int32 `json:"category_id"`
ViewCount int32 `json:"view_count"`
Tags interface{} `json:"tags"`
}
// 第二步:用这极少量的记录去进行 JOIN
func (q *Queries) ListPosts(ctx context.Context, arg ListPostsParams) ([]ListPostsRow, error) {
rows, err := q.db.Query(ctx, listPosts, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListPostsRow{}
for rows.Next() {
var i ListPostsRow
if err := rows.Scan(
&i.ID,
&i.Title,
&i.CoverID,
&i.Slug,
&i.Summary,
&i.Status,
&i.Sort,
&i.PublishedAt,
&i.CreatedAt,
&i.UpdatedAt,
&i.Cover,
&i.CoverSize,
&i.CategoryName,
&i.CategoryID,
&i.ViewCount,
&i.Tags,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listPublishedPosts = `-- name: ListPublishedPosts :many
WITH paginated_posts AS (
-- 第一步:先精准查出当前页需要的文章 ID
SELECT id,
title,
cover_id,
slug,
summary,
sort,
published_at
FROM posts
WHERE status = 1
AND published_at < NOW()
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,
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
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
LEFT JOIN categories c ON c.id = pc.category_id
LEFT JOIN post_stats ps ON ps.post_id = p.id
LEFT JOIN post_tag pt ON pt.post_id = p.id
LEFT JOIN tags t ON t.id = pt.tag_id
GROUP BY p.id,
p.title,
p.cover_id,
p.slug,
p.summary,
p.sort,
p.published_at,
f.file_url,
c.name,
c.id,
c.code,
ps.view_count
ORDER BY p.sort DESC, p.published_at DESC, p.id DESC
`
type ListPublishedPostsParams struct {
Limit int32 `json:"limit"`
Offset int32 `json:"offset"`
}
type ListPublishedPostsRow struct {
ID int32 `json:"id"`
Title string `json:"title"`
CoverID *int32 `json:"cover_id"`
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"`
CategoryID *int32 `json:"category_id"`
CategoryCode *string `json:"category_code"`
ViewCount int32 `json:"view_count"`
Tags interface{} `json:"tags"`
}
func (q *Queries) ListPublishedPosts(ctx context.Context, arg ListPublishedPostsParams) ([]ListPublishedPostsRow, error) {
rows, err := q.db.Query(ctx, listPublishedPosts, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
items := []ListPublishedPostsRow{}
for rows.Next() {
var i ListPublishedPostsRow
if err := rows.Scan(
&i.ID,
&i.Title,
&i.CoverID,
&i.Slug,
&i.Summary,
&i.Sort,
&i.PublishedAt,
&i.Cover,
&i.CategoryName,
&i.CategoryID,
&i.CategoryCode,
&i.ViewCount,
&i.Tags,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
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 = 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"`
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,
arg.Summary,
arg.Status,
arg.Sort,
arg.PublishedAt,
arg.ID,
)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}