Made some changes to how index pages are made
This commit is contained in:
parent
ba12398d2f
commit
573517565d
|
@ -28,6 +28,41 @@ func (q *Queries) GetBundleWithID(ctx context.Context, id int64) (Bundle, error)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getSiteBundleInfo = `-- name: GetSiteBundleInfo :many
|
||||||
|
WITH page_counts AS (
|
||||||
|
SELECT b.bundle_id, count(*) AS page_count FROM pages b WHERE b.site_id = $1 GROUP BY bundle_id
|
||||||
|
), index_pages AS (
|
||||||
|
SELECT p.id AS index_page_id, p.bundle_id FROM pages p WHERE p.site_id = $1 AND p.role = 'index'
|
||||||
|
)
|
||||||
|
SELECT b.bundle_id, b.page_count, p.index_page_id FROM page_counts b LEFT OUTER JOIN index_pages p ON b.bundle_id = p.bundle_id
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetSiteBundleInfoRow struct {
|
||||||
|
BundleID int64
|
||||||
|
PageCount int64
|
||||||
|
IndexPageID pgtype.Int8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetSiteBundleInfo(ctx context.Context, siteID int64) ([]GetSiteBundleInfoRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, getSiteBundleInfo, siteID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetSiteBundleInfoRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetSiteBundleInfoRow
|
||||||
|
if err := rows.Scan(&i.BundleID, &i.PageCount, &i.IndexPageID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const insertBundle = `-- name: InsertBundle :one
|
const insertBundle = `-- name: InsertBundle :one
|
||||||
INSERT INTO bundles (
|
INSERT INTO bundles (
|
||||||
site_id,
|
site_id,
|
||||||
|
|
|
@ -54,6 +54,47 @@ func (ns NullPageNameProvenance) Value() (driver.Value, error) {
|
||||||
return string(ns.PageNameProvenance), nil
|
return string(ns.PageNameProvenance), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PageRole string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PageRoleIndex PageRole = "index"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *PageRole) Scan(src interface{}) error {
|
||||||
|
switch s := src.(type) {
|
||||||
|
case []byte:
|
||||||
|
*e = PageRole(s)
|
||||||
|
case string:
|
||||||
|
*e = PageRole(s)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported scan type for PageRole: %T", src)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullPageRole struct {
|
||||||
|
PageRole PageRole
|
||||||
|
Valid bool // Valid is true if PageRole is not NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the Scanner interface.
|
||||||
|
func (ns *NullPageRole) Scan(value interface{}) error {
|
||||||
|
if value == nil {
|
||||||
|
ns.PageRole, ns.Valid = "", false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ns.Valid = true
|
||||||
|
return ns.PageRole.Scan(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (ns NullPageRole) Value() (driver.Value, error) {
|
||||||
|
if !ns.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return string(ns.PageRole), nil
|
||||||
|
}
|
||||||
|
|
||||||
type PostState string
|
type PostState string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -193,10 +234,11 @@ type Page struct {
|
||||||
Name string
|
Name string
|
||||||
NameProvenance PageNameProvenance
|
NameProvenance PageNameProvenance
|
||||||
Title pgtype.Text
|
Title pgtype.Text
|
||||||
Role pgtype.Int8
|
PostTypeID pgtype.Int8
|
||||||
Body string
|
Body string
|
||||||
State PostState
|
State PostState
|
||||||
Props []byte
|
Props []byte
|
||||||
|
Role NullPageRole
|
||||||
PublishDate pgtype.Timestamptz
|
PublishDate pgtype.Timestamptz
|
||||||
CreatedAt pgtype.Timestamp
|
CreatedAt pgtype.Timestamp
|
||||||
UpdatedAt pgtype.Timestamp
|
UpdatedAt pgtype.Timestamp
|
||||||
|
@ -206,7 +248,7 @@ type Post struct {
|
||||||
ID int64
|
ID int64
|
||||||
SiteID int64
|
SiteID int64
|
||||||
Title pgtype.Text
|
Title pgtype.Text
|
||||||
Role pgtype.Int8
|
PostTypeID pgtype.Int8
|
||||||
Body string
|
Body string
|
||||||
State PostState
|
State PostState
|
||||||
Props []byte
|
Props []byte
|
||||||
|
@ -215,7 +257,7 @@ type Post struct {
|
||||||
UpdatedAt pgtype.Timestamp
|
UpdatedAt pgtype.Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostRole struct {
|
type PostType struct {
|
||||||
ID int64
|
ID int64
|
||||||
SiteID int64
|
SiteID int64
|
||||||
LayoutName string
|
LayoutName string
|
||||||
|
|
|
@ -21,7 +21,7 @@ func (q *Queries) DeletePageWithID(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPageWithID = `-- name: GetPageWithID :one
|
const getPageWithID = `-- name: GetPageWithID :one
|
||||||
SELECT id, site_id, bundle_id, name, name_provenance, title, role, body, state, props, publish_date, created_at, updated_at FROM pages WHERE id = $1
|
SELECT id, site_id, bundle_id, name, name_provenance, title, post_type_id, body, state, props, role, publish_date, created_at, updated_at FROM pages WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetPageWithID(ctx context.Context, id int64) (Page, error) {
|
func (q *Queries) GetPageWithID(ctx context.Context, id int64) (Page, error) {
|
||||||
|
@ -34,10 +34,11 @@ func (q *Queries) GetPageWithID(ctx context.Context, id int64) (Page, error) {
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.NameProvenance,
|
&i.NameProvenance,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
&i.Role,
|
&i.PostTypeID,
|
||||||
&i.Body,
|
&i.Body,
|
||||||
&i.State,
|
&i.State,
|
||||||
&i.Props,
|
&i.Props,
|
||||||
|
&i.Role,
|
||||||
&i.PublishDate,
|
&i.PublishDate,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
@ -52,14 +53,15 @@ INSERT INTO pages (
|
||||||
name,
|
name,
|
||||||
name_provenance,
|
name_provenance,
|
||||||
title,
|
title,
|
||||||
role,
|
post_type_id,
|
||||||
body,
|
body,
|
||||||
state,
|
state,
|
||||||
props,
|
props,
|
||||||
|
role,
|
||||||
publish_date,
|
publish_date,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $11)
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $12)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -69,10 +71,11 @@ type InsertPageParams struct {
|
||||||
Name string
|
Name string
|
||||||
NameProvenance PageNameProvenance
|
NameProvenance PageNameProvenance
|
||||||
Title pgtype.Text
|
Title pgtype.Text
|
||||||
Role pgtype.Int8
|
PostTypeID pgtype.Int8
|
||||||
Body string
|
Body string
|
||||||
State PostState
|
State PostState
|
||||||
Props []byte
|
Props []byte
|
||||||
|
Role NullPageRole
|
||||||
PublishDate pgtype.Timestamptz
|
PublishDate pgtype.Timestamptz
|
||||||
CreatedAt pgtype.Timestamp
|
CreatedAt pgtype.Timestamp
|
||||||
}
|
}
|
||||||
|
@ -84,10 +87,11 @@ func (q *Queries) InsertPage(ctx context.Context, arg InsertPageParams) (int64,
|
||||||
arg.Name,
|
arg.Name,
|
||||||
arg.NameProvenance,
|
arg.NameProvenance,
|
||||||
arg.Title,
|
arg.Title,
|
||||||
arg.Role,
|
arg.PostTypeID,
|
||||||
arg.Body,
|
arg.Body,
|
||||||
arg.State,
|
arg.State,
|
||||||
arg.Props,
|
arg.Props,
|
||||||
|
arg.Role,
|
||||||
arg.PublishDate,
|
arg.PublishDate,
|
||||||
arg.CreatedAt,
|
arg.CreatedAt,
|
||||||
)
|
)
|
||||||
|
@ -97,7 +101,7 @@ func (q *Queries) InsertPage(ctx context.Context, arg InsertPageParams) (int64,
|
||||||
}
|
}
|
||||||
|
|
||||||
const listPages = `-- name: ListPages :many
|
const listPages = `-- name: ListPages :many
|
||||||
SELECT id, site_id, bundle_id, name, name_provenance, title, role, body, state, props, publish_date, created_at, updated_at FROM pages WHERE site_id = $1 ORDER BY name ASC LIMIT 25
|
SELECT id, site_id, bundle_id, name, name_provenance, title, post_type_id, body, state, props, role, publish_date, created_at, updated_at FROM pages WHERE site_id = $1 ORDER BY name ASC LIMIT 25
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListPages(ctx context.Context, siteID int64) ([]Page, error) {
|
func (q *Queries) ListPages(ctx context.Context, siteID int64) ([]Page, error) {
|
||||||
|
@ -116,10 +120,11 @@ func (q *Queries) ListPages(ctx context.Context, siteID int64) ([]Page, error) {
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.NameProvenance,
|
&i.NameProvenance,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
&i.Role,
|
&i.PostTypeID,
|
||||||
&i.Body,
|
&i.Body,
|
||||||
&i.State,
|
&i.State,
|
||||||
&i.Props,
|
&i.Props,
|
||||||
|
&i.Role,
|
||||||
&i.PublishDate,
|
&i.PublishDate,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
@ -135,7 +140,7 @@ func (q *Queries) ListPages(ctx context.Context, siteID int64) ([]Page, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const listPublishablePages = `-- name: ListPublishablePages :many
|
const listPublishablePages = `-- name: ListPublishablePages :many
|
||||||
SELECT id, site_id, bundle_id, name, name_provenance, title, role, body, state, props, publish_date, created_at, updated_at
|
SELECT id, site_id, bundle_id, name, name_provenance, title, post_type_id, body, state, props, role, publish_date, created_at, updated_at
|
||||||
FROM pages
|
FROM pages
|
||||||
WHERE id > $1 AND site_id = $2 AND state = 'published'
|
WHERE id > $1 AND site_id = $2 AND state = 'published'
|
||||||
ORDER BY id LIMIT 100
|
ORDER BY id LIMIT 100
|
||||||
|
@ -162,10 +167,11 @@ func (q *Queries) ListPublishablePages(ctx context.Context, arg ListPublishableP
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.NameProvenance,
|
&i.NameProvenance,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
&i.Role,
|
&i.PostTypeID,
|
||||||
&i.Body,
|
&i.Body,
|
||||||
&i.State,
|
&i.State,
|
||||||
&i.Props,
|
&i.Props,
|
||||||
|
&i.Role,
|
||||||
&i.PublishDate,
|
&i.PublishDate,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
@ -187,13 +193,14 @@ UPDATE pages SET
|
||||||
name = $4,
|
name = $4,
|
||||||
name_provenance = $5,
|
name_provenance = $5,
|
||||||
title = $6,
|
title = $6,
|
||||||
role = $7,
|
post_type_id = $7,
|
||||||
body = $8,
|
role = $8,
|
||||||
state = $9,
|
body = $9,
|
||||||
props = $10,
|
state = $10,
|
||||||
publish_date = $11,
|
props = $11,
|
||||||
created_at = $12,
|
publish_date = $12,
|
||||||
updated_at = $13
|
created_at = $13,
|
||||||
|
updated_at = $14
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -204,7 +211,8 @@ type UpdatePageParams struct {
|
||||||
Name string
|
Name string
|
||||||
NameProvenance PageNameProvenance
|
NameProvenance PageNameProvenance
|
||||||
Title pgtype.Text
|
Title pgtype.Text
|
||||||
Role pgtype.Int8
|
PostTypeID pgtype.Int8
|
||||||
|
Role NullPageRole
|
||||||
Body string
|
Body string
|
||||||
State PostState
|
State PostState
|
||||||
Props []byte
|
Props []byte
|
||||||
|
@ -221,6 +229,7 @@ func (q *Queries) UpdatePage(ctx context.Context, arg UpdatePageParams) error {
|
||||||
arg.Name,
|
arg.Name,
|
||||||
arg.NameProvenance,
|
arg.NameProvenance,
|
||||||
arg.Title,
|
arg.Title,
|
||||||
|
arg.PostTypeID,
|
||||||
arg.Role,
|
arg.Role,
|
||||||
arg.Body,
|
arg.Body,
|
||||||
arg.State,
|
arg.State,
|
||||||
|
|
|
@ -21,7 +21,7 @@ func (q *Queries) DeletePost(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPostWithID = `-- name: GetPostWithID :one
|
const getPostWithID = `-- name: GetPostWithID :one
|
||||||
SELECT id, site_id, title, role, body, state, props, publish_date, created_at, updated_at FROM posts WHERE id = $1 LIMIT 1
|
SELECT id, site_id, title, post_type_id, body, state, props, publish_date, created_at, updated_at FROM posts WHERE id = $1 LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetPostWithID(ctx context.Context, id int64) (Post, error) {
|
func (q *Queries) GetPostWithID(ctx context.Context, id int64) (Post, error) {
|
||||||
|
@ -31,7 +31,7 @@ func (q *Queries) GetPostWithID(ctx context.Context, id int64) (Post, error) {
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.SiteID,
|
&i.SiteID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
&i.Role,
|
&i.PostTypeID,
|
||||||
&i.Body,
|
&i.Body,
|
||||||
&i.State,
|
&i.State,
|
||||||
&i.Props,
|
&i.Props,
|
||||||
|
@ -84,7 +84,7 @@ func (q *Queries) InsertPost(ctx context.Context, arg InsertPostParams) (int64,
|
||||||
}
|
}
|
||||||
|
|
||||||
const listPosts = `-- name: ListPosts :many
|
const listPosts = `-- name: ListPosts :many
|
||||||
SELECT id, site_id, title, role, body, state, props, publish_date, created_at, updated_at FROM posts WHERE site_id = $1 ORDER BY publish_date DESC LIMIT 25
|
SELECT id, site_id, title, post_type_id, body, state, props, publish_date, created_at, updated_at FROM posts WHERE site_id = $1 ORDER BY publish_date DESC LIMIT 25
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) ListPosts(ctx context.Context, siteID int64) ([]Post, error) {
|
func (q *Queries) ListPosts(ctx context.Context, siteID int64) ([]Post, error) {
|
||||||
|
@ -100,7 +100,7 @@ func (q *Queries) ListPosts(ctx context.Context, siteID int64) ([]Post, error) {
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.SiteID,
|
&i.SiteID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
&i.Role,
|
&i.PostTypeID,
|
||||||
&i.Body,
|
&i.Body,
|
||||||
&i.State,
|
&i.State,
|
||||||
&i.Props,
|
&i.Props,
|
||||||
|
@ -119,7 +119,7 @@ func (q *Queries) ListPosts(ctx context.Context, siteID int64) ([]Post, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const listPublishablePosts = `-- name: ListPublishablePosts :many
|
const listPublishablePosts = `-- name: ListPublishablePosts :many
|
||||||
SELECT id, site_id, title, role, body, state, props, publish_date, created_at, updated_at
|
SELECT id, site_id, title, post_type_id, body, state, props, publish_date, created_at, updated_at
|
||||||
FROM posts
|
FROM posts
|
||||||
WHERE id > $1 AND site_id = $2 AND state = 'published' AND publish_date <= $3
|
WHERE id > $1 AND site_id = $2 AND state = 'published' AND publish_date <= $3
|
||||||
ORDER BY id LIMIT 100
|
ORDER BY id LIMIT 100
|
||||||
|
@ -144,7 +144,7 @@ func (q *Queries) ListPublishablePosts(ctx context.Context, arg ListPublishableP
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.SiteID,
|
&i.SiteID,
|
||||||
&i.Title,
|
&i.Title,
|
||||||
&i.Role,
|
&i.PostTypeID,
|
||||||
&i.Body,
|
&i.Body,
|
||||||
&i.State,
|
&i.State,
|
||||||
&i.Props,
|
&i.Props,
|
||||||
|
|
|
@ -15,6 +15,13 @@ const (
|
||||||
DateNameProvenance NameProvenance = iota
|
DateNameProvenance NameProvenance = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PageRole int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NormalPageRole PageRole = iota
|
||||||
|
IndexPageRole
|
||||||
|
)
|
||||||
|
|
||||||
type Bundle struct {
|
type Bundle struct {
|
||||||
ID int64
|
ID int64
|
||||||
SiteID int64
|
SiteID int64
|
||||||
|
@ -30,11 +37,18 @@ type Page struct {
|
||||||
Name string
|
Name string
|
||||||
NameProvenance NameProvenance
|
NameProvenance NameProvenance
|
||||||
Title string
|
Title string
|
||||||
Role int64
|
Role PageRole
|
||||||
Body string
|
Body string
|
||||||
State PostState
|
State PostState
|
||||||
|
PageTypeID int64
|
||||||
Props []byte
|
Props []byte
|
||||||
PublishDate time.Time
|
PublishDate time.Time
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BundleInfo struct {
|
||||||
|
BundleID int64
|
||||||
|
PageCount int
|
||||||
|
IndexPageID int64
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
"lmika.dev/lmika/hugo-cms/gen/sqlc/dbq"
|
"lmika.dev/lmika/hugo-cms/gen/sqlc/dbq"
|
||||||
"lmika.dev/lmika/hugo-cms/models"
|
"lmika.dev/lmika/hugo-cms/models"
|
||||||
|
"lmika.dev/pkg/modash/momap"
|
||||||
"lmika.dev/pkg/modash/moslice"
|
"lmika.dev/pkg/modash/moslice"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,6 +40,20 @@ func (db *DB) GetBundleWithID(ctx context.Context, id int64) (models.Bundle, err
|
||||||
return dbBundleToBundle(res), nil
|
return dbBundleToBundle(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) GetSiteBundleInfo(ctx context.Context, siteID int64) (map[int64]models.BundleInfo, error) {
|
||||||
|
res, err := db.q.GetSiteBundleInfo(ctx, siteID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return momap.FromSlice(res, func(bi dbq.GetSiteBundleInfoRow) (int64, models.BundleInfo) {
|
||||||
|
return bi.BundleID, models.BundleInfo{
|
||||||
|
BundleID: bi.BundleID,
|
||||||
|
PageCount: int(bi.PageCount),
|
||||||
|
IndexPageID: bi.IndexPageID.Int64,
|
||||||
|
}
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
func dbBundleToBundle(b dbq.Bundle) models.Bundle {
|
func dbBundleToBundle(b dbq.Bundle) models.Bundle {
|
||||||
return models.Bundle{
|
return models.Bundle{
|
||||||
ID: b.ID,
|
ID: b.ID,
|
||||||
|
|
|
@ -16,6 +16,12 @@ var nameProvenanceToDBNameProvenance = map[models.NameProvenance]dbq.PageNamePro
|
||||||
}
|
}
|
||||||
var dbNameProvenanceToNameProvenance = momap.ReverseMap(nameProvenanceToDBNameProvenance)
|
var dbNameProvenanceToNameProvenance = momap.ReverseMap(nameProvenanceToDBNameProvenance)
|
||||||
|
|
||||||
|
var pageRoleToDBPageRole = map[models.PageRole]dbq.NullPageRole{
|
||||||
|
models.NormalPageRole: {},
|
||||||
|
models.IndexPageRole: {PageRole: dbq.PageRoleIndex, Valid: true},
|
||||||
|
}
|
||||||
|
var dbPageRoleToPageRole = momap.ReverseMap(pageRoleToDBPageRole)
|
||||||
|
|
||||||
func (db *DB) InsertPage(ctx context.Context, page *models.Page) error {
|
func (db *DB) InsertPage(ctx context.Context, page *models.Page) error {
|
||||||
|
|
||||||
id, err := db.q.InsertPage(ctx, dbq.InsertPageParams{
|
id, err := db.q.InsertPage(ctx, dbq.InsertPageParams{
|
||||||
|
@ -23,6 +29,7 @@ func (db *DB) InsertPage(ctx context.Context, page *models.Page) error {
|
||||||
BundleID: page.BundleID,
|
BundleID: page.BundleID,
|
||||||
Name: page.Name,
|
Name: page.Name,
|
||||||
NameProvenance: nameProvenanceToDBNameProvenance[page.NameProvenance],
|
NameProvenance: nameProvenanceToDBNameProvenance[page.NameProvenance],
|
||||||
|
Role: pageRoleToDBPageRole[page.Role],
|
||||||
Title: pgtype.Text{String: page.Title, Valid: page.Title != ""},
|
Title: pgtype.Text{String: page.Title, Valid: page.Title != ""},
|
||||||
Body: page.Body,
|
Body: page.Body,
|
||||||
State: dbq.PostState(page.State),
|
State: dbq.PostState(page.State),
|
||||||
|
@ -43,6 +50,7 @@ func (db *DB) UpdatePage(ctx context.Context, page *models.Page) error {
|
||||||
SiteID: page.SiteID,
|
SiteID: page.SiteID,
|
||||||
BundleID: page.BundleID,
|
BundleID: page.BundleID,
|
||||||
Name: page.Name,
|
Name: page.Name,
|
||||||
|
Role: pageRoleToDBPageRole[page.Role],
|
||||||
NameProvenance: nameProvenanceToDBNameProvenance[page.NameProvenance],
|
NameProvenance: nameProvenanceToDBNameProvenance[page.NameProvenance],
|
||||||
Title: pgtype.Text{String: page.Title, Valid: page.Title != ""},
|
Title: pgtype.Text{String: page.Title, Valid: page.Title != ""},
|
||||||
Body: page.Body,
|
Body: page.Body,
|
||||||
|
@ -95,6 +103,7 @@ func dbPageToPage(p dbq.Page) models.Page {
|
||||||
SiteID: p.SiteID,
|
SiteID: p.SiteID,
|
||||||
BundleID: p.BundleID,
|
BundleID: p.BundleID,
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
|
Role: dbPageRoleToPageRole[p.Role],
|
||||||
NameProvenance: dbNameProvenanceToNameProvenance[p.NameProvenance],
|
NameProvenance: dbNameProvenanceToNameProvenance[p.NameProvenance],
|
||||||
Title: p.Title.String,
|
Title: p.Title.String,
|
||||||
Body: p.Body,
|
Body: p.Body,
|
||||||
|
|
|
@ -85,7 +85,7 @@ func (s *Service) Create(ctx context.Context, site models.Site, req NewPost) (mo
|
||||||
post := models.Page{
|
post := models.Page{
|
||||||
SiteID: site.ID,
|
SiteID: site.ID,
|
||||||
BundleID: rootBundle.ID,
|
BundleID: rootBundle.ID,
|
||||||
Name: s.normalizePageName(req.Title),
|
Name: name,
|
||||||
NameProvenance: nameProvenance,
|
NameProvenance: nameProvenance,
|
||||||
Title: req.Title,
|
Title: req.Title,
|
||||||
Body: req.Body,
|
Body: req.Body,
|
||||||
|
|
|
@ -27,7 +27,17 @@ func (s *Service) WritePage(site models.Site, bundle models.Bundle, page models.
|
||||||
return fmt.Errorf("theme %s not found in themes", site.Theme)
|
return fmt.Errorf("theme %s not found in themes", site.Theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.writePage(site, themeMeta, bundle, page); err != nil {
|
bundleInfo, err := s.db.GetSiteBundleInfo(ctx, site.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.writePage(pageBuildInfo{
|
||||||
|
site: site,
|
||||||
|
themeMeta: themeMeta,
|
||||||
|
bundle: bundle,
|
||||||
|
bundleInfo: bundleInfo,
|
||||||
|
}, page); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return s.publish(ctx, site)
|
return s.publish(ctx, site)
|
||||||
|
@ -45,8 +55,23 @@ func (s *Service) DeletePage(site models.Site, page models.Page) models.Job {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
themeMeta, ok := s.themes.Lookup(site.Theme)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("theme %s not found in themes", site.Theme)
|
||||||
|
}
|
||||||
|
|
||||||
postFilename := s.pageFilename(site, bundle, page)
|
bundleInfo, err := s.db.GetSiteBundleInfo(ctx, site.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
postFilename := s.pageFilename(pageBuildInfo{
|
||||||
|
site: site,
|
||||||
|
themeMeta: themeMeta,
|
||||||
|
bundle: bundle,
|
||||||
|
bundleInfo: bundleInfo,
|
||||||
|
}, page)
|
||||||
|
|
||||||
if os.Remove(postFilename) != nil {
|
if os.Remove(postFilename) != nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -71,6 +96,11 @@ func (s *Service) writeAllPages(ctx context.Context, site models.Site) error {
|
||||||
|
|
||||||
bundlesByID := momap.FromSlice(bundles, func(b models.Bundle) (int64, models.Bundle) { return b.ID, b })
|
bundlesByID := momap.FromSlice(bundles, func(b models.Bundle) (int64, models.Bundle) { return b.ID, b })
|
||||||
|
|
||||||
|
bundleInfo, err := s.db.GetSiteBundleInfo(ctx, site.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var startId int64
|
var startId int64
|
||||||
for {
|
for {
|
||||||
pages, err := s.db.ListPublishablePages(ctx, int64(startId), site.ID)
|
pages, err := s.db.ListPublishablePages(ctx, int64(startId), site.ID)
|
||||||
|
@ -81,7 +111,12 @@ func (s *Service) writeAllPages(ctx context.Context, site models.Site) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, page := range pages {
|
for _, page := range pages {
|
||||||
if err := s.writePage(site, themeMeta, bundlesByID[page.BundleID], page); err != nil {
|
if err := s.writePage(pageBuildInfo{
|
||||||
|
site: site,
|
||||||
|
themeMeta: themeMeta,
|
||||||
|
bundle: bundlesByID[page.BundleID],
|
||||||
|
bundleInfo: bundleInfo,
|
||||||
|
}, page); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,17 +124,24 @@ func (s *Service) writeAllPages(ctx context.Context, site models.Site) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) writePage(site models.Site, themeMeta models.ThemeMeta, bundle models.Bundle, page models.Page) error {
|
func (s *Service) writePage(bi pageBuildInfo, page models.Page) error {
|
||||||
postFilename := s.pageFilename(site, bundle, page)
|
postFilename := s.pageFilename(bi, page)
|
||||||
|
|
||||||
frontMatter := map[string]any{
|
frontMatter := map[string]any{
|
||||||
"date": page.PublishDate.Format(time.RFC3339),
|
"date": page.PublishDate.Format(time.RFC3339),
|
||||||
}
|
}
|
||||||
if page.Title != "" {
|
if page.Title != "" {
|
||||||
frontMatter["title"] = page.Title
|
frontMatter["title"] = page.Title
|
||||||
} else if themeMeta.PreferTitle {
|
} else if bi.themeMeta.PreferTitle {
|
||||||
frontMatter["title"] = page.PublishDate.Format(time.ANSIC)
|
frontMatter["title"] = page.PublishDate.Format(time.ANSIC)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.writeMarkdownFile(postFilename, frontMatter, page.Body)
|
return s.writeMarkdownFile(postFilename, frontMatter, page.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type pageBuildInfo struct {
|
||||||
|
site models.Site
|
||||||
|
themeMeta models.ThemeMeta
|
||||||
|
bundle models.Bundle
|
||||||
|
bundleInfo map[int64]models.BundleInfo
|
||||||
|
}
|
||||||
|
|
|
@ -151,12 +151,32 @@ func (s *Service) postFilename(site models.Site, themeMeta models.ThemeMeta, pos
|
||||||
return filepath.Join(s.hugo.SiteStagingDir(site, hugo.ContentSiteDir), themeMeta.BlogPostBundle, post.CreatedAt.Format("2006-01-02-150405.md"))
|
return filepath.Join(s.hugo.SiteStagingDir(site, hugo.ContentSiteDir), themeMeta.BlogPostBundle, post.CreatedAt.Format("2006-01-02-150405.md"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) pageFilename(site models.Site, bundle models.Bundle, page models.Page) string {
|
func (s *Service) pageFilename(bi pageBuildInfo, page models.Page) string {
|
||||||
bundleDir := ""
|
isIndex := false
|
||||||
if bundle.Name != models.RootBundleName {
|
isLeafBundle := true
|
||||||
bundleDir = bundle.Name
|
|
||||||
|
thisBundleInfo := bi.bundleInfo[bi.bundle.ID]
|
||||||
|
if thisBundleInfo.PageCount > 1 {
|
||||||
|
isLeafBundle = false
|
||||||
|
isIndex = thisBundleInfo.IndexPageID == page.ID
|
||||||
|
} else {
|
||||||
|
isIndex = true
|
||||||
}
|
}
|
||||||
|
|
||||||
pageName := page.Name + ".md"
|
bundleDir := ""
|
||||||
return filepath.Join(s.hugo.SiteStagingDir(site, hugo.ContentSiteDir), bundleDir, pageName)
|
if bi.bundle.Name != models.RootBundleName {
|
||||||
|
bundleDir = bi.bundle.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
pageName := page.Name
|
||||||
|
if isIndex {
|
||||||
|
if isLeafBundle {
|
||||||
|
pageName = "index"
|
||||||
|
} else {
|
||||||
|
pageName = "_index"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pageName += ".md"
|
||||||
|
return filepath.Join(s.hugo.SiteStagingDir(bi.site, hugo.ContentSiteDir), bundleDir, pageName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ func (s *Service) CreateSite(ctx context.Context, user models.User, name string)
|
||||||
Title: "Welcome to the home page",
|
Title: "Welcome to the home page",
|
||||||
Body: "This is the home page",
|
Body: "This is the home page",
|
||||||
State: models.PostStatePublished,
|
State: models.PostStatePublished,
|
||||||
|
Role: models.IndexPageRole,
|
||||||
PublishDate: time.Now(),
|
PublishDate: time.Now(),
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
UpdatedAt: time.Now(),
|
UpdatedAt: time.Now(),
|
||||||
|
|
|
@ -10,4 +10,12 @@ INSERT INTO bundles (
|
||||||
SELECT * FROM bundles WHERE site_id = $1;
|
SELECT * FROM bundles WHERE site_id = $1;
|
||||||
|
|
||||||
-- name: GetBundleWithID :one
|
-- name: GetBundleWithID :one
|
||||||
SELECT * FROM bundles WHERE id = $1;
|
SELECT * FROM bundles WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: GetSiteBundleInfo :many
|
||||||
|
WITH page_counts AS (
|
||||||
|
SELECT b.bundle_id, count(*) AS page_count FROM pages b WHERE b.site_id = $1 GROUP BY bundle_id
|
||||||
|
), index_pages AS (
|
||||||
|
SELECT p.id AS index_page_id, p.bundle_id FROM pages p WHERE p.site_id = $1 AND p.role = 'index'
|
||||||
|
)
|
||||||
|
SELECT b.bundle_id, b.page_count, p.index_page_id FROM page_counts b LEFT OUTER JOIN index_pages p ON b.bundle_id = p.bundle_id;
|
||||||
|
|
|
@ -5,14 +5,15 @@ INSERT INTO pages (
|
||||||
name,
|
name,
|
||||||
name_provenance,
|
name_provenance,
|
||||||
title,
|
title,
|
||||||
role,
|
post_type_id,
|
||||||
body,
|
body,
|
||||||
state,
|
state,
|
||||||
props,
|
props,
|
||||||
|
role,
|
||||||
publish_date,
|
publish_date,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $11)
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $12)
|
||||||
RETURNING id;
|
RETURNING id;
|
||||||
|
|
||||||
-- name: UpdatePage :exec
|
-- name: UpdatePage :exec
|
||||||
|
@ -22,13 +23,14 @@ UPDATE pages SET
|
||||||
name = $4,
|
name = $4,
|
||||||
name_provenance = $5,
|
name_provenance = $5,
|
||||||
title = $6,
|
title = $6,
|
||||||
role = $7,
|
post_type_id = $7,
|
||||||
body = $8,
|
role = $8,
|
||||||
state = $9,
|
body = $9,
|
||||||
props = $10,
|
state = $10,
|
||||||
publish_date = $11,
|
props = $11,
|
||||||
created_at = $12,
|
publish_date = $12,
|
||||||
updated_at = $13
|
created_at = $13,
|
||||||
|
updated_at = $14
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
||||||
-- name: ListPublishablePages :many
|
-- name: ListPublishablePages :many
|
||||||
|
|
|
@ -17,6 +17,10 @@ CREATE TYPE page_name_provenance AS ENUM (
|
||||||
'date'
|
'date'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TYPE page_role AS ENUM (
|
||||||
|
'index'
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id BIGSERIAL NOT NULL PRIMARY KEY,
|
id BIGSERIAL NOT NULL PRIMARY KEY,
|
||||||
email TEXT NOT NULL UNIQUE,
|
email TEXT NOT NULL UNIQUE,
|
||||||
|
@ -36,7 +40,7 @@ CREATE TABLE sites (
|
||||||
|
|
||||||
-- Post role is used to describe a specific kind of post, such as a link.
|
-- Post role is used to describe a specific kind of post, such as a link.
|
||||||
-- When set, it specifies the layout to use for the page
|
-- When set, it specifies the layout to use for the page
|
||||||
CREATE TABLE post_roles (
|
CREATE TABLE post_types (
|
||||||
id BIGSERIAL NOT NULL PRIMARY KEY,
|
id BIGSERIAL NOT NULL PRIMARY KEY,
|
||||||
site_id BIGINT NOT NULL,
|
site_id BIGINT NOT NULL,
|
||||||
layout_name TEXT NOT NULL,
|
layout_name TEXT NOT NULL,
|
||||||
|
@ -48,7 +52,7 @@ CREATE TABLE posts (
|
||||||
id BIGSERIAL NOT NULL PRIMARY KEY,
|
id BIGSERIAL NOT NULL PRIMARY KEY,
|
||||||
site_id BIGINT NOT NULL,
|
site_id BIGINT NOT NULL,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
role BIGINT,
|
post_type_id BIGINT,
|
||||||
body TEXT NOT NULL,
|
body TEXT NOT NULL,
|
||||||
state post_state NOT NULL,
|
state post_state NOT NULL,
|
||||||
props JSON NOT NULL,
|
props JSON NOT NULL,
|
||||||
|
@ -56,7 +60,7 @@ CREATE TABLE posts (
|
||||||
created_at TIMESTAMP NOT NULL,
|
created_at TIMESTAMP NOT NULL,
|
||||||
updated_at TIMESTAMP NOT NULL,
|
updated_at TIMESTAMP NOT NULL,
|
||||||
|
|
||||||
FOREIGN KEY (role) REFERENCES post_roles (id) ON DELETE CASCADE,
|
FOREIGN KEY (post_type_id) REFERENCES post_types (id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (site_id) REFERENCES sites (id) ON DELETE CASCADE
|
FOREIGN KEY (site_id) REFERENCES sites (id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -77,19 +81,21 @@ CREATE TABLE pages (
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
name_provenance page_name_provenance NOT NULL,
|
name_provenance page_name_provenance NOT NULL,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
role BIGINT,
|
post_type_id BIGINT,
|
||||||
body TEXT NOT NULL,
|
body TEXT NOT NULL,
|
||||||
state post_state NOT NULL,
|
state post_state NOT NULL,
|
||||||
props JSON NOT NULL,
|
props JSON NOT NULL,
|
||||||
|
role page_role,
|
||||||
publish_date TIMESTAMP WITH TIME ZONE,
|
publish_date TIMESTAMP WITH TIME ZONE,
|
||||||
created_at TIMESTAMP NOT NULL,
|
created_at TIMESTAMP NOT NULL,
|
||||||
updated_at TIMESTAMP NOT NULL,
|
updated_at TIMESTAMP NOT NULL,
|
||||||
|
|
||||||
UNIQUE (bundle_id, name),
|
UNIQUE (bundle_id, name),
|
||||||
FOREIGN KEY (site_id) REFERENCES sites (id) ON DELETE CASCADE,
|
FOREIGN KEY (site_id) REFERENCES sites (id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (role) REFERENCES post_roles (id) ON DELETE CASCADE,
|
FOREIGN KEY (post_type_id) REFERENCES post_types (id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (bundle_id) REFERENCES sites (id) ON DELETE CASCADE
|
FOREIGN KEY (bundle_id) REFERENCES sites (id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
CREATE UNIQUE INDEX page_bundle_id_role ON pages (bundle_id, role) WHERE (role is NOT null);
|
||||||
|
|
||||||
CREATE TABLE publish_targets (
|
CREATE TABLE publish_targets (
|
||||||
id BIGSERIAL NOT NULL PRIMARY KEY,
|
id BIGSERIAL NOT NULL PRIMARY KEY,
|
||||||
|
|
Loading…
Reference in a new issue