haixunMaster/haixun-backend/internal/model/content_matrix/repository/mongo.go

106 lines
3.1 KiB
Go
Raw Normal View History

2026-06-24 10:02:42 +00:00
package repository
import (
"context"
"strings"
"haixun-backend/internal/library/clock"
app "haixun-backend/internal/library/errors"
"haixun-backend/internal/library/errors/code"
libmongo "haixun-backend/internal/library/mongo"
"haixun-backend/internal/model/content_matrix/domain/entity"
domrepo "haixun-backend/internal/model/content_matrix/domain/repository"
"github.com/google/uuid"
"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
}
return libmongo.EnsureIndexes(ctx, r.collection, []mongo.IndexModel{
{
Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "brand_id", Value: 1}},
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"brand_id": bson.M{"$gt": ""}})},
{
Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "persona_id", Value: 1}},
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"persona_id": bson.M{"$gt": ""}})},
})
}
func brandOwnerFilter(tenantID, ownerUID, brandID string) bson.M {
filter := bson.M{
"tenant_id": tenantID,
"owner_uid": ownerUID,
}
for k, v := range libmongo.BrandScopeFilter(brandID) {
filter[k] = v
}
return filter
}
func (r *mongoRepository) UpsertByBrand(ctx context.Context, matrix *entity.ContentMatrix) (*entity.ContentMatrix, error) {
if r.collection == nil {
return nil, app.For(code.Brand).DBUnavailable("Mongo is not configured")
}
now := clock.NowUnixNano()
matrix.UpdateAt = now
if matrix.CreateAt == 0 {
matrix.CreateAt = now
}
if strings.TrimSpace(matrix.ID) == "" {
matrix.ID = uuid.NewString()
}
filter := brandOwnerFilter(matrix.TenantID, matrix.OwnerUID, matrix.BrandID)
update := bson.M{
"$set": bson.M{
"rows": matrix.Rows,
"generated_at": matrix.GeneratedAt,
"update_at": matrix.UpdateAt,
"brand_id": matrix.BrandID,
},
"$setOnInsert": bson.M{
"_id": matrix.ID,
"tenant_id": matrix.TenantID,
"owner_uid": matrix.OwnerUID,
"create_at": matrix.CreateAt,
},
}
opts := options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)
var out entity.ContentMatrix
err := r.collection.FindOneAndUpdate(ctx, filter, update, opts).Decode(&out)
if err != nil {
return nil, err
}
return &out, nil
}
func (r *mongoRepository) GetByBrand(ctx context.Context, tenantID, ownerUID, brandID string) (*entity.ContentMatrix, error) {
if r.collection == nil {
return nil, app.For(code.Brand).DBUnavailable("Mongo is not configured")
}
var out entity.ContentMatrix
err := r.collection.FindOne(ctx, brandOwnerFilter(tenantID, ownerUID, brandID)).Decode(&out)
if err == mongo.ErrNoDocuments {
return nil, nil
}
if err != nil {
return nil, err
}
return &out, nil
}