owpengram-server/internal/store/postgres/langpack.go
2026-06-04 01:37:39 +08:00

169 lines
4.7 KiB
Go

package postgres
import (
"context"
"errors"
"fmt"
"github.com/jackc/pgx/v5"
"telesrv/internal/domain"
"telesrv/internal/store/postgres/sqlcgen"
)
// LangPackStore 用 PostgreSQL 实现 store.LangPackStore。
type LangPackStore struct {
db sqlcgen.DBTX
q *sqlcgen.Queries
}
// NewLangPackStore 基于 pgx 连接池(或事务)创建 LangPackStore。
func NewLangPackStore(db sqlcgen.DBTX) *LangPackStore {
return &LangPackStore{db: db, q: sqlcgen.New(db)}
}
func (s *LangPackStore) GetPack(ctx context.Context, langPack, langCode string, fromVersion int) (domain.LangPack, error) {
meta, found, err := s.meta(ctx, langPack, langCode)
if err != nil || !found {
return meta, err
}
meta.FromVersion = fromVersion
if meta.Version <= fromVersion {
return meta, nil
}
rows, err := s.q.ListLangPackStrings(ctx, sqlcgen.ListLangPackStringsParams{
LangPack: langPack,
LangCode: langCode,
})
if err != nil {
return domain.LangPack{}, fmt.Errorf("list lang pack strings: %w", err)
}
meta.Strings = make([]domain.LangPackString, 0, len(rows))
for _, row := range rows {
meta.Strings = append(meta.Strings, langPackStringFromListRow(row))
}
return meta, nil
}
func (s *LangPackStore) GetStrings(ctx context.Context, langPack, langCode string, keys []string) (domain.LangPack, error) {
meta, found, err := s.meta(ctx, langPack, langCode)
if err != nil || !found {
return meta, err
}
if len(keys) == 0 {
return s.GetPack(ctx, langPack, langCode, 0)
}
rows, err := s.q.GetLangPackStringsByKeys(ctx, sqlcgen.GetLangPackStringsByKeysParams{
LangPack: langPack,
LangCode: langCode,
Keys: keys,
})
if err != nil {
return domain.LangPack{}, fmt.Errorf("get lang pack strings: %w", err)
}
meta.Strings = make([]domain.LangPackString, 0, len(rows))
for _, row := range rows {
meta.Strings = append(meta.Strings, langPackStringFromKeysRow(row))
}
return meta, nil
}
func (s *LangPackStore) UpsertPack(ctx context.Context, pack domain.LangPack) error {
if txer, ok := s.db.(interface {
Begin(context.Context) (pgx.Tx, error)
}); ok {
tx, err := txer.Begin(ctx)
if err != nil {
return fmt.Errorf("begin lang pack upsert: %w", err)
}
q := s.q.WithTx(tx)
if err := upsertPackWith(ctx, q, pack); err != nil {
_ = tx.Rollback(ctx)
return err
}
if err := tx.Commit(ctx); err != nil {
return fmt.Errorf("commit lang pack upsert: %w", err)
}
return nil
}
return upsertPackWith(ctx, s.q, pack)
}
func upsertPackWith(ctx context.Context, q *sqlcgen.Queries, pack domain.LangPack) error {
if err := q.UpsertLangPackMeta(ctx, sqlcgen.UpsertLangPackMetaParams{
LangPack: pack.LangPack,
LangCode: pack.LangCode,
Version: int32(pack.Version),
StringsCount: int32(len(pack.Strings)),
}); err != nil {
return fmt.Errorf("upsert lang pack meta: %w", err)
}
for _, item := range pack.Strings {
if err := q.UpsertLangPackString(ctx, sqlcgen.UpsertLangPackStringParams{
LangPack: pack.LangPack,
LangCode: pack.LangCode,
Key: item.Key,
Version: int32(pack.Version),
Pluralized: item.Pluralized,
Value: item.Value,
ZeroValue: item.ZeroValue,
OneValue: item.OneValue,
TwoValue: item.TwoValue,
FewValue: item.FewValue,
ManyValue: item.ManyValue,
OtherValue: item.OtherValue,
Deleted: item.Deleted,
}); err != nil {
return fmt.Errorf("upsert lang pack string %q: %w", item.Key, err)
}
}
return nil
}
func (s *LangPackStore) meta(ctx context.Context, langPack, langCode string) (domain.LangPack, bool, error) {
row, err := s.q.GetLangPackMeta(ctx, sqlcgen.GetLangPackMetaParams{
LangPack: langPack,
LangCode: langCode,
})
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.LangPack{LangPack: langPack, LangCode: langCode}, false, nil
}
return domain.LangPack{}, false, fmt.Errorf("get lang pack meta: %w", err)
}
return domain.LangPack{
LangPack: row.LangPack,
LangCode: row.LangCode,
Version: int(row.Version),
}, true, nil
}
func langPackStringFromListRow(row sqlcgen.ListLangPackStringsRow) domain.LangPackString {
return domain.LangPackString{
Key: row.Key,
Value: row.Value,
Pluralized: row.Pluralized,
ZeroValue: row.ZeroValue,
OneValue: row.OneValue,
TwoValue: row.TwoValue,
FewValue: row.FewValue,
ManyValue: row.ManyValue,
OtherValue: row.OtherValue,
Deleted: row.Deleted,
}
}
func langPackStringFromKeysRow(row sqlcgen.GetLangPackStringsByKeysRow) domain.LangPackString {
return domain.LangPackString{
Key: row.Key,
Value: row.Value,
Pluralized: row.Pluralized,
ZeroValue: row.ZeroValue,
OneValue: row.OneValue,
TwoValue: row.TwoValue,
FewValue: row.FewValue,
ManyValue: row.ManyValue,
OtherValue: row.OtherValue,
Deleted: row.Deleted,
}
}