package repository import ( "context" "errors" "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain" "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity" "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository" mgo "code.30cm.net/digimon/library-go/mongo" "time" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/mon" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) type CategoryRepositoryParam struct { Conf *mgo.Conf CacheConf cache.CacheConf DBOpts []mon.Option CacheOpts []cache.Option } type CategoryRepository struct { DB mgo.DocumentDBWithCacheUseCase } func MustCategoryRepository(param CategoryRepositoryParam) repository.CategoryRepository { e := entity.Category{} documentDB, err := mgo.MustDocumentDBWithCache( param.Conf, e.CollectionName(), param.CacheConf, param.DBOpts, param.CacheOpts, ) if err != nil { panic(err) } return &CategoryRepository{ DB: documentDB, } } func (repo *CategoryRepository) IsCategoryExists(ctx context.Context, ids []string) []string { // 將傳入的 string id 轉換為 ObjectID objectIDs := make([]primitive.ObjectID, 0, len(ids)) for _, id := range ids { objID, err := primitive.ObjectIDFromHex(id) if err == nil { // 如果轉換失敗,忽略該 id objectIDs = append(objectIDs, objID) } } // 查詢存在的標籤 filter := bson.M{"_id": bson.M{"$in": objectIDs}} // find 並沒有快取要快取要去其他地方做 opts := options.Find().SetProjection(bson.M{"_id": 1}) // 只返回 _id 欄位 // 執行查詢並獲取結果 var category []*entity.Category err := repo.DB.GetClient().Find(ctx, &category, filter, opts) if err != nil { return []string{} } // 將存在的標籤ID轉換回 string,並加入結果列表 existingIDs := make([]string, 0, len(category)) for _, item := range category { existingIDs = append(existingIDs, item.ID.Hex()) } return existingIDs } func (repo *CategoryRepository) Insert(ctx context.Context, data *entity.Category) error { now := time.Now().UTC().UnixNano() if data.ID.IsZero() { data.ID = primitive.NewObjectID() data.CreatedAt = now data.UpdatedAt = now } _, err := repo.DB.GetClient().InsertOne(ctx, data) return err } func (repo *CategoryRepository) FindOneByID(ctx context.Context, id string) (*entity.Category, error) { oid, err := primitive.ObjectIDFromHex(id) if err != nil { return nil, ErrInvalidObjectID } var data entity.Category rk := domain.GetCategoryRedisKey(id) err = repo.DB.FindOne(ctx, rk, &data, bson.M{"_id": oid}) switch { case err == nil: return &data, nil case errors.Is(err, mon.ErrNotFound): return nil, ErrNotFound default: return nil, err } } func (repo *CategoryRepository) Update(ctx context.Context, id string, data *entity.Category) (*mongo.UpdateResult, error) { oid, err := primitive.ObjectIDFromHex(id) if err != nil { return nil, ErrInvalidObjectID } updateFields := bson.M{} if data.Name != "" { updateFields["name"] = data.Name } updateFields["updated_at"] = time.Now().UTC().UnixNano() // 構建查找條件 filter := bson.M{"_id": oid} update := bson.M{"$set": updateFields} opt := options.Update().SetUpsert(false) rk := domain.GetCategoryRedisKey(id) res, err := repo.DB.UpdateOne(ctx, rk, filter, update, opt) if err != nil { return nil, err } // 檢查更新結果,若沒有匹配的文檔,則返回錯誤 if res.MatchedCount == 0 { return nil, ErrNotFound // 自定義的錯誤表示未找到記錄 } return res, err } func (repo *CategoryRepository) Delete(ctx context.Context, id string) (int64, error) { oid, err := primitive.ObjectIDFromHex(id) if err != nil { return 0, ErrInvalidObjectID } rk := domain.GetCategoryRedisKey(id) res, err := repo.DB.DeleteOne(ctx, rk, bson.M{"_id": oid}) return res, err } func (repo *CategoryRepository) ListCategory(ctx context.Context, params *repository.CategoryQueryParams) ([]*entity.Category, int64, error) { // TODO 有需要列表快取實在取列表快取 // 構建查詢過濾器 filter := bson.M{} if len(params.ID) > 0 { objectIDs := make([]primitive.ObjectID, 0, len(params.ID)) for _, id := range params.ID { objID, err := primitive.ObjectIDFromHex(id) if err != nil { continue } objectIDs = append(objectIDs, objID) } filter["_id"] = bson.M{"$in": objectIDs} } // 設置排序選項 opts := options.Find().SetSkip((params.PageIndex - 1) * params.PageSize).SetLimit(params.PageSize) opts.SetSort(bson.D{{Key: "created_at", Value: -1}}) // 查詢符合條件的總數 count, err := repo.DB.GetClient().CountDocuments(ctx, filter) if err != nil { return nil, 0, err } // 執行查詢並獲取結果 var category []*entity.Category err = repo.DB.GetClient().Find(ctx, &category, filter, opts) if err != nil { return nil, 0, err } return category, count, nil }