Browse Source

tweak tags and add story repository.

master
Gisle Aune 3 years ago
parent
commit
525191a0f9
  1. 4
      cmd/rpdata-restore/main.go
  2. 1
      database/postgres/character.go
  3. 2
      database/postgres/db.go
  4. 87
      database/postgres/psqlcore/stories.sql.go
  5. 93
      database/postgres/psqlcore/tags.sql.go
  6. 1
      database/postgres/queries/changes.sql
  7. 1
      database/postgres/queries/channels.sql
  8. 24
      database/postgres/queries/stories.sql
  9. 28
      database/postgres/queries/tags.sql
  10. 163
      database/postgres/stories.go
  11. 22
      database/postgres/tags.go
  12. 1
      go.sum
  13. 3
      graph2/complexity.go
  14. 29
      models/story.go
  15. 7
      services/characters.go
  16. 14
      services/stories.go

4
cmd/rpdata-restore/main.go

@ -83,6 +83,10 @@ func main() {
hideList := make(map[string]bool)
if parts[1] != "story" {
continue
}
log.Println("Loaded", parts[1], parts[2], "from archive.")
switch parts[1] {

1
database/postgres/character.go

@ -108,7 +108,6 @@ func (r *characterRepository) Insert(ctx context.Context, character models.Chara
return nil, err
}
defer func() { _ = tx.Rollback() }()
q := psqlcore.New(tx)
if !r.insertWithIDs || character.ID == "" {

2
database/postgres/db.go

@ -77,7 +77,7 @@ func (d *DB) Posts() repositories.PostRepository {
}
func (d *DB) Stories() repositories.StoryRepository {
panic("implement me")
return &storyRepository{insertWithIDs: d.insertWithIDs, db: d.db}
}
func (d *DB) Chapters() repositories.ChapterRepository {

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

@ -10,6 +10,53 @@ import (
"github.com/lib/pq"
)
const deleteStory = `-- name: DeleteStory :exec
DELETE FROM story WHERE id=$1
`
func (q *Queries) DeleteStory(ctx context.Context, id string) error {
_, err := q.db.ExecContext(ctx, deleteStory, id)
return err
}
const insertStory = `-- name: InsertStory :exec
INSERT INTO story (id, author, name, category, open, listed, sort_by_fictional_date, created_date, fictional_date, updated_date)
VALUES (
$1::text, $2::text, $3::text, $4::text,
$5::boolean, $6::boolean, $7::boolean,
$8::timestamp, $9::timestamp, $10::timestamp
)
`
type InsertStoryParams struct {
ID string `json:"id"`
Author string `json:"author"`
Name string `json:"name"`
Category string `json:"category"`
Open bool `json:"open"`
Listed bool `json:"listed"`
SortByFictionalDate bool `json:"sort_by_fictional_date"`
CreatedDate time.Time `json:"created_date"`
FictionalDate time.Time `json:"fictional_date"`
UpdatedDate time.Time `json:"updated_date"`
}
func (q *Queries) InsertStory(ctx context.Context, arg InsertStoryParams) error {
_, err := q.db.ExecContext(ctx, insertStory,
arg.ID,
arg.Author,
arg.Name,
arg.Category,
arg.Open,
arg.Listed,
arg.SortByFictionalDate,
arg.CreatedDate,
arg.FictionalDate,
arg.UpdatedDate,
)
return err
}
const selectStories = `-- name: SelectStories :many
SELECT id, author, name, category, open, listed, sort_by_fictional_date, created_date, fictional_date, updated_date FROM story
WHERE ($1::bool = false OR id = ANY($2::text[]))
@ -111,3 +158,43 @@ func (q *Queries) SelectStory(ctx context.Context, id string) (Story, error) {
)
return i, err
}
const updateStory = `-- name: UpdateStory :exec
UPDATE story
SET name=$1,
category=$2,
author=$3,
open=$4,
listed=$5,
fictional_date=$6,
updated_date=$7,
sort_by_fictional_date=$8
WHERE id=$9
`
type UpdateStoryParams struct {
Name string `json:"name"`
Category string `json:"category"`
Author string `json:"author"`
Open bool `json:"open"`
Listed bool `json:"listed"`
FictionalDate time.Time `json:"fictional_date"`
UpdatedDate time.Time `json:"updated_date"`
SortByFictionalDate bool `json:"sort_by_fictional_date"`
ID string `json:"id"`
}
func (q *Queries) UpdateStory(ctx context.Context, arg UpdateStoryParams) error {
_, err := q.db.ExecContext(ctx, updateStory,
arg.Name,
arg.Category,
arg.Author,
arg.Open,
arg.Listed,
arg.FictionalDate,
arg.UpdatedDate,
arg.SortByFictionalDate,
arg.ID,
)
return err
}

93
database/postgres/psqlcore/tags.sql.go

@ -43,8 +43,26 @@ func (q *Queries) ClearTagsByTarget(ctx context.Context, arg ClearTagsByTargetPa
return err
}
const clearTagsByTargetLike = `-- name: ClearTagsByTargetLike :exec
DELETE FROM common_tag
WHERE target_kind=$1::TEXT
AND target_id=$2::TEXT
AND tag LIKE $3::TEXT
`
type ClearTagsByTargetLikeParams struct {
TargetKind string `json:"target_kind"`
TargetID string `json:"target_id"`
TagLike string `json:"tag_like"`
}
func (q *Queries) ClearTagsByTargetLike(ctx context.Context, arg ClearTagsByTargetLikeParams) error {
_, err := q.db.ExecContext(ctx, clearTagsByTargetLike, arg.TargetKind, arg.TargetID, arg.TagLike)
return err
}
const selectDistinctTags = `-- name: SelectDistinctTags :many
SELECT DISTINCT tag FROM common_tag
SELECT DISTINCT tag FROM common_tag ORDER BY tag
`
func (q *Queries) SelectDistinctTags(ctx context.Context) ([]string, error) {
@ -70,12 +88,12 @@ func (q *Queries) SelectDistinctTags(ctx context.Context) ([]string, error) {
return items, nil
}
const selectDistinctTagsByKind = `-- name: SelectDistinctTagsByKind :many
SELECT DISTINCT tag FROM common_tag WHERE tag LIKE '$1::text%'
const selectDistinctTagsLike = `-- name: SelectDistinctTagsLike :many
SELECT DISTINCT tag FROM common_tag WHERE tag LIKE $1::text ORDER BY tag
`
func (q *Queries) SelectDistinctTagsByKind(ctx context.Context) ([]string, error) {
rows, err := q.db.QueryContext(ctx, selectDistinctTagsByKind)
func (q *Queries) SelectDistinctTagsLike(ctx context.Context, dollar_1 string) ([]string, error) {
rows, err := q.db.QueryContext(ctx, selectDistinctTagsLike, dollar_1)
if err != nil {
return nil, err
}
@ -98,7 +116,7 @@ func (q *Queries) SelectDistinctTagsByKind(ctx context.Context) ([]string, error
}
const selectTagsByTag = `-- name: SelectTagsByTag :many
SELECT tag, target_kind, target_id FROM common_tag WHERE tag = $1::text
SELECT tag, target_kind, target_id FROM common_tag WHERE tag = $1::text ORDER BY tag
`
func (q *Queries) SelectTagsByTag(ctx context.Context, tagName string) ([]CommonTag, error) {
@ -125,7 +143,7 @@ func (q *Queries) SelectTagsByTag(ctx context.Context, tagName string) ([]Common
}
const selectTagsByTags = `-- name: SelectTagsByTags :many
SELECT tag, target_kind, target_id FROM common_tag WHERE tag = ANY($1::text[])
SELECT tag, target_kind, target_id FROM common_tag WHERE tag = ANY($1::text[]) ORDER BY tag
`
func (q *Queries) SelectTagsByTags(ctx context.Context, tagNames []string) ([]CommonTag, error) {
@ -152,16 +170,16 @@ func (q *Queries) SelectTagsByTags(ctx context.Context, tagNames []string) ([]Co
}
const selectTagsByTarget = `-- name: SelectTagsByTarget :many
SELECT tag, target_kind, target_id FROM common_tag WHERE target_kind = $1 AND target_id = $2::text
SELECT tag, target_kind, target_id FROM common_tag WHERE target_kind = $1 AND target_id = $2::text ORDER BY tag
`
type SelectTagsByTargetParams struct {
TargetKind string `json:"target_kind"`
Column2 string `json:"column_2"`
TargetID string `json:"target_id"`
}
func (q *Queries) SelectTagsByTarget(ctx context.Context, arg SelectTagsByTargetParams) ([]CommonTag, error) {
rows, err := q.db.QueryContext(ctx, selectTagsByTarget, arg.TargetKind, arg.Column2)
rows, err := q.db.QueryContext(ctx, selectTagsByTarget, arg.TargetKind, arg.TargetID)
if err != nil {
return nil, err
}
@ -184,16 +202,16 @@ func (q *Queries) SelectTagsByTarget(ctx context.Context, arg SelectTagsByTarget
}
const selectTagsByTargets = `-- name: SelectTagsByTargets :many
SELECT tag, target_kind, target_id FROM common_tag WHERE target_kind = $1 AND target_id = ANY($2::text[])
SELECT tag, target_kind, target_id FROM common_tag WHERE target_kind = $1 AND target_id = ANY($2::text[]) ORDER BY tag
`
type SelectTagsByTargetsParams struct {
TargetKind string `json:"target_kind"`
Column2 []string `json:"column_2"`
TargetIds []string `json:"target_ids"`
}
func (q *Queries) SelectTagsByTargets(ctx context.Context, arg SelectTagsByTargetsParams) ([]CommonTag, error) {
rows, err := q.db.QueryContext(ctx, selectTagsByTargets, arg.TargetKind, pq.Array(arg.Column2))
rows, err := q.db.QueryContext(ctx, selectTagsByTargets, arg.TargetKind, pq.Array(arg.TargetIds))
if err != nil {
return nil, err
}
@ -215,6 +233,38 @@ func (q *Queries) SelectTagsByTargets(ctx context.Context, arg SelectTagsByTarge
return items, nil
}
const selectTargetsByTags = `-- name: SelectTargetsByTags :many
SELECT DISTINCT(target_id) FROM common_tag WHERE tag = ANY($1::text[]) AND target_kind = $2::text ORDER BY tag
`
type SelectTargetsByTagsParams struct {
TagNames []string `json:"tag_names"`
TargetKind string `json:"target_kind"`
}
func (q *Queries) SelectTargetsByTags(ctx context.Context, arg SelectTargetsByTagsParams) ([]string, error) {
rows, err := q.db.QueryContext(ctx, selectTargetsByTags, pq.Array(arg.TagNames), arg.TargetKind)
if err != nil {
return nil, err
}
defer rows.Close()
items := []string{}
for rows.Next() {
var target_id string
if err := rows.Scan(&target_id); err != nil {
return nil, err
}
items = append(items, target_id)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const setTag = `-- name: SetTag :exec
INSERT INTO common_tag (tag, target_kind, target_id)
VALUES (
@ -233,3 +283,20 @@ func (q *Queries) SetTag(ctx context.Context, arg SetTagParams) error {
_, err := q.db.ExecContext(ctx, setTag, arg.Tag, arg.TargetKind, arg.TargetID)
return err
}
const setTags = `-- name: SetTags :exec
INSERT INTO common_tag (tag, target_kind, target_id)
SELECT unnest($1::TEXT[]), $2::TEXT as target_kind, $3::TEXT as target_id
ON CONFLICT DO NOTHING
`
type SetTagsParams struct {
Tags []string `json:"tags"`
TargetKind string `json:"target_kind"`
TargetID string `json:"target_id"`
}
func (q *Queries) SetTags(ctx context.Context, arg SetTagsParams) error {
_, err := q.db.ExecContext(ctx, setTags, pq.Array(arg.Tags), arg.TargetKind, arg.TargetID)
return err
}

1
database/postgres/queries/changes.sql

@ -7,6 +7,7 @@ WHERE (sqlc.arg(filter_keys)::bool = false OR keys && (sqlc.arg(keys)::text[]))
AND (sqlc.arg(filter_earliest_date)::bool = false OR date >= sqlc.arg(earliest_date)::timestamp)
AND (sqlc.arg(filter_latest_date)::bool = false OR date <= sqlc.arg(latest_date)::timestamp)
AND (sqlc.arg(filter_author)::bool = false OR author = sqlc.arg(author)::text)
ORDER BY date DESC
LIMIT sqlc.arg(limit_size)::int;
-- name: InsertChange :exec

1
database/postgres/queries/channels.sql

@ -15,6 +15,7 @@ WHERE (sqlc.arg(filter_name)::bool = false OR name = ANY(sqlc.arg(names)::text[]
AND (sqlc.arg(filter_logged)::bool = false OR logged = sqlc.arg(logged))
AND (sqlc.arg(filter_event_name)::bool = false OR event_name = sqlc.arg(event_name))
AND (sqlc.arg(filter_location_name)::bool = false OR location_name = sqlc.arg(location_name))
ORDER BY name
LIMIT sqlc.arg(limit_size)::int;
-- name: UpdateChannel :exec

24
database/postgres/queries/stories.sql

@ -10,4 +10,28 @@ WHERE (sqlc.arg(filter_id)::bool = false OR id = ANY(sqlc.arg(ids)::text[]))
AND (sqlc.arg(filter_category)::bool = false OR category = sqlc.arg(category)::text)
AND (sqlc.arg(filter_open)::bool = false OR open = sqlc.arg(open)::bool)
AND (sqlc.arg(filter_unlisted)::bool = false OR unlisted = sqlc.arg(unlisted)::bool)
ORDER BY updated_date
LIMIT sqlc.arg(limit_size)::int;
-- name: InsertStory :exec
INSERT INTO story (id, author, name, category, open, listed, sort_by_fictional_date, created_date, fictional_date, updated_date)
VALUES (
sqlc.arg(id)::text, sqlc.arg(author)::text, sqlc.arg(name)::text, sqlc.arg(category)::text,
sqlc.arg(open)::boolean, sqlc.arg(listed)::boolean, sqlc.arg(sort_by_fictional_date)::boolean,
sqlc.arg(created_date)::timestamp, sqlc.arg(fictional_date)::timestamp, sqlc.arg(updated_date)::timestamp
);
-- name: UpdateStory :exec
UPDATE story
SET name=sqlc.arg(name),
category=sqlc.arg(category),
author=sqlc.arg(author),
open=sqlc.arg(open),
listed=sqlc.arg(listed),
fictional_date=sqlc.arg(fictional_date),
updated_date=sqlc.arg(updated_date),
sort_by_fictional_date=sqlc.arg(sort_by_fictional_date)
WHERE id=sqlc.arg(id);
-- name: DeleteStory :exec
DELETE FROM story WHERE id=$1;

28
database/postgres/queries/tags.sql

@ -5,31 +5,45 @@ VALUES (
)
ON CONFLICT DO NOTHING;
-- name: SetTags :exec
INSERT INTO common_tag (tag, target_kind, target_id)
SELECT unnest(sqlc.arg(tags)::TEXT[]), sqlc.arg(target_kind)::TEXT as target_kind, sqlc.arg(target_id)::TEXT as target_id
ON CONFLICT DO NOTHING;
-- name: ClearTag :exec
DELETE FROM common_tag
WHERE tag=sqlc.arg(tag)::TEXT
AND target_kind=sqlc.arg(target_kind)::TEXT
AND target_id=sqlc.arg(target_id)::TEXT;
-- name: ClearTagsByTargetLike :exec
DELETE FROM common_tag
WHERE target_kind=sqlc.arg(target_kind)::TEXT
AND target_id=sqlc.arg(target_id)::TEXT
AND tag LIKE sqlc.arg(tag_like)::TEXT;
-- name: ClearTagsByTarget :exec
DELETE FROM common_tag
WHERE target_kind=sqlc.arg(target_kind)::TEXT
AND target_id=sqlc.arg(target_id)::TEXT;
-- name: SelectDistinctTags :many
SELECT DISTINCT tag FROM common_tag;
SELECT DISTINCT tag FROM common_tag ORDER BY tag;
-- name: SelectDistinctTagsByKind :many
SELECT DISTINCT tag FROM common_tag WHERE tag LIKE '$1::text%';
-- name: SelectDistinctTagsLike :many
SELECT DISTINCT tag FROM common_tag WHERE tag LIKE $1::text ORDER BY tag;
-- name: SelectTagsByTag :many
SELECT * FROM common_tag WHERE tag = sqlc.arg(tag_name)::text;
SELECT * FROM common_tag WHERE tag = sqlc.arg(tag_name)::text ORDER BY tag;
-- name: SelectTagsByTags :many
SELECT * FROM common_tag WHERE tag = ANY(sqlc.arg(tag_names)::text[]);
SELECT * FROM common_tag WHERE tag = ANY(sqlc.arg(tag_names)::text[]) ORDER BY tag;
-- name: SelectTargetsByTags :many
SELECT DISTINCT(target_id) FROM common_tag WHERE tag = ANY(sqlc.arg(tag_names)::text[]) AND target_kind = sqlc.arg(target_kind)::text ORDER BY tag;
-- name: SelectTagsByTarget :many
SELECT * FROM common_tag WHERE target_kind = $1 AND target_id = $2::text;
SELECT * FROM common_tag WHERE target_kind = sqlc.arg(target_kind) AND target_id = sqlc.arg(target_id)::text ORDER BY tag;
-- name: SelectTagsByTargets :many
SELECT * FROM common_tag WHERE target_kind = $1 AND target_id = ANY($2::text[]);
SELECT * FROM common_tag WHERE target_kind = sqlc.arg(target_kind) AND target_id = ANY(sqlc.arg(target_ids)::text[]) ORDER BY tag;

163
database/postgres/stories.go

@ -4,6 +4,7 @@ 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"
)
@ -35,72 +36,172 @@ func (r *storyRepository) List(ctx context.Context, filter models.StoryFilter) (
params := psqlcore.SelectStoriesParams{LimitSize: 100}
if len(filter.Tags) > 0 {
params.FilterID = true
if len(filter.Tags) == 1 {
tags, err := q.SelectTagsByKindName(ctx, psqlcore.SelectTagsByKindNameParams{
Kind: string(filter.Tags[0].Kind),
Name: filter.Tags[0].Name,
})
if err != nil && err != sql.ErrNoRows {
return nil, err
}
for _, tag := range tags {
params.Ids = append(params.Ids, tag.TargetID)
}
} else {
targets, err := q.SelectTargetsByTags(ctx, psqlcore.SelectTargetsByTagsParams{
TagNames: models.EncodeTagArray(filter.Tags),
TargetKind: "Story",
})
if err != nil && err != sql.ErrNoRows {
return nil, err
}
if len(params.Ids) == 0 {
return []*models.Story{}, nil
}
params.FilterID = true
params.Ids = targets
}
if filter.Author != nil {
params.FilterAuthor = true
params.Author = *filter.Author
}
if filter.Category != nil {
params.FilterCategory = true
params.Category = string(*filter.Category)
}
if !filter.EarliestFictionalDate.IsZero() {
params.FilterEarlistFictionalDate = true
params.EarliestFictionalDate = filter.EarliestFictionalDate.UTC()
}
if !filter.LatestFictionalDate.IsZero() {
params.FilterLastestFictionalDate = true
params.LatestFictionalDate = filter.LatestFictionalDate.UTC()
}
if filter.Open != nil {
params.FilterOpen = true
params.Open = *filter.Open
}
if filter.Unlisted != nil {
params.FilterUnlisted = true
params.Unlisted = *filter.Unlisted
}
if filter.Limit <= 0 {
params.LimitSize = 1000
}
stories, err := q.SelectStories(ctx, params)
if err != nil {
return nil, err
}
if filter.Limit > 0 {
params.LimitSize = 1000000
targetIDs := make([]string, len(stories))
for i, story := range stories {
targetIDs[i] = story.ID
}
tags, err := q.SelectTagsByTargets(ctx, psqlcore.SelectTagsByTargetsParams{
TargetKind: "Story",
TargetIds: targetIDs,
})
panic("implement me")
return r.stories(stories, tags), nil
}
func (r *storyRepository) Insert(ctx context.Context, story models.Story) (*models.Story, error) {
panic("implement me")
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return nil, err
}
defer func() { _ = tx.Rollback() }()
q := psqlcore.New(tx)
if !r.insertWithIDs || len(story.ID) < 8 {
story.ID = generate.StoryID()
}
if story.UpdatedDate.Before(story.CreatedDate) {
story.UpdatedDate = story.CreatedDate
}
err = q.InsertStory(ctx, psqlcore.InsertStoryParams{
ID: story.ID,
Author: story.Author,
Name: story.Name,
Category: string(story.Category),
Open: story.Open,
Listed: story.Listed,
SortByFictionalDate: story.SortByFictionalDate,
CreatedDate: story.CreatedDate.UTC(),
FictionalDate: story.FictionalDate.UTC(),
UpdatedDate: story.UpdatedDate.UTC(),
})
if err != nil {
return nil, err
}
// This is inefficient, but tags are very rarely added before the story is submitted.
err = q.SetTags(ctx, psqlcore.SetTagsParams{
Tags: models.EncodeTagArray(story.Tags),
TargetKind: "Story",
TargetID: story.ID,
})
if err != nil {
return nil, err
}
return &story, tx.Commit()
}
func (r *storyRepository) Update(ctx context.Context, story models.Story, update models.StoryUpdate) (*models.Story, error) {
panic("implement me")
story.ApplyUpdate(update)
err := psqlcore.New(r.db).UpdateStory(ctx, psqlcore.UpdateStoryParams{
Name: story.Name,
Category: string(story.Category),
Author: story.Author,
Open: story.Open,
Listed: story.Listed,
FictionalDate: story.FictionalDate.UTC(),
UpdatedDate: story.UpdatedDate.UTC(),
SortByFictionalDate: story.SortByFictionalDate,
ID: story.ID,
})
if err != nil {
return nil, err
}
return &story, nil
}
func (r *storyRepository) AddTag(ctx context.Context, story models.Story, tag models.Tag) error {
return psqlcore.New(r.db).SetTag(ctx, psqlcore.SetTagParams{
Kind: string(tag.Kind),
Name: tag.Name,
TargetKind: "Story",
TargetID: story.ID,
Tag: tag.String(),
})
}
func (r *storyRepository) RemoveTag(ctx context.Context, story models.Story, tag models.Tag) error {
return psqlcore.New(r.db).ClearTag(ctx, psqlcore.ClearTagParams{
Kind: string(tag.Kind),
Name: tag.Name,
TargetKind: "Story",
TargetID: story.ID,
Tag: tag.String(),
})
}
func (r *storyRepository) Delete(ctx context.Context, story models.Story) error {
panic("implement me")
q := psqlcore.New(r.db)
err := q.ClearTagsByTarget(ctx, psqlcore.ClearTagsByTargetParams{
TargetKind: "Story",
TargetID: story.ID,
})
if err != nil {
return err
}
return q.DeleteStory(ctx, story.ID)
}
func (r *storyRepository) story(story psqlcore.Story, tags []psqlcore.CommonTag) *models.Story {
tags2 := make([]models.Tag, 0, 8)
storyTags := make([]models.Tag, 0, 8)
for _, tag := range tags {
if tag.TargetKind == "Story" && tag.TargetID == story.ID {
tags2 = append(tags2, models.Tag{
Kind: models.TagKind(tag.Kind),
Name: tag.Name,
})
newTag := models.Tag{}
err := newTag.Decode(tag.Tag)
if err != nil {
continue
}
storyTags = append(storyTags, newTag)
}
}
@ -111,7 +212,7 @@ func (r *storyRepository) story(story psqlcore.Story, tags []psqlcore.CommonTag)
Category: models.StoryCategory(story.Category),
Open: story.Open,
Listed: story.Listed,
Tags: tags2,
Tags: storyTags,
CreatedDate: story.CreatedDate,
FictionalDate: story.FictionalDate,
UpdatedDate: story.UpdatedDate,

22
database/postgres/tags.go

@ -13,19 +13,25 @@ type tagRepository struct {
}
func (r *tagRepository) Find(ctx context.Context, kind models.TagKind, name string) (*models.Tag, error) {
tag, err := psqlcore.New(r.db).SelectTagsByTag(ctx, fmt.Sprintf("%s:%s", kind, nmae))
tag, err := psqlcore.New(r.db).SelectTagsByTag(ctx, fmt.Sprintf("%s:%s", kind, name))
if err != nil {
return nil, err
}
return &models.Tag{Kind: models.TagKind(tag.Kind), Name: tag.Name}, nil
tag2 := &models.Tag{}
err = tag2.Decode(tag[0].Tag)
if err != nil {
return nil, err
}
return tag2, nil
}
func (r *tagRepository) List(ctx context.Context, filter models.TagFilter) ([]*models.Tag, error) {
var tags []string
var err error
if filter.Kind != nil {
tags, err = psqlcore.New(r.db).SelectDistinctTagsByKind(ctx, string(*filter.Kind))
tags, err = psqlcore.New(r.db).SelectDistinctTagsLike(ctx, string(*filter.Kind)+"%")
} else {
tags, err = psqlcore.New(r.db).SelectDistinctTags(ctx)
}
@ -36,11 +42,15 @@ func (r *tagRepository) List(ctx context.Context, filter models.TagFilter) ([]*m
return models.DecodeTagArray(tags)
}
func modelsTagsFromDataTags(tags []psqlcore.CommonTag) []*models.Tag {
func modelsTagsFromDataTags(tags []psqlcore.CommonTag) ([]*models.Tag, error) {
results := make([]*models.Tag, len(tags))
for i, tag := range tags {
results[i] = &models.Tag{Kind: models.TagKind(tag.Kind), Name: tag.Name}
results[i] = &models.Tag{}
err := results[i].Decode(tag.Tag)
if err != nil {
return nil, err
}
}
return results
return results, nil
}

1
go.sum

@ -201,7 +201,6 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=

3
graph2/complexity.go

@ -6,6 +6,7 @@ import (
)
func complexity() (cr graphcore.ComplexityRoot) {
tinySubListComplexity := 2
subListComplexity := 25
bigSublistComplexity := 75
hugeSublistComplexity := 100
@ -175,7 +176,7 @@ func complexity() (cr graphcore.ComplexityRoot) {
return childComplexity + bigSublistComplexity
}
cr.Story.Tags = func(childComplexity int) int {
return childComplexity + subListComplexity
return childComplexity + tinySubListComplexity
}
cr.Chapter.Comments = func(childComplexity int, limit *int) int {

29
models/story.go

@ -18,9 +18,36 @@ type Story struct {
SortByFictionalDate bool `bson:"sortByFictionalDate"`
}
func (story *Story) ApplyUpdate(update StoryUpdate) {
if update.Name != nil {
story.Name = *update.Name
}
if update.Category != nil {
story.Category = *update.Category
}
if update.Author != nil {
story.Author = *update.Author
}
if update.Open != nil {
story.Open = *update.Open
}
if update.Listed != nil {
story.Listed = *update.Listed
}
if update.SortByFictionalDate != nil {
story.SortByFictionalDate = *update.SortByFictionalDate
}
if update.FictionalDate != nil {
story.FictionalDate = *update.FictionalDate
}
if update.UpdatedDate != nil {
story.UpdatedDate = *update.UpdatedDate
}
}
// IsChangeObject is an interface implementation to identify it as a valid
// ChangeObject in GQL.
func (*Story) IsChangeObject() {
func (_ *Story) IsChangeObject() {
panic("this method is a dummy, and so is its caller")
}

7
services/characters.go

@ -61,6 +61,13 @@ func (s *CharacterService) List(ctx context.Context, filter models.CharacterFilt
}
sort.Slice(characters, func(i, j int) bool {
if len(characters[i].ID) > len(characters[j].ID) {
return true
}
if len(characters[i].ID) < len(characters[j].ID) {
return false
}
return strings.Compare(characters[i].ID, characters[j].ID) < 0
})

14
services/stories.go

@ -34,6 +34,20 @@ func (s *StoryService) FindComment(ctx context.Context, id string) (*models.Comm
}
func (s *StoryService) ListStories(ctx context.Context, filter models.StoryFilter) ([]*models.Story, error) {
if filter.Unlisted != nil && *filter.Unlisted {
token := s.authService.TokenFromContext(ctx)
if !token.Authenticated() {
return nil, errors.New("you cannot view unlisted stories")
}
if !token.Permitted("story.unlisted") {
if filter.Author == nil {
filter.Author = &token.UserID
} else if *filter.Author != token.UserID {
return nil, errors.New("you cannot view your own unlisted stories")
}
}
}
return s.stories.List(ctx, filter)
}

Loading…
Cancel
Save