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)
|