178 lines
5.1 KiB
Go
178 lines
5.1 KiB
Go
|
|
package repository
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
|
|||
|
|
libmongo "apps/backend/internal/lib/mongo"
|
|||
|
|
"apps/backend/internal/module/inspire/domain"
|
|||
|
|
|
|||
|
|
"github.com/zeromicro/go-zero/core/stores/mon"
|
|||
|
|
"go.mongodb.org/mongo-driver/bson"
|
|||
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
type MonStore struct {
|
|||
|
|
trends *mon.Model
|
|||
|
|
elements *mon.Model
|
|||
|
|
sessions *mon.Model
|
|||
|
|
active *mon.Model // inspire_session_active: _id=owner_uid, session_id
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func NewMonStore(uri, database string) *MonStore {
|
|||
|
|
uri = libmongo.MustMongoURI(uri)
|
|||
|
|
return &MonStore{
|
|||
|
|
trends: mon.MustNewModel(uri, database, "inspire_trends"),
|
|||
|
|
elements: mon.MustNewModel(uri, database, "inspire_elements"),
|
|||
|
|
sessions: mon.MustNewModel(uri, database, "inspire_sessions"),
|
|||
|
|
active: mon.MustNewModel(uri, database, "inspire_session_active"),
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type trendBag struct {
|
|||
|
|
OwnerUID int64 `bson:"_id"`
|
|||
|
|
Items []*domain.TrendItem `bson:"items"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type activeRef struct {
|
|||
|
|
OwnerUID int64 `bson:"_id"`
|
|||
|
|
SessionID string `bson:"session_id"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) ListTrends(ctx context.Context, ownerUID int64) ([]*domain.TrendItem, error) {
|
|||
|
|
var bag trendBag
|
|||
|
|
err := s.trends.FindOne(ctx, &bag, bson.M{"_id": ownerUID})
|
|||
|
|
if err != nil {
|
|||
|
|
if err == mon.ErrNotFound {
|
|||
|
|
return nil, nil
|
|||
|
|
}
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return bag.Items, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) SaveTrends(ctx context.Context, ownerUID int64, items []*domain.TrendItem) error {
|
|||
|
|
bag := trendBag{OwnerUID: ownerUID, Items: items}
|
|||
|
|
_, err := s.trends.ReplaceOne(ctx, bson.M{"_id": ownerUID}, bag, options.Replace().SetUpsert(true))
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) ListElements(ctx context.Context, ownerUID int64) ([]*domain.Element, error) {
|
|||
|
|
var list []*domain.Element
|
|||
|
|
err := s.elements.Find(ctx, &list, bson.M{"owner_uid": ownerUID},
|
|||
|
|
options.Find().SetSort(bson.D{{Key: "updated_at", Value: -1}}))
|
|||
|
|
return list, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) SaveElement(ctx context.Context, e *domain.Element) error {
|
|||
|
|
_, err := s.elements.ReplaceOne(ctx, bson.M{"_id": e.ID}, e, options.Replace().SetUpsert(true))
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) DeleteElement(ctx context.Context, id string) error {
|
|||
|
|
res, err := s.elements.DeleteOne(ctx, bson.M{"_id": id})
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
if res == 0 {
|
|||
|
|
return domain.ErrNotFound
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) GetElement(ctx context.Context, id string) (*domain.Element, error) {
|
|||
|
|
var e domain.Element
|
|||
|
|
err := s.elements.FindOne(ctx, &e, bson.M{"_id": id})
|
|||
|
|
if err != nil {
|
|||
|
|
if err == mon.ErrNotFound {
|
|||
|
|
return nil, domain.ErrNotFound
|
|||
|
|
}
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return &e, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) ListSessions(ctx context.Context, ownerUID int64) ([]*domain.Session, error) {
|
|||
|
|
var list []*domain.Session
|
|||
|
|
err := s.sessions.Find(ctx, &list, bson.M{"owner_uid": ownerUID},
|
|||
|
|
options.Find().SetSort(bson.D{{Key: "updated_at", Value: -1}}).SetLimit(50))
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return list, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetSession — active;無 active/失效則取最近一則;都沒有回 NotFound(usecase 建新)。
|
|||
|
|
func (s *MonStore) GetSession(ctx context.Context, ownerUID int64) (*domain.Session, error) {
|
|||
|
|
if id, err := s.GetActiveSessionID(ctx, ownerUID); err == nil && id != "" {
|
|||
|
|
if sess, gerr := s.GetSessionByID(ctx, ownerUID, id); gerr == nil {
|
|||
|
|
return sess, nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// fallback:最近更新
|
|||
|
|
var list []*domain.Session
|
|||
|
|
err := s.sessions.Find(ctx, &list, bson.M{"owner_uid": ownerUID},
|
|||
|
|
options.Find().SetSort(bson.D{{Key: "updated_at", Value: -1}}).SetLimit(1))
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
if len(list) == 0 {
|
|||
|
|
return nil, domain.ErrNotFound
|
|||
|
|
}
|
|||
|
|
_ = s.SetActiveSessionID(ctx, ownerUID, list[0].ID)
|
|||
|
|
return list[0], nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) GetSessionByID(ctx context.Context, ownerUID int64, id string) (*domain.Session, error) {
|
|||
|
|
var sess domain.Session
|
|||
|
|
err := s.sessions.FindOne(ctx, &sess, bson.M{"_id": id, "owner_uid": ownerUID})
|
|||
|
|
if err != nil {
|
|||
|
|
if err == mon.ErrNotFound {
|
|||
|
|
return nil, domain.ErrNotFound
|
|||
|
|
}
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return &sess, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) SaveSession(ctx context.Context, sess *domain.Session) error {
|
|||
|
|
// 用 _id + owner_uid:多 session 且禁止覆寫別人的對話
|
|||
|
|
_, err := s.sessions.ReplaceOne(
|
|||
|
|
ctx,
|
|||
|
|
bson.M{"_id": sess.ID, "owner_uid": sess.OwnerUID},
|
|||
|
|
sess,
|
|||
|
|
options.Replace().SetUpsert(true),
|
|||
|
|
)
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) DeleteSessionByID(ctx context.Context, ownerUID int64, id string) error {
|
|||
|
|
res, err := s.sessions.DeleteOne(ctx, bson.M{"_id": id, "owner_uid": ownerUID})
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
if res == 0 {
|
|||
|
|
return domain.ErrNotFound
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) GetActiveSessionID(ctx context.Context, ownerUID int64) (string, error) {
|
|||
|
|
var ref activeRef
|
|||
|
|
err := s.active.FindOne(ctx, &ref, bson.M{"_id": ownerUID})
|
|||
|
|
if err != nil {
|
|||
|
|
if err == mon.ErrNotFound {
|
|||
|
|
return "", domain.ErrNotFound
|
|||
|
|
}
|
|||
|
|
return "", err
|
|||
|
|
}
|
|||
|
|
return ref.SessionID, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (s *MonStore) SetActiveSessionID(ctx context.Context, ownerUID int64, sessionID string) error {
|
|||
|
|
ref := activeRef{OwnerUID: ownerUID, SessionID: sessionID}
|
|||
|
|
_, err := s.active.ReplaceOne(ctx, bson.M{"_id": ownerUID}, ref, options.Replace().SetUpsert(true))
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var _ domain.Repository = (*MonStore)(nil)
|