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 { params.FilterSearch = true params.Search = TSQueryFromSearch(*filter.Search) } if filter.Open != nil { params.FilterOpen = true params.Open = *filter.Open } if len(filter.Characters) > 0 { params.FilterCharacterID = true params.CharacterIds = filter.Characters } if len(filter.Channels) > 0 { params.FilterChannelName = true params.ChannelNames = filter.Channels } if len(filter.Events) > 0 { 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 } } if log.CharacterIDs == nil { log.CharacterIDs = []string{} } 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.SelectLogRow) *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.SelectLogsRow) []*models.Log { results := make([]*models.Log, 0, len(logs)) for _, log := range logs { results = append(results, r.log(psqlcore.SelectLogRow(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() }