package repository import ( "context" "strings" "haixun-backend/internal/library/clock" app "haixun-backend/internal/library/errors" "haixun-backend/internal/library/errors/code" "haixun-backend/internal/model/copy_mission/domain/entity" domrepo "haixun-backend/internal/model/copy_mission/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: "persona_id", Value: 1}, {Key: "update_at", Value: -1}}}, {Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "persona_id", Value: 1}, {Key: "_id", Value: 1}}, Options: options.Index().SetUnique(true)}, }) return err } func (r *mongoRepository) Create(ctx context.Context, mission *entity.Mission) (*entity.Mission, error) { if r.collection == nil { return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured") } now := clock.NowUnixNano() mission.CreateAt = now mission.UpdateAt = now if mission.Status == "" { mission.Status = entity.StatusOpen } _, err := r.collection.InsertOne(ctx, mission) if err != nil { return nil, err } return mission, nil } func (r *mongoRepository) FindByID(ctx context.Context, tenantID, ownerUID, personaID, missionID string) (*entity.Mission, error) { return r.findOne(ctx, bson.M{ "_id": strings.TrimSpace(missionID), "tenant_id": tenantID, "owner_uid": ownerUID, "persona_id": strings.TrimSpace(personaID), "status": bson.M{"$ne": entity.StatusDeleted}, }) } func (r *mongoRepository) ListByPersona(ctx context.Context, tenantID, ownerUID, personaID string) ([]*entity.Mission, error) { if r.collection == nil { return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured") } cursor, err := r.collection.Find( ctx, bson.M{ "tenant_id": tenantID, "owner_uid": ownerUID, "persona_id": strings.TrimSpace(personaID), "status": bson.M{"$ne": entity.StatusDeleted}, }, options.Find().SetSort(bson.D{{Key: "update_at", Value: -1}}), ) if err != nil { return nil, err } defer cursor.Close(ctx) var items []*entity.Mission if err := cursor.All(ctx, &items); err != nil { return nil, err } return items, nil } func (r *mongoRepository) Update(ctx context.Context, tenantID, ownerUID, personaID, missionID string, patch map[string]interface{}) (*entity.Mission, error) { if r.collection == nil { return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured") } if len(patch) == 0 { return r.FindByID(ctx, tenantID, ownerUID, personaID, missionID) } patch["update_at"] = clock.NowUnixNano() var out entity.Mission err := r.collection.FindOneAndUpdate( ctx, bson.M{ "_id": strings.TrimSpace(missionID), "tenant_id": tenantID, "owner_uid": ownerUID, "persona_id": strings.TrimSpace(personaID), "status": bson.M{"$ne": entity.StatusDeleted}, }, bson.M{"$set": patch}, options.FindOneAndUpdate().SetReturnDocument(options.After), ).Decode(&out) if err != nil { if err == mongo.ErrNoDocuments { return nil, app.For(code.Persona).ResNotFound("找不到拷貝任務") } return nil, err } return &out, nil } func (r *mongoRepository) Delete(ctx context.Context, tenantID, ownerUID, personaID, missionID string) error { _, err := r.Update(ctx, tenantID, ownerUID, personaID, missionID, map[string]interface{}{ "status": entity.StatusDeleted, }) return err } func (r *mongoRepository) findOne(ctx context.Context, filter bson.M) (*entity.Mission, error) { if r.collection == nil { return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured") } var out entity.Mission err := r.collection.FindOne(ctx, filter).Decode(&out) if err != nil { if err == mongo.ErrNoDocuments { return nil, app.For(code.Persona).ResNotFound("找不到拷貝任務") } return nil, err } return &out, nil }