feat: update tags
This commit is contained in:
commit
84e608f4bb
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module code.30cm.net/digimon/app-cloudep-product-service
|
|||
go 1.24.0
|
||||
|
||||
require (
|
||||
code.30cm.net/digimon/library-go/errs v1.2.14
|
||||
code.30cm.net/digimon/library-go/mongo v0.0.9
|
||||
github.com/alicebob/miniredis/v2 v2.34.0
|
||||
github.com/shopspring/decimal v1.4.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1,3 +1,5 @@
|
|||
code.30cm.net/digimon/library-go/errs v1.2.14 h1:Un9wcIIjjJW8D2i0ISf8ibzp9oNT4OqLsaSKW0T4RJU=
|
||||
code.30cm.net/digimon/library-go/errs v1.2.14/go.mod h1:Hs4v7SbXNggDVBGXSYsFMjkii1qLF+rugrIpWePN4/o=
|
||||
code.30cm.net/digimon/library-go/mongo v0.0.9 h1:fPciIE5B85tXpLg8aeVQqKVbLnfpVAk9xbMu7pE2tVw=
|
||||
code.30cm.net/digimon/library-go/mongo v0.0.9/go.mod h1:KBVKz/Ci5IheI77BgZxPUeKkaGvDy8fV8EDHSCOLIO4=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
|
|
|
@ -48,8 +48,8 @@ type TagModifyParams struct {
|
|||
|
||||
// TagBindingRepo 定義與 tag binding (TagsBindingTable) 資料表相關的操作
|
||||
type TagBindingRepo interface {
|
||||
// BindTag 建立一筆 tag 與其他資料(例如專案)的綁定關係
|
||||
BindTag(ctx context.Context, binding *entity.TagsBindingTable) error
|
||||
// BindTags 建立一筆 tag 與其他資料(例如專案)的綁定關係
|
||||
BindTags(ctx context.Context, binding []*entity.TagsBindingTable) error
|
||||
// UnbindTag 刪除一筆綁定資料
|
||||
UnbindTag(ctx context.Context, tagID, referenceID string) error
|
||||
// GetBindingsByReference 根據參照 ID 取得所有綁定資料
|
||||
|
|
|
@ -12,15 +12,22 @@ import (
|
|||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func (repo *TagsRepository) BindTag(ctx context.Context, data *entity.TagsBindingTable) error {
|
||||
if data.ID.IsZero() {
|
||||
now := time.Now().UTC().UnixNano()
|
||||
data.ID = primitive.NewObjectID()
|
||||
data.CreatedAt = now
|
||||
data.UpdatedAt = now
|
||||
}
|
||||
func (repo *TagsRepository) BindTags(ctx context.Context, data []*entity.TagsBindingTable) error {
|
||||
now := time.Now().UTC().UnixNano()
|
||||
docs := make([]any, 0, len(data))
|
||||
|
||||
_, err := repo.TageBinding.GetClient().InsertOne(ctx, data)
|
||||
for i := range data {
|
||||
if data[i].ID.IsZero() {
|
||||
data[i].ID = primitive.NewObjectID()
|
||||
data[i].CreatedAt = now
|
||||
data[i].UpdatedAt = now
|
||||
}
|
||||
docs = append(docs, data[i])
|
||||
}
|
||||
if len(docs) == 0 {
|
||||
return nil
|
||||
}
|
||||
_, err := repo.TageBinding.GetClient().InsertMany(ctx, docs)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -545,7 +545,7 @@ func TestBindTag(t *testing.T) {
|
|||
for _, tc := range tests {
|
||||
tc := tc // capture range variable
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := repo.BindTag(ctx, tc.inputBinding)
|
||||
err := repo.BindTags(ctx, []*entity.TagsBindingTable{tc.inputBinding})
|
||||
if tc.expectError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
|
@ -581,11 +581,7 @@ func TestGetBindingsByReference(t *testing.T) {
|
|||
}
|
||||
|
||||
// 插入資料
|
||||
err = repo.BindTag(ctx, binding1)
|
||||
require.NoError(t, err)
|
||||
err = repo.BindTag(ctx, binding2)
|
||||
require.NoError(t, err)
|
||||
err = repo.BindTag(ctx, binding3)
|
||||
err = repo.BindTags(ctx, []*entity.TagsBindingTable{binding1, binding2, binding3})
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
|
@ -665,14 +661,8 @@ func TestListTagBinding(t *testing.T) {
|
|||
UpdatedAt: 2500,
|
||||
}
|
||||
|
||||
// 插入綁定資料
|
||||
err = repo.BindTag(ctx, binding1)
|
||||
require.NoError(t, err)
|
||||
err = repo.BindTag(ctx, binding2)
|
||||
require.NoError(t, err)
|
||||
err = repo.BindTag(ctx, binding3)
|
||||
require.NoError(t, err)
|
||||
err = repo.BindTag(ctx, binding4)
|
||||
// 插入資料
|
||||
err = repo.BindTags(ctx, []*entity.TagsBindingTable{binding1, binding2, binding3, binding4})
|
||||
require.NoError(t, err)
|
||||
|
||||
// 測試案例
|
||||
|
@ -767,7 +757,7 @@ func TestUnbindTag(t *testing.T) {
|
|||
ReferenceID: "ref-001",
|
||||
TagID: "tag-001",
|
||||
}
|
||||
err = repo.BindTag(ctx, binding)
|
||||
err = repo.BindTags(ctx, []*entity.TagsBindingTable{binding})
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
|
|
|
@ -68,6 +68,7 @@ func SetupTestProductRepository(db string) (repository.ProductRepository, func()
|
|||
func TestListProduct(t *testing.T) {
|
||||
model, tearDown, err := SetupTestProductRepository("testDB")
|
||||
defer tearDown()
|
||||
fmt.Println("ddddddddddddddddddddd", err.Error())
|
||||
assert.NoError(t, err)
|
||||
|
||||
now := time.Now()
|
||||
|
|
|
@ -4,7 +4,13 @@ import (
|
|||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/utils"
|
||||
"code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.mongodb.org/mongo-driver/mongo/readconcern"
|
||||
)
|
||||
|
||||
type ProductUseCaseParam struct {
|
||||
|
@ -25,19 +31,130 @@ func MustProductUseCase(param ProductUseCaseParam) usecase.ProductUseCase {
|
|||
}
|
||||
|
||||
func (use *ProductUseCase) Create(ctx context.Context, product *usecase.Product) error {
|
||||
//use.ProductRepo.Transaction()
|
||||
insert := &entity.Product{
|
||||
UID: *product.UID,
|
||||
Title: *product.Title,
|
||||
ShortTitle: product.ShortTitle,
|
||||
// 資料前處理:準備 entity.Product 實體
|
||||
insert := &entity.Product{}
|
||||
|
||||
if product.UID != nil {
|
||||
insert.UID = *product.UID
|
||||
}
|
||||
if product.Title != nil {
|
||||
insert.Title = *product.Title
|
||||
}
|
||||
if product.IsPublished != nil {
|
||||
insert.IsPublished = *product.IsPublished
|
||||
}
|
||||
if product.Category != nil {
|
||||
insert.Category = *product.Category
|
||||
}
|
||||
if product.ShortTitle != nil {
|
||||
insert.ShortTitle = product.ShortTitle
|
||||
}
|
||||
if product.Details != nil {
|
||||
insert.Details = product.Details
|
||||
}
|
||||
if product.ShortDescription != nil {
|
||||
insert.ShortDescription = *product.ShortDescription
|
||||
}
|
||||
if product.Slug != nil {
|
||||
insert.Slug = product.Slug
|
||||
}
|
||||
if product.Amount != 0 {
|
||||
insert.Amount = product.Amount
|
||||
}
|
||||
if product.StartTime != nil {
|
||||
st := utils.Rfc3339ToUnix(utils.ToValue(product.StartTime))
|
||||
insert.StartTime = &st
|
||||
}
|
||||
if product.EndTime != nil {
|
||||
et := utils.Rfc3339ToUnix(utils.ToValue(product.EndTime))
|
||||
insert.EndTime = &et
|
||||
}
|
||||
if len(product.Media) > 0 {
|
||||
medias := make([]entity.Media, 0, len(product.Media))
|
||||
for _, m := range product.Media {
|
||||
medias = append(medias, entity.Media{
|
||||
Sort: m.Sort,
|
||||
URL: m.URL,
|
||||
Type: m.Type,
|
||||
})
|
||||
}
|
||||
insert.Media = medias
|
||||
}
|
||||
if len(product.CustomFields) > 0 {
|
||||
cf := make([]entity.CustomFields, 0, len(product.CustomFields))
|
||||
for _, field := range product.CustomFields {
|
||||
cf = append(cf, entity.CustomFields{
|
||||
Key: field.Key,
|
||||
Value: field.Value,
|
||||
})
|
||||
}
|
||||
insert.CustomFields = cf
|
||||
}
|
||||
|
||||
err := use.ProductRepo.Insert(ctx, insert)
|
||||
// Transaction 設定:只做必要寫入
|
||||
opts := options.Transaction().SetReadConcern(readconcern.Local())
|
||||
err := use.ProductRepo.Transaction(ctx, func(sessCtx mongo.SessionContext) (any, error) {
|
||||
// 插入 Product
|
||||
if err := use.ProductRepo.Insert(sessCtx, insert); err != nil {
|
||||
e := errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "req", Value: product},
|
||||
{Key: "func", Value: "ProductRepo.Insert"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
},
|
||||
"failed to create product")
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
// 插入 Product 統計資料
|
||||
if err := use.ProductStatisticsRepo.Create(sessCtx, &entity.ProductStatistics{
|
||||
ProductID: insert.ID.Hex(),
|
||||
Orders: 0,
|
||||
OrdersUpdateTime: 0,
|
||||
AverageRating: 0,
|
||||
AverageRatingUpdateTime: 0,
|
||||
FansCount: 0,
|
||||
FansCountUpdateTime: 0,
|
||||
}); err != nil {
|
||||
e := errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "ProductID", Value: insert.ID.Hex()},
|
||||
{Key: "func", Value: "ProductStatisticsRepo.Create"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
},
|
||||
"failed to create product statistics")
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
// 過濾 Tag
|
||||
// 綁定 Tags
|
||||
//for _, tag := range product.Tags {
|
||||
// if err := use.TagBinding.BindTag(sessCtx, &entity.TagsBindingTable{
|
||||
// ReferenceID: insert.ID.Hex(),
|
||||
// TagID: tag,
|
||||
// }); err != nil {
|
||||
// _ = errs.DBErrorL(logx.WithContext(ctx),
|
||||
// []logx.LogField{
|
||||
// {Key: "ReferenceID", Value: insert.ID.Hex()},
|
||||
// {Key: "TagID", Value: tag},
|
||||
// {Key: "func", Value: "TagBinding.BindTag"},
|
||||
// {Key: "err", Value: err.Error()},
|
||||
// }, "")
|
||||
//
|
||||
// continue
|
||||
// }
|
||||
//}
|
||||
|
||||
return nil, nil
|
||||
}, opts)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (use *ProductUseCase) Update(ctx context.Context, id string, product *usecase.Product) error {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package utils
|
||||
|
||||
import "time"
|
||||
|
||||
func UnixToRfc3339(t int64) string {
|
||||
res := time.Unix(0, t).UTC()
|
||||
|
||||
return res.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func Rfc3339ToUnix(rfc3339 string) int64 {
|
||||
// 解析 RFC3339 格式的時間
|
||||
t, err := time.Parse(time.RFC3339, rfc3339)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
// 轉換為 Unix Nano (納秒)
|
||||
return t.UTC().UnixNano()
|
||||
}
|
||||
|
||||
func ToValue[T any](ptr *T) T {
|
||||
if ptr == nil {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
return *ptr
|
||||
}
|
Loading…
Reference in New Issue