补充标签过滤 LIKE模式

This commit is contained in:
yumaojun03 2025-06-29 10:24:46 +08:00
parent 13ea1f2e04
commit 1b27d97f2a
5 changed files with 56 additions and 16 deletions

View File

@ -4,8 +4,10 @@ import (
"context" "context"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/label" "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label"
"github.com/infraboard/mcube/v2/exception"
"github.com/infraboard/mcube/v2/ioc/config/datasource" "github.com/infraboard/mcube/v2/ioc/config/datasource"
"github.com/infraboard/mcube/v2/types" "github.com/infraboard/mcube/v2/types"
"gorm.io/gorm"
) )
// CreateLabel implements label.Service. // CreateLabel implements label.Service.
@ -46,13 +48,23 @@ func (i *LabelServiceImpl) QueryLabel(ctx context.Context, in *label.QueryLabelR
return set, nil return set, nil
} }
// DeleteLabel implements label.Service.
func (i *LabelServiceImpl) DeleteLabel(ctx context.Context, in *label.DeleteLabelRequest) (*label.Label, error) {
panic("unimplemented")
}
// DescribeLabel implements label.Service. // DescribeLabel implements label.Service.
func (i *LabelServiceImpl) DescribeLabel(ctx context.Context, in *label.DescribeLabelRequest) (*label.Label, error) { func (i *LabelServiceImpl) DescribeLabel(ctx context.Context, in *label.DescribeLabelRequest) (*label.Label, error) {
query := datasource.DBFromCtx(ctx)
ins := &label.Label{}
if err := query.Where("id = ?", in.Id).First(ins).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, exception.NewNotFound("label %s not found", in.Id)
}
return nil, err
}
return ins, nil
}
// DeleteLabel implements label.Service.
func (i *LabelServiceImpl) DeleteLabel(ctx context.Context, in *label.DeleteLabelRequest) (*label.Label, error) {
panic("unimplemented") panic("unimplemented")
} }

View File

@ -8,12 +8,16 @@ import (
func TestCreateLabel(t *testing.T) { func TestCreateLabel(t *testing.T) {
req := label.NewCreateLabelRequest() req := label.NewCreateLabelRequest()
req.Key = "tech" req.Key = "team"
req.KeyDesc = "技术部" req.KeyDesc = "小组"
req.ValueType = label.VALUE_TYPE_ENUM req.ValueType = label.VALUE_TYPE_ENUM
req.AddEnumOption(&label.EnumOption{ req.AddEnumOption(&label.EnumOption{
Label: "开发一组", Label: "开发一组",
Value: "dev01", Value: "dev01",
Children: []*label.EnumOption{
{Label: "后端开发", Value: "dev01.backend_developer"},
{Label: "前端开发", Value: "dev01.web_developer"},
},
}) })
ins, err := svc.CreateLabel(ctx, req) ins, err := svc.CreateLabel(ctx, req)
@ -22,3 +26,12 @@ func TestCreateLabel(t *testing.T) {
} }
t.Log(ins) t.Log(ins)
} }
func TestQueryLabel(t *testing.T) {
req := label.NewQueryLabelRequest()
set, err := svc.QueryLabel(ctx, req)
if err != nil {
t.Fatal(err)
}
t.Log(set)
}

View File

@ -11,8 +11,8 @@ func NewLabel(spc *CreateLabelRequest) (*Label, error) {
return nil, err return nil, err
} }
return &Label{ return &Label{
ResourceMeta: *apps.NewResourceMeta(), ResourceMeta: *apps.NewResourceMeta(),
Spec: spc, CreateLabelRequest: *spc,
}, nil }, nil
} }
@ -20,7 +20,7 @@ type Label struct {
// 基础数据 // 基础数据
apps.ResourceMeta apps.ResourceMeta
// 空间定义 // 空间定义
Spec *CreateLabelRequest `json:"spec" bson:",inline" gorm:"embedded"` CreateLabelRequest `bson:",inline" gorm:"embedded"`
} }
func (l *Label) TableName() string { func (l *Label) TableName() string {
@ -65,13 +65,14 @@ type CreateCreateLabelSpec struct {
// 适用于那些资源 // 适用于那些资源
Resources []string `json:"resources" bson:"resources" gorm:"column:resources;type:json;serializer:json;" description:"适用于那些资源" optional:"true"` Resources []string `json:"resources" bson:"resources" gorm:"column:resources;type:json;serializer:json;" description:"适用于那些资源" optional:"true"`
// 标签的键, 标签的Key不允许修改, 带前缀的 tech.dev.frontend01 tech.dev.backend01 // 标签的键, 标签的Key不允许修改
Key string `json:"key" bson:"key" gorm:"column:key;type:varchar(255)" validate:"required"` Key string `json:"key" bson:"key" gorm:"column:key;type:varchar(255)" validate:"required"`
// 标签的键的描述 // 标签的键的描述
KeyDesc string `json:"key_desc" bson:"key_desc" gorm:"column:key_desc;type:varchar(255)" validate:"required"` KeyDesc string `json:"key_desc" bson:"key_desc" gorm:"column:key_desc;type:varchar(255)" validate:"required"`
// 标签的颜色 // 标签的颜色
Color string `json:"color" bson:"color" gorm:"column:color;type:varchar(100)"` Color string `json:"color" bson:"color" gorm:"column:color;type:varchar(100)"`
// 标签的值相关信息, tech.dev.frontend01 tech.dev.backend01
// 值类型 // 值类型
ValueType VALUE_TYPE `json:"value_type" gorm:"column:value_type;type:varchar(20)" bson:"value_type"` ValueType VALUE_TYPE `json:"value_type" gorm:"column:value_type;type:varchar(20)" bson:"value_type"`
// 标签默认值 // 标签默认值
@ -83,7 +84,7 @@ type CreateCreateLabelSpec struct {
// 枚举值的选项 // 枚举值的选项
EnumOptions []*EnumOption `json:"enum_options,omitempty" bson:"enum_options" gorm:"column:enum_options;type:json;serializer:json;"` EnumOptions []*EnumOption `json:"enum_options,omitempty" bson:"enum_options" gorm:"column:enum_options;type:json;serializer:json;"`
// 基于Http枚举的配置 // 基于Http枚举的配置
HttpEnumConfig HttpEnumConfig `json:"http_enum_config,omitempty" gorm:"embedded" bson:"http_enum_config"` HttpEnumConfig HttpEnumConfig `json:"http_enum_config" gorm:"embedded" bson:"http_enum_config"`
// 值的样例 // 值的样例
Example string `json:"example" bson:"example" gorm:"column:example;type:text"` Example string `json:"example" bson:"example" gorm:"column:example;type:text"`
@ -98,6 +99,8 @@ type EnumOption struct {
Input string `json:"input" bson:"input" validate:"required"` Input string `json:"input" bson:"input" validate:"required"`
// 选项的值, 根据parent.input + children.input 自动生成 // 选项的值, 根据parent.input + children.input 自动生成
Value string `json:"value" bson:"value"` Value string `json:"value" bson:"value"`
// 是否禁止选中, 和前端UI组件配合使用
Disabled bool `json:"disabled" bson:"disabled"`
// 标签的颜色 // 标签的颜色
Color string `json:"color" bson:"color"` Color string `json:"color" bson:"color"`
// 是否废弃 // 是否废弃

View File

@ -1,6 +1,7 @@
package policy package policy
import ( import (
"strings"
"time" "time"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace" "122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace"
@ -104,8 +105,18 @@ func (r ResourceScope) GormResourceFilter(query *gorm.DB) *gorm.DB {
// 构建"标签值匹配"条件 // 构建"标签值匹配"条件
var valueMatches []clause.Expression var valueMatches []clause.Expression
for _, val := range values { for _, val := range values {
valueMatches = append(valueMatches, if strings.Contains(val, "%") {
datatypes.JSONQuery("label").Equals(val, key)) // 如果值包含通配符%使用LIKE条件
valueMatches = append(valueMatches,
clause.Expr{
SQL: "JSON_UNQUOTE(JSON_EXTRACT(label, ?)) LIKE ?",
Vars: []any{"$." + key, val},
})
} else {
// 否则使用精确匹配
valueMatches = append(valueMatches,
datatypes.JSONQuery("label").Equals(val, key))
}
} }
// 组合条件:标签不存在 OR 标签值匹配 // 组合条件:标签不存在 OR 标签值匹配

View File

@ -14,7 +14,7 @@ func TestCreateApplication(t *testing.T) {
req.CodeRepository = application.CodeRepository{ req.CodeRepository = application.CodeRepository{
SshUrl: "git@122.51.31.227:go-course/go18.git", SshUrl: "git@122.51.31.227:go-course/go18.git",
} }
req.SetLabel("team", "golang_dev_group_01") req.SetLabel("team", "dev01.web_developer")
ins, err := svc.CreateApplication(ctx, req) ins, err := svc.CreateApplication(ctx, req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -25,7 +25,8 @@ func TestCreateApplication(t *testing.T) {
// SELECT * FROM `applications` WHERE (NOT JSON_EXTRACT(`label`,'$.team') IS NOT NULL OR JSON_EXTRACT(`label`,'$.team') = 'golang_dev_group_01') ORDER BY created_at desc LIMIT 20 // SELECT * FROM `applications` WHERE (NOT JSON_EXTRACT(`label`,'$.team') IS NOT NULL OR JSON_EXTRACT(`label`,'$.team') = 'golang_dev_group_01') ORDER BY created_at desc LIMIT 20
func TestQueryApplication(t *testing.T) { func TestQueryApplication(t *testing.T) {
req := application.NewQueryApplicationRequest() req := application.NewQueryApplicationRequest()
req.SetScope("team", []string{"golang_dev_group_01"}) // dev01.%
req.SetScope("team", []string{"%"})
// req.SetScope("env", []string{"prod"}) // req.SetScope("env", []string{"prod"})
ins, err := svc.QueryApplication(ctx, req) ins, err := svc.QueryApplication(ctx, req)
if err != nil { if err != nil {