Browse Source

add chapter repository to postgres.

master
Gisle Aune 4 years ago
parent
commit
663a95c70d
  1. 2
      cmd/rpdata-restore/main.go
  2. 127
      database/postgres/chapters.go
  3. 2
      database/postgres/db.go
  4. 20
      database/postgres/migrations/20210326165205_create_table_chapter.sql
  5. 9
      database/postgres/migrations/20210326165603_create_index_chapter_story_id.sql
  6. 1
      database/postgres/psqlcore/changes.sql.go
  7. 1
      database/postgres/psqlcore/channels.sql.go
  8. 177
      database/postgres/psqlcore/chapters.sql.go
  9. 13
      database/postgres/psqlcore/models.go
  10. 1
      database/postgres/psqlcore/stories.sql.go
  11. 33
      database/postgres/queries/chapters.sql
  12. 21
      database/postgres/stories.go
  13. 18
      models/chapter.go

2
cmd/rpdata-restore/main.go

@ -83,7 +83,7 @@ func main() {
hideList := make(map[string]bool) hideList := make(map[string]bool)
if parts[1] != "story" {
if parts[1] != "story" && parts[1] != "chapter" {
continue continue
} }

127
database/postgres/chapters.go

@ -0,0 +1,127 @@
package postgres
import (
"context"
"database/sql"
"git.aiterp.net/rpdata/api/database/postgres/psqlcore"
"git.aiterp.net/rpdata/api/internal/generate"
"git.aiterp.net/rpdata/api/models"
)
type chapterRepository struct {
insertWithIDs bool
db *sql.DB
}
func (r *chapterRepository) Find(ctx context.Context, id string) (*models.Chapter, error) {
chapter, err := psqlcore.New(r.db).SelectChapter(ctx, id)
if err != nil {
return nil, err
}
return r.chapter(chapter), nil
}
func (r *chapterRepository) List(ctx context.Context, filter models.ChapterFilter) ([]*models.Chapter, error) {
params := psqlcore.SelectChaptersParams{
StoryID: "",
LimitSize: 10000,
}
if filter.StoryID != nil {
params.StoryID = *filter.StoryID
}
if filter.Limit > 0 {
params.LimitSize = int32(filter.Limit)
}
chapters, err := psqlcore.New(r.db).SelectChapters(ctx, params)
if err != nil {
return nil, err
}
return r.chapters(chapters), nil
}
func (r *chapterRepository) Insert(ctx context.Context, chapter models.Chapter) (*models.Chapter, error) {
if !r.insertWithIDs || len(chapter.ID) < 8 {
chapter.ID = generate.ChapterID()
}
err := psqlcore.New(r.db).InsertChapter(ctx, psqlcore.InsertChapterParams{
ID: chapter.ID,
StoryID: chapter.StoryID,
Title: chapter.Title,
Author: chapter.Author,
Source: chapter.Source,
CreatedDate: chapter.CreatedDate.UTC(),
FictionalDate: chapter.FictionalDate.UTC(),
EditedDate: chapter.EditedDate.UTC(),
CommentMode: string(chapter.CommentMode),
CommentsLocked: chapter.CommentsLocked,
})
if err != nil {
return nil, err
}
return &chapter, nil
}
func (r *chapterRepository) Update(ctx context.Context, chapter models.Chapter, update models.ChapterUpdate) (*models.Chapter, error) {
chapter.ApplyUpdate(update)
err := psqlcore.New(r.db).UpdateChapter(ctx, psqlcore.UpdateChapterParams{
Title: chapter.Title,
Source: chapter.Source,
FictionalDate: chapter.FictionalDate.UTC(),
CommentMode: string(chapter.CommentMode),
CommentsLocked: chapter.CommentsLocked,
ID: chapter.ID,
})
if err != nil {
return nil, err
}
return &chapter, nil
}
func (r *chapterRepository) Move(ctx context.Context, chapter models.Chapter, from, to models.Story) (*models.Chapter, error) {
err := psqlcore.New(r.db).UpdateChapterStoryID(ctx, psqlcore.UpdateChapterStoryIDParams{
StoryID: to.ID,
ID: chapter.ID,
})
if err != nil {
return nil, err
}
chapter.StoryID = to.ID
return &chapter, nil
}
func (r *chapterRepository) Delete(ctx context.Context, chapter models.Chapter) error {
return psqlcore.New(r.db).DeleteChapter(ctx, chapter.ID)
}
func (r *chapterRepository) chapter(chapter psqlcore.StoryChapter) *models.Chapter {
return &models.Chapter{
ID: chapter.ID,
StoryID: chapter.StoryID,
Title: chapter.Title,
Author: chapter.Author,
Source: chapter.Source,
CreatedDate: chapter.CreatedDate,
FictionalDate: chapter.FictionalDate,
EditedDate: chapter.EditedDate,
CommentMode: models.ChapterCommentMode(chapter.CommentMode),
CommentsLocked: chapter.CommentsLocked,
}
}
func (r *chapterRepository) chapters(chapters []psqlcore.StoryChapter) []*models.Chapter {
results := make([]*models.Chapter, 0, len(chapters))
for _, chapter := range chapters {
results = append(results, r.chapter(chapter))
}
return results
}

2
database/postgres/db.go

@ -81,7 +81,7 @@ func (d *DB) Stories() repositories.StoryRepository {
} }
func (d *DB) Chapters() repositories.ChapterRepository { func (d *DB) Chapters() repositories.ChapterRepository {
panic("implement me")
return &chapterRepository{insertWithIDs: d.insertWithIDs, db: d.db}
} }
func (d *DB) Comments() repositories.CommentRepository { func (d *DB) Comments() repositories.CommentRepository {

20
database/postgres/migrations/20210326165205_create_table_chapter.sql

@ -0,0 +1,20 @@
-- +goose Up
-- +goose StatementBegin
CREATE TABLE story_chapter (
id TEXT NOT NULL PRIMARY KEY,
story_id TEXT NOT NULL,
title TEXT NOT NULL,
author TEXT NOT NULL,
source TEXT NOT NULL,
created_date TIMESTAMP NOT NULL,
fictional_date TIMESTAMP NOT NULL,
edited_date TIMESTAMP NOT NULL,
comment_mode TEXT NOT NULL,
comments_locked BOOLEAN NOT NULL
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE story_chapter;
-- +goose StatementEnd

9
database/postgres/migrations/20210326165603_create_index_chapter_story_id.sql

@ -0,0 +1,9 @@
-- +goose Up
-- +goose StatementBegin
CREATE INDEX story_chapter_index_story_id ON story_chapter (story_id);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP INDEX IF EXISTS story_chapter_index_story_id;
-- +goose StatementEnd

1
database/postgres/psqlcore/changes.sql.go

@ -80,6 +80,7 @@ WHERE ($1::bool = false OR keys && ($2::text[]))
AND ($3::bool = false OR date >= $4::timestamp) AND ($3::bool = false OR date >= $4::timestamp)
AND ($5::bool = false OR date <= $6::timestamp) AND ($5::bool = false OR date <= $6::timestamp)
AND ($7::bool = false OR author = $8::text) AND ($7::bool = false OR author = $8::text)
ORDER BY date DESC
LIMIT $9::int LIMIT $9::int
` `

1
database/postgres/psqlcore/channels.sql.go

@ -69,6 +69,7 @@ WHERE ($1::bool = false OR name = ANY($2::text[]))
AND ($3::bool = false OR logged = $4) AND ($3::bool = false OR logged = $4)
AND ($5::bool = false OR event_name = $6) AND ($5::bool = false OR event_name = $6)
AND ($7::bool = false OR location_name = $8) AND ($7::bool = false OR location_name = $8)
ORDER BY name
LIMIT $9::int LIMIT $9::int
` `

177
database/postgres/psqlcore/chapters.sql.go

@ -0,0 +1,177 @@
// Code generated by sqlc. DO NOT EDIT.
// source: chapters.sql
package psqlcore
import (
"context"
"time"
)
const deleteChapter = `-- name: DeleteChapter :exec
DELETE FROM story_chapter WHERE id=$1
`
func (q *Queries) DeleteChapter(ctx context.Context, id string) error {
_, err := q.db.ExecContext(ctx, deleteChapter, id)
return err
}
const deleteChaptersByStoryID = `-- name: DeleteChaptersByStoryID :exec
DELETE FROM story_chapter WHERE story_id=$1
`
func (q *Queries) DeleteChaptersByStoryID(ctx context.Context, storyID string) error {
_, err := q.db.ExecContext(ctx, deleteChaptersByStoryID, storyID)
return err
}
const insertChapter = `-- name: InsertChapter :exec
INSERT INTO story_chapter (id, story_id, title, author, source, created_date, fictional_date, edited_date, comment_mode, comments_locked)
VALUES (
$1::TEXT, $2::TEXT, $3::TEXT, $4::TEXT, $5::TEXT,
$6::TIMESTAMP, $7::TIMESTAMP, $8::TIMESTAMP,
$9::TEXT, $10::BOOLEAN
)
`
type InsertChapterParams struct {
ID string `json:"id"`
StoryID string `json:"story_id"`
Title string `json:"title"`
Author string `json:"author"`
Source string `json:"source"`
CreatedDate time.Time `json:"created_date"`
FictionalDate time.Time `json:"fictional_date"`
EditedDate time.Time `json:"edited_date"`
CommentMode string `json:"comment_mode"`
CommentsLocked bool `json:"comments_locked"`
}
func (q *Queries) InsertChapter(ctx context.Context, arg InsertChapterParams) error {
_, err := q.db.ExecContext(ctx, insertChapter,
arg.ID,
arg.StoryID,
arg.Title,
arg.Author,
arg.Source,
arg.CreatedDate,
arg.FictionalDate,
arg.EditedDate,
arg.CommentMode,
arg.CommentsLocked,
)
return err
}
const selectChapter = `-- name: SelectChapter :one
SELECT id, story_id, title, author, source, created_date, fictional_date, edited_date, comment_mode, comments_locked FROM story_chapter WHERE id=$1::TEXT LIMIT 1
`
func (q *Queries) SelectChapter(ctx context.Context, dollar_1 string) (StoryChapter, error) {
row := q.db.QueryRowContext(ctx, selectChapter, dollar_1)
var i StoryChapter
err := row.Scan(
&i.ID,
&i.StoryID,
&i.Title,
&i.Author,
&i.Source,
&i.CreatedDate,
&i.FictionalDate,
&i.EditedDate,
&i.CommentMode,
&i.CommentsLocked,
)
return i, err
}
const selectChapters = `-- name: SelectChapters :many
SELECT id, story_id, title, author, source, created_date, fictional_date, edited_date, comment_mode, comments_locked FROM story_chapter WHERE (sqlx.arg(story_id)::TEXT == '' OR story_id=$1::TEXT) ORDER BY created_date LIMIT $2::INT
`
type SelectChaptersParams struct {
StoryID string `json:"story_id"`
LimitSize int32 `json:"limit_size"`
}
func (q *Queries) SelectChapters(ctx context.Context, arg SelectChaptersParams) ([]StoryChapter, error) {
rows, err := q.db.QueryContext(ctx, selectChapters, arg.StoryID, arg.LimitSize)
if err != nil {
return nil, err
}
defer rows.Close()
items := []StoryChapter{}
for rows.Next() {
var i StoryChapter
if err := rows.Scan(
&i.ID,
&i.StoryID,
&i.Title,
&i.Author,
&i.Source,
&i.CreatedDate,
&i.FictionalDate,
&i.EditedDate,
&i.CommentMode,
&i.CommentsLocked,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateChapter = `-- name: UpdateChapter :exec
UPDATE story_chapter
SET title=$1,
source=$2,
fictional_date=$3,
comment_mode=$4,
comments_locked=$5
WHERE id=$6
`
type UpdateChapterParams struct {
Title string `json:"title"`
Source string `json:"source"`
FictionalDate time.Time `json:"fictional_date"`
CommentMode string `json:"comment_mode"`
CommentsLocked bool `json:"comments_locked"`
ID string `json:"id"`
}
func (q *Queries) UpdateChapter(ctx context.Context, arg UpdateChapterParams) error {
_, err := q.db.ExecContext(ctx, updateChapter,
arg.Title,
arg.Source,
arg.FictionalDate,
arg.CommentMode,
arg.CommentsLocked,
arg.ID,
)
return err
}
const updateChapterStoryID = `-- name: UpdateChapterStoryID :exec
UPDATE story_chapter
SET story_id=$1::TEXT
WHERE id=$2
`
type UpdateChapterStoryIDParams struct {
StoryID string `json:"story_id"`
ID string `json:"id"`
}
func (q *Queries) UpdateChapterStoryID(ctx context.Context, arg UpdateChapterStoryIDParams) error {
_, err := q.db.ExecContext(ctx, updateChapterStoryID, arg.StoryID, arg.ID)
return err
}

13
database/postgres/psqlcore/models.go

@ -60,3 +60,16 @@ type Story struct {
FictionalDate time.Time `json:"fictional_date"` FictionalDate time.Time `json:"fictional_date"`
UpdatedDate time.Time `json:"updated_date"` UpdatedDate time.Time `json:"updated_date"`
} }
type StoryChapter struct {
ID string `json:"id"`
StoryID string `json:"story_id"`
Title string `json:"title"`
Author string `json:"author"`
Source string `json:"source"`
CreatedDate time.Time `json:"created_date"`
FictionalDate time.Time `json:"fictional_date"`
EditedDate time.Time `json:"edited_date"`
CommentMode string `json:"comment_mode"`
CommentsLocked bool `json:"comments_locked"`
}

1
database/postgres/psqlcore/stories.sql.go

@ -66,6 +66,7 @@ WHERE ($1::bool = false OR id = ANY($2::text[]))
AND ($9::bool = false OR category = $10::text) AND ($9::bool = false OR category = $10::text)
AND ($11::bool = false OR open = $12::bool) AND ($11::bool = false OR open = $12::bool)
AND ($13::bool = false OR unlisted = $14::bool) AND ($13::bool = false OR unlisted = $14::bool)
ORDER BY updated_date
LIMIT $15::int LIMIT $15::int
` `

33
database/postgres/queries/chapters.sql

@ -0,0 +1,33 @@
-- name: SelectChapter :one
SELECT * FROM story_chapter WHERE id=$1::TEXT LIMIT 1;
-- name: SelectChapters :many
SELECT * FROM story_chapter WHERE (sqlx.arg(story_id)::TEXT == '' OR story_id=sqlc.arg(story_id)::TEXT) ORDER BY created_date LIMIT sqlc.arg(limit_size)::INT;
-- name: InsertChapter :exec
INSERT INTO story_chapter (id, story_id, title, author, source, created_date, fictional_date, edited_date, comment_mode, comments_locked)
VALUES (
sqlc.arg(id)::TEXT, sqlc.arg(story_id)::TEXT, sqlc.arg(title)::TEXT, sqlc.arg(author)::TEXT, sqlc.arg(source)::TEXT,
sqlc.arg(created_date)::TIMESTAMP, sqlc.arg(fictional_date)::TIMESTAMP, sqlc.arg(edited_date)::TIMESTAMP,
sqlc.arg(comment_mode)::TEXT, sqlc.arg(comments_locked)::BOOLEAN
);
-- name: UpdateChapterStoryID :exec
UPDATE story_chapter
SET story_id=sqlc.arg(story_id)::TEXT
WHERE id=sqlc.arg(id);
-- name: UpdateChapter :exec
UPDATE story_chapter
SET title=sqlc.arg(title),
source=sqlc.arg(source),
fictional_date=sqlc.arg(fictional_date),
comment_mode=sqlc.arg(comment_mode),
comments_locked=sqlc.arg(comments_locked)
WHERE id=sqlc.arg(id);
-- name: DeleteChapter :exec
DELETE FROM story_chapter WHERE id=$1;
-- name: DeleteChaptersByStoryID :exec
DELETE FROM story_chapter WHERE story_id=$1;

21
database/postgres/stories.go

@ -178,9 +178,14 @@ func (r *storyRepository) RemoveTag(ctx context.Context, story models.Story, tag
} }
func (r *storyRepository) Delete(ctx context.Context, story models.Story) error { func (r *storyRepository) Delete(ctx context.Context, story models.Story) error {
q := psqlcore.New(r.db)
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer func() { _ = tx.Rollback() }()
q := psqlcore.New(tx)
err := q.ClearTagsByTarget(ctx, psqlcore.ClearTagsByTargetParams{
err = q.ClearTagsByTarget(ctx, psqlcore.ClearTagsByTargetParams{
TargetKind: "Story", TargetKind: "Story",
TargetID: story.ID, TargetID: story.ID,
}) })
@ -188,7 +193,17 @@ func (r *storyRepository) Delete(ctx context.Context, story models.Story) error
return err return err
} }
return q.DeleteStory(ctx, story.ID)
err = q.DeleteChaptersByStoryID(ctx, story.ID)
if err != nil {
return err
}
err = q.DeleteStory(ctx, story.ID)
if err != nil {
return err
}
return tx.Commit()
} }
func (r *storyRepository) story(story psqlcore.Story, tags []psqlcore.CommonTag) *models.Story { func (r *storyRepository) story(story psqlcore.Story, tags []psqlcore.CommonTag) *models.Story {

18
models/chapter.go

@ -16,6 +16,24 @@ type Chapter struct {
CommentsLocked bool `bson:"commentsLocked"` CommentsLocked bool `bson:"commentsLocked"`
} }
func (chapter *Chapter) ApplyUpdate(update ChapterUpdate) {
if update.Title != nil {
chapter.Title = *update.Title
}
if update.Source != nil {
chapter.Source = *update.Source
}
if update.FictionalDate != nil {
chapter.FictionalDate = update.FictionalDate.UTC()
}
if update.CommentMode != nil {
chapter.CommentMode = *update.CommentMode
}
if update.CommentsLocked != nil {
chapter.CommentsLocked = *update.CommentsLocked
}
}
// CanComment returns true if the chapter can be commented to. // CanComment returns true if the chapter can be commented to.
func (chapter *Chapter) CanComment() bool { func (chapter *Chapter) CanComment() bool {
return !chapter.CommentsLocked && chapter.CommentMode.IsEnabled() return !chapter.CommentsLocked && chapter.CommentMode.IsEnabled()

Loading…
Cancel
Save