package repository import ( "context" "strings" app "haixun-backend/internal/library/errors" "haixun-backend/internal/library/errors/code" "haixun-backend/internal/model/publish_analytics/domain/entity" domrepo "haixun-backend/internal/model/publish_analytics/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().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.D{ {Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "media_id", Value: 1}, {Key: "checkpoint", Value: 1}, }, }, }) return err } func actorFilter(tenantID, ownerUID string) bson.M { return bson.M{ "tenant_id": strings.TrimSpace(tenantID), "owner_uid": strings.TrimSpace(ownerUID), } } func (r *mongoRepository) Create(ctx context.Context, analytics *entity.PublishAnalytics) error { if r.collection == nil { return app.For(code.AI).DBUnavailable("Mongo is not configured") } if analytics == nil { return app.For(code.AI).InputMissingRequired("analytics is required") } _, err := r.collection.InsertOne(ctx, analytics) return err } func (r *mongoRepository) Get(ctx context.Context, tenantID, ownerUID, analyticsID string) (*entity.PublishAnalytics, error) { if r.collection == nil { return nil, app.For(code.AI).DBUnavailable("Mongo is not configured") } analyticsID = strings.TrimSpace(analyticsID) if analyticsID == "" { return nil, app.For(code.AI).InputMissingRequired("analytics_id is required") } filter := actorFilter(tenantID, ownerUID) filter["_id"] = analyticsID var out entity.PublishAnalytics err := r.collection.FindOne(ctx, filter).Decode(&out) if err != nil { if err == mongo.ErrNoDocuments { return nil, app.For(code.AI).ResNotFound("publish analytics not found") } return nil, err } return &out, nil } func (r *mongoRepository) ListByMedia(ctx context.Context, tenantID, ownerUID, mediaID string) ([]entity.PublishAnalytics, error) { if r.collection == nil { return nil, app.For(code.AI).DBUnavailable("Mongo is not configured") } mediaID = strings.TrimSpace(mediaID) if mediaID == "" { return nil, app.For(code.AI).InputMissingRequired("media_id is required") } filter := actorFilter(tenantID, ownerUID) filter["media_id"] = mediaID opts := options.Find().SetSort(bson.D{{Key: "checked_at", Value: -1}}) cur, err := r.collection.Find(ctx, filter, opts) if err != nil { return nil, err } defer cur.Close(ctx) var out []entity.PublishAnalytics if err := cur.All(ctx, &out); err != nil { return nil, err } return out, nil } func (r *mongoRepository) Upsert(ctx context.Context, analytics *entity.PublishAnalytics) (*entity.PublishAnalytics, error) { if r.collection == nil { return nil, app.For(code.AI).DBUnavailable("Mongo is not configured") } if analytics == nil { return nil, app.For(code.AI).InputMissingRequired("analytics is required") } if analytics.ID == "" { return nil, app.For(code.AI).InputMissingRequired("analytics id is required") } filter := bson.M{"_id": analytics.ID} opts := options.Replace().SetUpsert(true) _, err := r.collection.ReplaceOne(ctx, filter, analytics, opts) if err != nil { return nil, err } return analytics, nil }