136 lines
3.6 KiB
Go
136 lines
3.6 KiB
Go
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
|
|
}
|