thread-master/internal/model/setting/repository/mongo.go

136 lines
3.6 KiB
Go
Raw Normal View History

2026-06-26 08:37:04 +00:00
package repository
import (
"context"
"haixun-backend/internal/library/clock"
app "haixun-backend/internal/library/errors"
"haixun-backend/internal/library/errors/code"
"haixun-backend/internal/model/setting/domain/entity"
domrepo "haixun-backend/internal/model/setting/domain/repository"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type mongoRepository struct {
collection *mongo.Collection
}
func NewMongoRepository(db *mongo.Database) domrepo.Repository {
if db == nil {
return &mongoRepository{}
}
return &mongoRepository{collection: db.Collection(entity.CollectionName)}
}
func (r *mongoRepository) EnsureIndexes(ctx context.Context) error {
if r.collection == nil {
return nil
}
_, err := r.collection.Indexes().CreateOne(ctx, mongo.IndexModel{
Keys: bson.D{{Key: "scope", Value: 1}, {Key: "scope_id", Value: 1}, {Key: "key", Value: 1}},
Options: options.Index().SetUnique(true),
})
return err
}
func (r *mongoRepository) List(ctx context.Context, scope, scopeID string, offset, limit int64) ([]*entity.Setting, int64, error) {
if r.collection == nil {
return nil, 0, app.For(code.Setting).DBUnavailable("Mongo is not configured")
}
filter := bson.M{"scope": scope, "scope_id": scopeID}
total, err := r.collection.CountDocuments(ctx, filter)
if err != nil {
return nil, 0, err
}
cursor, err := r.collection.Find(
ctx,
filter,
options.Find().SetSort(bson.D{{Key: "key", Value: 1}}).SetSkip(offset).SetLimit(limit),
)
if err != nil {
return nil, 0, err
}
defer cursor.Close(ctx)
var items []*entity.Setting
if err := cursor.All(ctx, &items); err != nil {
return nil, 0, err
}
return items, total, nil
}
func (r *mongoRepository) Find(ctx context.Context, scope, scopeID, key string) (*entity.Setting, error) {
if r.collection == nil {
return nil, app.For(code.Setting).DBUnavailable("Mongo is not configured")
}
var item entity.Setting
err := r.collection.FindOne(ctx, identityFilter(scope, scopeID, key)).Decode(&item)
if err == mongo.ErrNoDocuments {
return nil, app.For(code.Setting).ResNotFound("setting not found")
}
if err != nil {
return nil, err
}
return &item, nil
}
func (r *mongoRepository) Upsert(ctx context.Context, setting *entity.Setting) (*entity.Setting, error) {
if r.collection == nil {
return nil, app.For(code.Setting).DBUnavailable("Mongo is not configured")
}
now := clock.NowUnixNano()
setting.UpdateAt = now
if setting.CreateAt == 0 {
setting.CreateAt = now
}
if setting.Version <= 0 {
setting.Version = 1
}
after := options.After
result := r.collection.FindOneAndUpdate(
ctx,
identityFilter(setting.Scope, setting.ScopeID, setting.Key),
bson.M{
"$set": bson.M{
"scope": setting.Scope,
"scope_id": setting.ScopeID,
"key": setting.Key,
"value": setting.Value,
"version": setting.Version,
"update_at": setting.UpdateAt,
},
"$setOnInsert": bson.M{"create_at": setting.CreateAt},
},
&options.FindOneAndUpdateOptions{
Upsert: ptr(true),
ReturnDocument: &after,
},
)
var saved entity.Setting
if err := result.Decode(&saved); err != nil {
return nil, err
}
return &saved, nil
}
func (r *mongoRepository) Delete(ctx context.Context, scope, scopeID, key string) error {
if r.collection == nil {
return app.For(code.Setting).DBUnavailable("Mongo is not configured")
}
_, err := r.collection.DeleteOne(ctx, identityFilter(scope, scopeID, key))
return err
}
func identityFilter(scope, scopeID, key string) bson.M {
return bson.M{"scope": scope, "scope_id": scopeID, "key": key}
}
func ptr[T any](v T) *T {
return &v
}