thread-master/old/backend/internal/model/content_ops/repository/mongo.go

233 lines
9.1 KiB
Go
Raw Normal View History

package repository
import (
"context"
"strings"
app "haixun-backend/internal/library/errors"
"haixun-backend/internal/library/errors/code"
"haixun-backend/internal/model/content_ops/domain/entity"
domrepo "haixun-backend/internal/model/content_ops/domain/repository"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type mongoRepository struct {
topics *mongo.Collection
plans *mongo.Collection
feedback *mongo.Collection
sources *mongo.Collection
chunks *mongo.Collection
formulas *mongo.Collection
}
func NewMongoRepository(db *mongo.Database) domrepo.Repository {
if db == nil {
return &mongoRepository{}
}
return &mongoRepository{
topics: db.Collection(entity.TopicCandidateCollectionName),
plans: db.Collection(entity.ContentPlanCollectionName),
feedback: db.Collection(entity.FeedbackEventCollectionName),
sources: db.Collection(entity.KnowledgeSourceCollectionName),
chunks: db.Collection(entity.KnowledgeChunkCollectionName),
formulas: db.Collection(entity.FormulaPoolCollectionName),
}
}
func (r *mongoRepository) EnsureIndexes(ctx context.Context) error {
if r.topics == nil || r.plans == nil || r.feedback == nil || r.sources == nil || r.chunks == nil || r.formulas == nil {
return nil
}
if _, err := r.topics.Indexes().CreateMany(ctx, []mongo.IndexModel{{Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "persona_id", Value: 1}, {Key: "create_at", Value: -1}}}}); err != nil {
return err
}
if _, err := r.plans.Indexes().CreateMany(ctx, []mongo.IndexModel{{Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "persona_id", Value: 1}, {Key: "create_at", Value: -1}}}, {Keys: bson.D{{Key: "topic_candidate_id", Value: 1}}}}); err != nil {
return err
}
_, err := r.feedback.Indexes().CreateMany(ctx, []mongo.IndexModel{{Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "persona_id", Value: 1}, {Key: "create_at", Value: -1}}}, {Keys: bson.D{{Key: "content_plan_id", Value: 1}}}, {Keys: bson.D{{Key: "draft_id", Value: 1}}}})
if err != nil {
return err
}
if _, err := r.sources.Indexes().CreateMany(ctx, []mongo.IndexModel{{Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "persona_id", Value: 1}, {Key: "create_at", Value: -1}}}}); err != nil {
return err
}
if _, err := r.chunks.Indexes().CreateMany(ctx, []mongo.IndexModel{{Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "persona_id", Value: 1}, {Key: "create_at", Value: -1}}}, {Keys: bson.D{{Key: "source_id", Value: 1}}}}); err != nil {
return err
}
_, err = r.formulas.Indexes().CreateMany(ctx, []mongo.IndexModel{{Keys: bson.D{{Key: "tenant_id", Value: 1}, {Key: "owner_uid", Value: 1}, {Key: "persona_id", Value: 1}, {Key: "type", Value: 1}}}})
return err
}
func personaFilter(tenantID, ownerUID, personaID string) bson.M {
return bson.M{"tenant_id": strings.TrimSpace(tenantID), "owner_uid": strings.TrimSpace(ownerUID), "persona_id": strings.TrimSpace(personaID)}
}
func normalizeLimit(limit int) int64 {
if limit <= 0 {
limit = 50
}
if limit > 200 {
limit = 200
}
return int64(limit)
}
func (r *mongoRepository) CreateTopicCandidate(ctx context.Context, item *entity.TopicCandidate) error {
if r.topics == nil {
return app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
_, err := r.topics.InsertOne(ctx, item)
return err
}
func (r *mongoRepository) ListTopicCandidates(ctx context.Context, tenantID, ownerUID, personaID string, limit int) ([]entity.TopicCandidate, error) {
if r.topics == nil {
return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
cur, err := r.topics.Find(ctx, personaFilter(tenantID, ownerUID, personaID), options.Find().SetSort(bson.D{{Key: "create_at", Value: -1}}).SetLimit(normalizeLimit(limit)))
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var out []entity.TopicCandidate
return out, cur.All(ctx, &out)
}
func (r *mongoRepository) CreateContentPlan(ctx context.Context, item *entity.ContentPlan) error {
if r.plans == nil {
return app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
_, err := r.plans.InsertOne(ctx, item)
return err
}
func (r *mongoRepository) UpdateContentPlan(ctx context.Context, tenantID, ownerUID, personaID, id string, patch map[string]any) (*entity.ContentPlan, error) {
if r.plans == nil {
return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
filter := personaFilter(tenantID, ownerUID, personaID)
filter["_id"] = strings.TrimSpace(id)
var out entity.ContentPlan
err := r.plans.FindOneAndUpdate(ctx, filter, bson.M{"$set": patch}, options.FindOneAndUpdate().SetReturnDocument(options.After)).Decode(&out)
if err == mongo.ErrNoDocuments {
return nil, app.For(code.Persona).ResNotFound("找不到內容計畫")
}
return &out, err
}
func (r *mongoRepository) GetContentPlan(ctx context.Context, tenantID, ownerUID, personaID, id string) (*entity.ContentPlan, error) {
if r.plans == nil {
return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
filter := personaFilter(tenantID, ownerUID, personaID)
filter["_id"] = strings.TrimSpace(id)
var out entity.ContentPlan
err := r.plans.FindOne(ctx, filter).Decode(&out)
if err == mongo.ErrNoDocuments {
return nil, app.For(code.Persona).ResNotFound("找不到內容計畫")
}
return &out, err
}
func (r *mongoRepository) ListContentPlans(ctx context.Context, tenantID, ownerUID, personaID string, limit int) ([]entity.ContentPlan, error) {
if r.plans == nil {
return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
cur, err := r.plans.Find(ctx, personaFilter(tenantID, ownerUID, personaID), options.Find().SetSort(bson.D{{Key: "create_at", Value: -1}}).SetLimit(normalizeLimit(limit)))
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var out []entity.ContentPlan
return out, cur.All(ctx, &out)
}
func (r *mongoRepository) CreateFeedbackEvent(ctx context.Context, item *entity.FeedbackEvent) error {
if r.feedback == nil {
return app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
_, err := r.feedback.InsertOne(ctx, item)
return err
}
func (r *mongoRepository) ListFeedbackEvents(ctx context.Context, tenantID, ownerUID, personaID string, limit int) ([]entity.FeedbackEvent, error) {
if r.feedback == nil {
return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
cur, err := r.feedback.Find(ctx, personaFilter(tenantID, ownerUID, personaID), options.Find().SetSort(bson.D{{Key: "create_at", Value: -1}}).SetLimit(normalizeLimit(limit)))
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var out []entity.FeedbackEvent
return out, cur.All(ctx, &out)
}
func (r *mongoRepository) CreateKnowledgeSource(ctx context.Context, item *entity.KnowledgeSource, chunks []*entity.KnowledgeChunk) error {
if r.sources == nil || r.chunks == nil {
return app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
if _, err := r.sources.InsertOne(ctx, item); err != nil {
return err
}
if len(chunks) == 0 {
return nil
}
docs := make([]any, 0, len(chunks))
for _, c := range chunks {
docs = append(docs, c)
}
_, err := r.chunks.InsertMany(ctx, docs)
return err
}
func (r *mongoRepository) ListKnowledgeSources(ctx context.Context, tenantID, ownerUID, personaID string, limit int) ([]entity.KnowledgeSource, error) {
if r.sources == nil {
return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
cur, err := r.sources.Find(ctx, personaFilter(tenantID, ownerUID, personaID), options.Find().SetSort(bson.D{{Key: "create_at", Value: -1}}).SetLimit(normalizeLimit(limit)))
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var out []entity.KnowledgeSource
return out, cur.All(ctx, &out)
}
func (r *mongoRepository) ListKnowledgeChunks(ctx context.Context, tenantID, ownerUID, personaID string, limit int) ([]entity.KnowledgeChunk, error) {
if r.chunks == nil {
return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
cur, err := r.chunks.Find(ctx, personaFilter(tenantID, ownerUID, personaID), options.Find().SetSort(bson.D{{Key: "create_at", Value: -1}}).SetLimit(normalizeLimit(limit)))
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var out []entity.KnowledgeChunk
return out, cur.All(ctx, &out)
}
func (r *mongoRepository) CreateFormulaPool(ctx context.Context, item *entity.FormulaPool) error {
if r.formulas == nil {
return app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
_, err := r.formulas.InsertOne(ctx, item)
return err
}
func (r *mongoRepository) ListFormulaPools(ctx context.Context, tenantID, ownerUID, personaID string, limit int) ([]entity.FormulaPool, error) {
if r.formulas == nil {
return nil, app.For(code.Persona).DBUnavailable("Mongo is not configured")
}
cur, err := r.formulas.Find(ctx, personaFilter(tenantID, ownerUID, personaID), options.Find().SetSort(bson.D{{Key: "weight", Value: -1}, {Key: "create_at", Value: -1}}).SetLimit(normalizeLimit(limit)))
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var out []entity.FormulaPool
return out, cur.All(ctx, &out)
}