Gisle Aune
4 years ago
32 changed files with 862 additions and 99 deletions
-
25cmd/rpdata-restore/main.go
-
8database/postgres/changes.go
-
2database/postgres/channel.go
-
2database/postgres/chapters.go
-
2database/postgres/character.go
-
2database/postgres/comments.go
-
6database/postgres/db.go
-
246database/postgres/logs.go
-
19database/postgres/migrations/20210327143154_create_table_log.sql
-
20database/postgres/migrations/20210327143158_create_table_post.sql
-
9database/postgres/migrations/20210327160328_create_index_post_search.sql
-
9database/postgres/migrations/20210327160357_create_index_log_open.sql
-
9database/postgres/migrations/20210327160406_create_index_log_characters.sql
-
9database/postgres/migrations/20210327160409_create_index_log_channel_name.sql
-
9database/postgres/migrations/20210327160414_create_index_log_event_name.sql
-
9database/postgres/migrations/20210327160427_create_index_log_date.sql
-
9database/postgres/migrations/20210327160502_create_index_post_kind.sql
-
266database/postgres/posts.go
-
16database/postgres/queries/changes.sql
-
26database/postgres/queries/channels.sql
-
5database/postgres/queries/chapters.sql
-
2database/postgres/queries/characters.sql
-
4database/postgres/queries/comments.sql
-
6database/postgres/queries/counter.sql
-
32database/postgres/queries/logs.sql
-
60database/postgres/queries/posts.sql
-
40database/postgres/queries/stories.sql
-
43database/postgres/queries/tags.sql
-
6database/postgres/stories.go
-
13database/postgres/tags.go
-
20models/log.go
-
15models/post.go
@ -0,0 +1,246 @@ |
|||||
|
package postgres |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"database/sql" |
||||
|
"fmt" |
||||
|
"git.aiterp.net/rpdata/api/database/postgres/psqlcore" |
||||
|
"git.aiterp.net/rpdata/api/internal/generate" |
||||
|
"git.aiterp.net/rpdata/api/models" |
||||
|
"strconv" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
type logRepository struct { |
||||
|
insertWithIDs bool |
||||
|
db *sql.DB |
||||
|
} |
||||
|
|
||||
|
func (r *logRepository) Find(ctx context.Context, id string) (*models.Log, error) { |
||||
|
log, err := psqlcore.New(r.db).SelectLog(ctx, id) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return r.log(log), nil |
||||
|
} |
||||
|
|
||||
|
func (r *logRepository) List(ctx context.Context, filter models.LogFilter) ([]*models.Log, error) { |
||||
|
q := psqlcore.New(r.db) |
||||
|
params := psqlcore.SelectLogsParams{ |
||||
|
LimitSize: 0, |
||||
|
} |
||||
|
|
||||
|
if filter.Search != nil { |
||||
|
ids, err := q.SelectLogIDsFromPostSearch(ctx, *filter.Search) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
params.FilterShortID = true |
||||
|
params.ShortIds = ids |
||||
|
} |
||||
|
if filter.Open != nil { |
||||
|
params.FilterOpen = true |
||||
|
params.Open = *filter.Open |
||||
|
} |
||||
|
if filter.Channels != nil { |
||||
|
params.FilterChannelName = true |
||||
|
params.ChannelNames = filter.Channels |
||||
|
} |
||||
|
if filter.Events != nil { |
||||
|
params.FilterEventName = true |
||||
|
params.EventNames = filter.Events |
||||
|
} |
||||
|
if filter.MinDate != nil { |
||||
|
params.FilterEarlistDate = true |
||||
|
params.EarliestDate = *filter.MinDate |
||||
|
} |
||||
|
if filter.MaxDate != nil { |
||||
|
params.FilterLastestDate = true |
||||
|
params.LatestDate = *filter.MaxDate |
||||
|
} |
||||
|
if filter.Limit > 0 { |
||||
|
params.LimitSize = int32(filter.Limit) |
||||
|
} |
||||
|
|
||||
|
logs, err := q.SelectLogs(ctx, params) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return r.logs(logs), nil |
||||
|
} |
||||
|
|
||||
|
func (r *logRepository) Insert(ctx context.Context, log models.Log) (*models.Log, error) { |
||||
|
tx, err := r.db.BeginTx(ctx, nil) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
defer func() { _ = tx.Rollback() }() |
||||
|
q := psqlcore.New(tx) |
||||
|
|
||||
|
if !r.insertWithIDs || log.ID == "" { |
||||
|
log.ID = generate.LogID(log) |
||||
|
} |
||||
|
|
||||
|
if !r.insertWithIDs || log.ShortID == "" { |
||||
|
next, err := q.IncrementCounter(ctx, "log_short_id") |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
log.ShortID = fmt.Sprintf("L%d", next) |
||||
|
} else { |
||||
|
n, err := strconv.Atoi(log.ShortID[1:]) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
err = q.BumpCounter(ctx, psqlcore.BumpCounterParams{ |
||||
|
ID: "log_short_id", |
||||
|
Value: int32(n), |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
err = q.InsertLog(ctx, psqlcore.InsertLogParams{ |
||||
|
ID: log.ID, |
||||
|
ShortID: log.ShortID, |
||||
|
Date: log.Date.UTC(), |
||||
|
ChannelName: log.ChannelName, |
||||
|
EventName: log.EventName, |
||||
|
Title: log.Title, |
||||
|
Description: log.Description, |
||||
|
Open: log.Open, |
||||
|
CharacterIds: log.CharacterIDs, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
err = tx.Commit() |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
_ = r.updateTags(log) |
||||
|
|
||||
|
return &log, nil |
||||
|
} |
||||
|
|
||||
|
func (r *logRepository) Update(ctx context.Context, log models.Log, update models.LogUpdate) (*models.Log, error) { |
||||
|
log.ApplyUpdate(update) |
||||
|
|
||||
|
err := psqlcore.New(r.db).UpdateLog(ctx, psqlcore.UpdateLogParams{ |
||||
|
Title: log.Title, |
||||
|
EventName: log.EventName, |
||||
|
Description: log.Description, |
||||
|
Open: log.Open, |
||||
|
CharacterIds: log.CharacterIDs, |
||||
|
ID: log.ID, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
_ = r.updateTags(log) |
||||
|
|
||||
|
return &log, nil |
||||
|
} |
||||
|
|
||||
|
func (r *logRepository) Delete(ctx context.Context, log models.Log) error { |
||||
|
tx, err := r.db.BeginTx(ctx, nil) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
defer func() { _ = tx.Rollback() }() |
||||
|
q := psqlcore.New(tx) |
||||
|
|
||||
|
err = q.DeleteLog(ctx, log.ID) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
err = q.DeletePostsByLogShortID(ctx, log.ShortID) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return tx.Commit() |
||||
|
} |
||||
|
|
||||
|
func (r *logRepository) log(log psqlcore.Log) *models.Log { |
||||
|
return &models.Log{ |
||||
|
ID: log.ID, |
||||
|
ShortID: log.ShortID, |
||||
|
Date: log.Date, |
||||
|
ChannelName: log.ChannelName, |
||||
|
EventName: log.EventName, |
||||
|
Title: log.Title, |
||||
|
Description: log.Description, |
||||
|
Open: log.Open, |
||||
|
CharacterIDs: log.CharacterIds, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (r *logRepository) logs(logs []psqlcore.Log) []*models.Log { |
||||
|
results := make([]*models.Log, 0, len(logs)) |
||||
|
for _, log := range logs { |
||||
|
results = append(results, r.log(log)) |
||||
|
} |
||||
|
|
||||
|
return results |
||||
|
} |
||||
|
|
||||
|
func (r *logRepository) updateTags(log models.Log) error { |
||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second) |
||||
|
defer cancel() |
||||
|
|
||||
|
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{TargetKind: "Log", TargetID: log.ID}) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
if len(log.CharacterIDs) > 0 { |
||||
|
err := q.SetCharacterTagsFromIDs(ctx, psqlcore.SetCharacterTagsFromIDsParams{ |
||||
|
TargetKind: "log", |
||||
|
TargetID: log.ID, |
||||
|
CharacterIds: log.CharacterIDs, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
err = q.SetLocationTagFromChannelName(ctx, psqlcore.SetLocationTagFromChannelNameParams{ |
||||
|
TargetKind: "log", |
||||
|
TargetID: log.ID, |
||||
|
ChannelName: log.ChannelName, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
if log.EventName != "" { |
||||
|
err := q.SetTag(ctx, psqlcore.SetTagParams{ |
||||
|
Tag: "Event:" + log.EventName, |
||||
|
TargetKind: "Log", |
||||
|
TargetID: log.ID, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return tx.Commit() |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE TABLE log ( |
||||
|
id TEXT NOT NULL PRIMARY KEY, |
||||
|
short_id TEXT NOT NULL UNIQUE, |
||||
|
character_ids TEXT[] NOT NULL, |
||||
|
date TIMESTAMP NOT NULL, |
||||
|
channel_name TEXT NOT NULL, |
||||
|
event_name TEXT NOT NULL, |
||||
|
title TEXT NOT NULL, |
||||
|
description TEXT NOT NULL, |
||||
|
open BOOLEAN NOT NULL |
||||
|
); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP TABLE log; |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,20 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE TABLE log_post ( |
||||
|
id TEXT NOT NULL PRIMARY KEY, |
||||
|
log_short_id TEXT NOT NULL, |
||||
|
time TIMESTAMP NOT NULL, |
||||
|
kind TEXT NOT NULL, |
||||
|
nick TEXT NOT NULL, |
||||
|
text TEXT NOT NULL, |
||||
|
position INT NOT NULL, |
||||
|
ts_vector TSVECTOR NOT NULL, |
||||
|
|
||||
|
UNIQUE (log_short_id, position) |
||||
|
); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP TABLE log_post; |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,9 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE INDEX log_post_index_search ON log_post USING GIN (ts_vector); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP INDEX IF EXISTS log_post_index_search; |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,9 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE INDEX log_index_open ON log (open); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP INDEX IF EXISTS log_index_open |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,9 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE INDEX log_index_character_ids on log USING GIN (character_ids); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP INDEX IF EXISTS log_index_character_ids; |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,9 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE INDEX log_index_channel_name ON log (channel_name); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP INDEX IF EXISTS log_index_channel_name |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,9 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE INDEX log_index_event_name ON log (event_name); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP INDEX IF EXISTS log_index_event_name |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,9 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE INDEX log_index_date ON log (date); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP INDEX IF EXISTS log_index_date |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,9 @@ |
|||||
|
-- +goose Up |
||||
|
-- +goose StatementBegin |
||||
|
CREATE INDEX log_post_index_kind ON log_post (kind); |
||||
|
-- +goose StatementEnd |
||||
|
|
||||
|
-- +goose Down |
||||
|
-- +goose StatementBegin |
||||
|
DROP INDEX IF EXISTS log_post_index_kind |
||||
|
-- +goose StatementEnd |
@ -0,0 +1,266 @@ |
|||||
|
package postgres |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"database/sql" |
||||
|
"errors" |
||||
|
"git.aiterp.net/rpdata/api/database/postgres/psqlcore" |
||||
|
"git.aiterp.net/rpdata/api/internal/generate" |
||||
|
"git.aiterp.net/rpdata/api/models" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
type postRepository struct { |
||||
|
insertWithIDs bool |
||||
|
db *sql.DB |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) Find(ctx context.Context, id string) (*models.Post, error) { |
||||
|
post, err := psqlcore.New(r.db).SelectPost(ctx, id) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return r.post(post), nil |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) List(ctx context.Context, filter models.PostFilter) ([]*models.Post, error) { |
||||
|
q := psqlcore.New(r.db) |
||||
|
params := psqlcore.SelectPostsParams{LimitSize: 0} |
||||
|
if filter.LogID != nil { |
||||
|
params.FilterLogShortID = true |
||||
|
|
||||
|
if !strings.HasPrefix(*filter.LogID, "L") { |
||||
|
log, err := q.SelectLog(ctx, *filter.LogID) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
params.LogShortID = log.ShortID |
||||
|
} else { |
||||
|
params.LogShortID = *filter.LogID |
||||
|
} |
||||
|
} |
||||
|
if filter.Kinds != nil { |
||||
|
params.FilterKinds = true |
||||
|
params.Kinds = filter.Kinds |
||||
|
} |
||||
|
if filter.Search != nil { |
||||
|
params.FilterSearch = true |
||||
|
params.Search = *filter.Search |
||||
|
} |
||||
|
if filter.Limit > 0 { |
||||
|
params.LimitSize = int32(filter.Limit) |
||||
|
} |
||||
|
|
||||
|
posts, err := q.SelectPosts(ctx, params) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return r.posts(posts), nil |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) Insert(ctx context.Context, post models.Post) (*models.Post, error) { |
||||
|
if !r.insertWithIDs || len(post.ID) < 8 { |
||||
|
post.ID = generate.PostID() |
||||
|
} |
||||
|
|
||||
|
position, err := psqlcore.New(r.db).InsertPost(ctx, psqlcore.InsertPostParams{ |
||||
|
ID: post.ID, |
||||
|
LogShortID: post.LogID, |
||||
|
Time: post.Time.UTC(), |
||||
|
Kind: post.Kind, |
||||
|
Nick: post.Nick, |
||||
|
Text: post.Text, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
post.Position = int(position) |
||||
|
|
||||
|
return &post, nil |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) InsertMany(ctx context.Context, posts ...*models.Post) ([]*models.Post, error) { |
||||
|
allowedLogID := "" |
||||
|
for _, post := range posts { |
||||
|
if allowedLogID == "" { |
||||
|
allowedLogID = post.LogID |
||||
|
} else if allowedLogID != post.LogID { |
||||
|
return nil, errors.New("cannot insert multiple posts with different log IDs") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
params := psqlcore.InsertPostsParams{ |
||||
|
LogShortID: posts[0].LogID, |
||||
|
} |
||||
|
|
||||
|
for _, post := range posts { |
||||
|
if !r.insertWithIDs || len(post.ID) < 8 { |
||||
|
post.ID = generate.PostID() |
||||
|
} |
||||
|
|
||||
|
params.Ids = append(params.Ids, post.ID) |
||||
|
params.Kinds = append(params.Kinds, post.Kind) |
||||
|
params.Nicks = append(params.Nicks, post.Nick) |
||||
|
params.Offsets = append(params.Offsets, int32(len(params.Offsets)+1)) |
||||
|
params.Times = append(params.Times, post.Time.UTC()) |
||||
|
params.Texts = append(params.Texts, post.Text) |
||||
|
} |
||||
|
|
||||
|
offset, err := psqlcore.New(r.db).InsertPosts(ctx, params) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
for i, post := range posts { |
||||
|
post.Position = int(offset) + i |
||||
|
} |
||||
|
|
||||
|
return posts, nil |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) Update(ctx context.Context, post models.Post, update models.PostUpdate) (*models.Post, error) { |
||||
|
post.ApplyUpdate(update) |
||||
|
|
||||
|
err := psqlcore.New(r.db).UpdatePost(ctx, psqlcore.UpdatePostParams{ |
||||
|
Time: post.Time, |
||||
|
Kind: post.Kind, |
||||
|
Nick: post.Nick, |
||||
|
Text: post.Text, |
||||
|
ID: post.ID, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return &post, nil |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) Move(ctx context.Context, post models.Post, position int) ([]*models.Post, error) { |
||||
|
if position == post.Position { |
||||
|
return r.List(ctx, models.PostFilter{LogID: &post.LogID}) |
||||
|
} |
||||
|
|
||||
|
tx, err := r.db.BeginTx(ctx, nil) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
defer func() { _ = tx.Rollback() }() |
||||
|
|
||||
|
_, err = tx.Exec("LOCK TABLE log_post IN SHARE UPDATE EXCLUSIVE MODE") |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
var lowest, highest int32 |
||||
|
|
||||
|
q := psqlcore.New(tx) |
||||
|
|
||||
|
err = q.MovePost(ctx, psqlcore.MovePostParams{ID: post.ID, Position: -1}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
if position > post.Position { |
||||
|
lowest = int32(post.Position) |
||||
|
highest = int32(position) |
||||
|
|
||||
|
err := q.ShiftPostsBetween(ctx, psqlcore.ShiftPostsBetweenParams{ |
||||
|
ShiftOffset: -1, |
||||
|
LogShortID: post.LogID, |
||||
|
FromPosition: lowest + 1, |
||||
|
ToPosition: highest, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
} else { |
||||
|
lowest = int32(position) |
||||
|
highest = int32(post.Position) |
||||
|
|
||||
|
err := q.ShiftPostsBetween(ctx, psqlcore.ShiftPostsBetweenParams{ |
||||
|
ShiftOffset: 1, |
||||
|
LogShortID: post.LogID, |
||||
|
FromPosition: lowest, |
||||
|
ToPosition: highest - 1, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
err = q.MovePost(ctx, psqlcore.MovePostParams{ID: post.ID, Position: int32(position)}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
posts, err := q.SelectPostsByPositionRange(ctx, psqlcore.SelectPostsByPositionRangeParams{ |
||||
|
LogShortID: post.LogID, |
||||
|
FromPosition: lowest, |
||||
|
ToPosition: highest, |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
err = tx.Commit() |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return r.posts(posts), nil |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) Delete(ctx context.Context, post models.Post) error { |
||||
|
tx, err := r.db.BeginTx(ctx, nil) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
defer func() { _ = tx.Rollback() }() |
||||
|
q := psqlcore.New(tx) |
||||
|
|
||||
|
_, err = tx.Exec("LOCK TABLE log_post IN SHARE UPDATE EXCLUSIVE MODE") |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
err = q.DeletePost(ctx, post.ID) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
err = q.ShiftPostsAfter(ctx, psqlcore.ShiftPostsAfterParams{ |
||||
|
ShiftOffset: -1, |
||||
|
LogShortID: post.LogID, |
||||
|
FromPosition: int32(post.Position + 1), |
||||
|
}) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return tx.Commit() |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) post(post psqlcore.LogPost) *models.Post { |
||||
|
return &models.Post{ |
||||
|
ID: post.ID, |
||||
|
LogID: post.LogShortID, |
||||
|
Time: post.Time, |
||||
|
Kind: post.Kind, |
||||
|
Nick: post.Nick, |
||||
|
Text: post.Text, |
||||
|
Position: int(post.Position), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (r *postRepository) posts(posts []psqlcore.LogPost) []*models.Post { |
||||
|
results := make([]*models.Post, 0, len(posts)) |
||||
|
for _, post := range posts { |
||||
|
results = append(results, r.post(post)) |
||||
|
} |
||||
|
|
||||
|
return results |
||||
|
} |
@ -1,8 +1,8 @@ |
|||||
-- name: EnsureCounter :exec |
-- name: EnsureCounter :exec |
||||
INSERT INTO core_counter (id, value) VALUES ($1::text, 0) ON CONFLICT DO NOTHING; |
|
||||
|
INSERT INTO core_counter (id, value) VALUES (@id::text, 0) ON CONFLICT DO NOTHING; |
||||
|
|
||||
-- name: IncrementCounter :one |
-- name: IncrementCounter :one |
||||
UPDATE core_counter SET value = value + 1 WHERE id = $1::text RETURNING value::int; |
|
||||
|
UPDATE core_counter SET value = value + 1 WHERE id = @id::text RETURNING value::int; |
||||
|
|
||||
-- name: BumpCounter :exec |
-- name: BumpCounter :exec |
||||
UPDATE core_counter SET value = value + 1 WHERE id = sqlc.arg(id)::text AND value <= sqlc.arg(value)::int; |
|
||||
|
UPDATE core_counter SET value = value + 1 WHERE id = @id::text AND value <= @value::int; |
@ -0,0 +1,32 @@ |
|||||
|
-- name: SelectLog :one |
||||
|
SELECT * FROM log WHERE id=$1 OR short_id=$1 LIMIT 1; |
||||
|
|
||||
|
-- name: SelectLogs :many |
||||
|
SELECT * FROM log |
||||
|
WHERE (@filter_short_id::BOOL = false OR short_id = ANY(@short_ids::TEXT[])) |
||||
|
AND (@filter_character_id::BOOL = false OR character_ids && (@character_ids::TEXT[])) |
||||
|
AND (@filter_channel_name::BOOL = false OR channel_name = ANY(@channel_names::TEXT[])) |
||||
|
AND (@filter_event_name::BOOL = false OR event_name = ANY(@event_names::TEXT[])) |
||||
|
AND (@filter_open::BOOL = false OR open = @open::BOOL) |
||||
|
AND (@filter_earlist_date::BOOL = false OR date >= @earliest_date::TIMESTAMP) |
||||
|
AND (@filter_lastest_date::BOOL = false OR date <= @latest_date::TIMESTAMP) |
||||
|
ORDER BY date |
||||
|
LIMIT NULLIF(@limit_size::INT, 0); |
||||
|
|
||||
|
-- name: InsertLog :exec |
||||
|
INSERT INTO log (id, short_id, character_ids, date, channel_name, event_name, title, description, open) |
||||
|
VALUES ( |
||||
|
@id, @short_id, @character_ids, @date, @channel_name, @event_name, @title, @description, @open |
||||
|
); |
||||
|
|
||||
|
-- name: UpdateLog :exec |
||||
|
UPDATE log |
||||
|
SET title = @title, |
||||
|
event_name = @event_name, |
||||
|
description = @description, |
||||
|
open = @open, |
||||
|
character_ids = @character_ids |
||||
|
WHERE id = @id; |
||||
|
|
||||
|
-- name: DeleteLog :exec |
||||
|
DELETE FROM log WHERE id=$1; |
@ -0,0 +1,60 @@ |
|||||
|
-- name: SelectPost :one |
||||
|
SELECT * FROM log_post WHERE id=$1 LIMIT 1; |
||||
|
|
||||
|
-- name: SelectLogIDsFromPostSearch :many |
||||
|
SELECT DISTINCT(log_short_id) FROM log_post WHERE "ts_vector" @@ to_tsquery(@search::TEXT); |
||||
|
|
||||
|
-- name: SelectPostsByPositionRange :many |
||||
|
SELECT * FROM log_post WHERE log_short_id = @log_short_id AND position >= @from_position AND position = @to_position; |
||||
|
|
||||
|
-- name: SelectPosts :many |
||||
|
SELECT * FROM log_post |
||||
|
WHERE (@filter_ids::BOOL = false OR id = ANY(@ids::TEXT[])) |
||||
|
AND (@filter_kinds::BOOL = false OR kind = ANY(@kinds::TEXT[])) |
||||
|
AND (@filter_log_short_id::BOOL = false OR log_short_id = @log_short_id) |
||||
|
AND (@filter_search::BOOL = false OR "ts_vector" @@ to_tsquery(@search::TEXT)) |
||||
|
ORDER BY log_short_id, position |
||||
|
LIMIT NULLIF(@limit_size::INT, 0); |
||||
|
|
||||
|
-- name: InsertPost :one |
||||
|
INSERT INTO log_post (id, log_short_id, time, kind, nick, text, position, ts_vector) |
||||
|
SELECT @id, @log_short_id, @time, @kind, @nick, @text, COALESCE(MAX(position), 0)+1, to_tsvector(@nick || ' ' || @text) |
||||
|
FROM log_post |
||||
|
WHERE log_short_id=@log_short_id |
||||
|
RETURNING position; |
||||
|
|
||||
|
-- name: InsertPosts :one |
||||
|
INSERT INTO log_post (id, log_short_id, time, kind, nick, text, position, ts_vector) |
||||
|
SELECT UNNEST(@ids::TEXT[]), @log_short_id, UNNEST(@times::TIMESTAMP[]), UNNEST(@kinds::TEXT[]), |
||||
|
UNNEST(@nicks::TEXT[]), UNNEST(@texts::TEXT[]), COALESCE(MAX(position), 1) + UNNEST(@offsets::INT[]), |
||||
|
to_tsvector(UNNEST(@nicks::TEXT[]) || ' ' || UNNEST(@texts::TEXT[])) |
||||
|
FROM log_post |
||||
|
WHERE log_short_id = @log_short_id |
||||
|
RETURNING position; |
||||
|
|
||||
|
-- name: UpdatePost :exec |
||||
|
UPDATE log_post |
||||
|
SET time = @time, |
||||
|
kind = @kind, |
||||
|
nick = @nick, |
||||
|
text = @text, |
||||
|
ts_vector = to_tsvector(@nick || ' ' || @text) |
||||
|
WHERE id = @id; |
||||
|
|
||||
|
-- name: MovePost :exec |
||||
|
UPDATE log_post SET position = @position WHERE id = @id; |
||||
|
|
||||
|
-- name: ShiftPostsBetween :exec |
||||
|
UPDATE log_post SET position = position + @shift_offset::INT WHERE log_short_id = @log_short_id AND position >= @from_position AND position <= @to_position; |
||||
|
|
||||
|
-- name: ShiftPostsAfter :exec |
||||
|
UPDATE log_post SET position = position + @shift_offset::INT WHERE log_short_id = @log_short_id AND position >= @from_position; |
||||
|
|
||||
|
-- name: ShiftPostsBefore :exec |
||||
|
UPDATE log_post SET position = position + @shift_offset::INT WHERE log_short_id = @log_short_id AND position <= @to_position; |
||||
|
|
||||
|
-- name: DeletePost :exec |
||||
|
DELETE FROM log_post WHERE id = @id; |
||||
|
|
||||
|
-- name: DeletePostsByLogShortID :exec |
||||
|
DELETE FROM log_post WHERE log_short_id = @log_short_id; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue