diff --git a/internal/dms/biz/cb_operation_log.go b/internal/dms/biz/cb_operation_log.go index d5c4b81d..9cb0b039 100644 --- a/internal/dms/biz/cb_operation_log.go +++ b/internal/dms/biz/cb_operation_log.go @@ -90,10 +90,10 @@ func (c CbOperationLog) GetDbServiceName() string { // ListCbOperationLogOption 用于查询操作日志的选项 type ListCbOperationLogOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy string - FilterBy []constant.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy string + FilterByOptions constant.FilterOptions } // CbOperationLogUsecase 定义操作日志的业务逻辑 diff --git a/internal/dms/biz/data_export_task.go b/internal/dms/biz/data_export_task.go index cf94d2e6..fe52208a 100644 --- a/internal/dms/biz/data_export_task.go +++ b/internal/dms/biz/data_export_task.go @@ -65,16 +65,16 @@ type DataExportTaskRecord struct { } type ListDataExportTaskRecordOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy DataExportTaskRecordField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy DataExportTaskRecordField + FilterByOptions pkgConst.FilterOptions } type ListDataExportTaskOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy DataExportTaskField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy DataExportTaskField + FilterByOptions pkgConst.FilterOptions } type DataExportTaskRepo interface { diff --git a/internal/dms/biz/data_export_workflow.go b/internal/dms/biz/data_export_workflow.go index 2af41eea..680341d4 100644 --- a/internal/dms/biz/data_export_workflow.go +++ b/internal/dms/biz/data_export_workflow.go @@ -150,8 +150,8 @@ func NewDataExportWorkflowUsecase(logger utilLog.Logger, tx TransactionGenerator } type ListWorkflowsOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy WorkflowField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy WorkflowField + FilterByOptions pkgConst.FilterOptions } diff --git a/internal/dms/biz/db_service.go b/internal/dms/biz/db_service.go index 400c80ca..46622e2e 100644 --- a/internal/dms/biz/db_service.go +++ b/internal/dms/biz/db_service.go @@ -282,10 +282,10 @@ func (d *DBServiceUsecase) createDBService(ctx context.Context, dbService *DBSer } type ListDBServicesOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy DBServiceField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy DBServiceField + FilterByOptions pkgConst.FilterOptions } func (d *DBServiceUsecase) ListDBService(ctx context.Context, option *ListDBServicesOption, projectUid, currentUserUid string) (dbServices []*DBService, total int64, err error) { diff --git a/internal/dms/biz/gateway.go b/internal/dms/biz/gateway.go index dd33c88e..c36e55a2 100644 --- a/internal/dms/biz/gateway.go +++ b/internal/dms/biz/gateway.go @@ -24,8 +24,8 @@ type Gateway struct { } type ListGatewaysOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy MemberField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy MemberField + FilterByOptions pkgConst.FilterOptions } diff --git a/internal/dms/biz/member.go b/internal/dms/biz/member.go index b3e14847..d9008e28 100644 --- a/internal/dms/biz/member.go +++ b/internal/dms/biz/member.go @@ -114,18 +114,20 @@ func (m *MemberUsecase) CreateMember(ctx context.Context, currentUserUid string, if _, total, err := m.ListMember(ctx, &ListMembersOption{ PageNumber: 0, LimitPerPage: 10, - FilterBy: []pkgConst.FilterCondition{ - { - Field: string(MemberFieldUserUID), - Operator: pkgConst.FilterOperatorEqual, - Value: memberUserUid, - }, - { - Field: string(MemberFieldProjectUID), - Operator: pkgConst.FilterOperatorEqual, - Value: projectUid, - }, - }, + FilterByOptions: pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd, + pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(MemberFieldUserUID), + Operator: pkgConst.FilterOperatorEqual, + Value: memberUserUid, + }, + pkgConst.FilterCondition{ + Field: string(MemberFieldProjectUID), + Operator: pkgConst.FilterOperatorEqual, + Value: projectUid, + }, + ), + ), }, projectUid); err != nil { return "", fmt.Errorf("check member exist failed: %v", err) } else if total > 0 { @@ -177,18 +179,20 @@ func (m *MemberUsecase) AddUserToProjectAdminMember(ctx context.Context, userUid if _, total, err := m.ListMember(ctx, &ListMembersOption{ PageNumber: 0, LimitPerPage: 10, - FilterBy: []pkgConst.FilterCondition{ - { + FilterByOptions: pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd, + pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ Field: string(MemberFieldUserUID), Operator: pkgConst.FilterOperatorEqual, Value: userUid, }, - { + pkgConst.FilterCondition{ Field: string(MemberFieldProjectUID), Operator: pkgConst.FilterOperatorEqual, Value: projectUid, }, - }, + ), + ), }, projectUid); err != nil { return "", fmt.Errorf("check member exist failed: %v", err) } else if total > 0 { @@ -283,10 +287,10 @@ func (m *MemberUsecase) GetMemberRoleWithOpRange(ctx context.Context, memberUid } type ListMembersOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy MemberField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy MemberField + FilterByOptions pkgConst.FilterOptions } func (m *MemberUsecase) ListMember(ctx context.Context, option *ListMembersOption, projectUid string) (members []*Member, total int64, err error) { diff --git a/internal/dms/biz/member_group.go b/internal/dms/biz/member_group.go index c83a81f9..d1652cd7 100644 --- a/internal/dms/biz/member_group.go +++ b/internal/dms/biz/member_group.go @@ -69,10 +69,10 @@ func NewMemberGroupUsecase(log utilLog.Logger, tx TransactionGenerator, repo Mem } type ListMemberGroupsOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy MemberGroupField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy MemberGroupField + FilterByOptions pkgConst.FilterOptions } func (m *MemberGroupUsecase) ListMemberGroups(ctx context.Context, option *ListMemberGroupsOption, projectUid string) ([]*MemberGroup, int64, error) { diff --git a/internal/dms/biz/op_permission.go b/internal/dms/biz/op_permission.go index 59c890c5..0c85799b 100644 --- a/internal/dms/biz/op_permission.go +++ b/internal/dms/biz/op_permission.go @@ -349,10 +349,10 @@ func GetProxyOpPermission() map[string][]*OpPermission { } type ListOpPermissionsOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy OpPermissionField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy OpPermissionField + FilterByOptions pkgConst.FilterOptions } type OpPermissionRepo interface { @@ -432,11 +432,14 @@ func (d *OpPermissionUsecase) ListOpPermissions(ctx context.Context, opt *ListOp func (d *OpPermissionUsecase) ListUserOpPermissions(ctx context.Context, opt *ListOpPermissionsOption) (ops []*OpPermission, total int64, err error) { // 用户只能被赋予全局权限 - opt.FilterBy = append(opt.FilterBy, pkgConst.FilterCondition{ - Field: string(OpPermissionFieldRangeType), - Operator: pkgConst.FilterOperatorEqual, - Value: OpRangeTypeGlobal, - }) + opt.FilterByOptions.Groups = append(opt.FilterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(OpPermissionFieldRangeType), + Operator: pkgConst.FilterOperatorEqual, + Value: OpRangeTypeGlobal, + }, + )) ops, total, err = d.repo.ListOpPermissions(ctx, opt) if err != nil { @@ -447,18 +450,24 @@ func (d *OpPermissionUsecase) ListUserOpPermissions(ctx context.Context, opt *Li func (d *OpPermissionUsecase) ListMemberOpPermissions(ctx context.Context, opt *ListOpPermissionsOption) (ops []*OpPermission, total int64, err error) { // 成员属于项目,只能被赋予非全局权限 - opt.FilterBy = append(opt.FilterBy, pkgConst.FilterCondition{ - Field: string(OpPermissionFieldRangeType), - Operator: pkgConst.FilterOperatorNotEqual, - Value: OpRangeTypeGlobal, - }) + opt.FilterByOptions.Groups = append(opt.FilterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(OpPermissionFieldRangeType), + Operator: pkgConst.FilterOperatorNotEqual, + Value: OpRangeTypeGlobal, + }, + )) // 设置成员权限时,有单独的“项目管理权限”选项代表项目权限,所以这里不返回项目权限 - opt.FilterBy = append(opt.FilterBy, pkgConst.FilterCondition{ - Field: string(OpPermissionFieldRangeType), - Operator: pkgConst.FilterOperatorNotEqual, - Value: OpRangeTypeProject, - }) + opt.FilterByOptions.Groups = append(opt.FilterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(OpPermissionFieldRangeType), + Operator: pkgConst.FilterOperatorNotEqual, + Value: OpRangeTypeProject, + }, + )) ops, total, err = d.repo.ListOpPermissions(ctx, opt) if err != nil { @@ -469,17 +478,19 @@ func (d *OpPermissionUsecase) ListMemberOpPermissions(ctx context.Context, opt * } func (d *OpPermissionUsecase) ListProjectOpPermissions(ctx context.Context, opt *ListOpPermissionsOption) (ops []*OpPermission, total int64, err error) { - opt.FilterBy = append(opt.FilterBy, pkgConst.FilterCondition{ - Field: string(OpPermissionFieldRangeType), - Operator: pkgConst.FilterOperatorEqual, - Value: OpRangeTypeProject, - }) - - opt.FilterBy = append(opt.FilterBy, pkgConst.FilterCondition{ - Field: string(OpPermissionFieldUID), - Operator: pkgConst.FilterOperatorNotEqual, - Value: pkgConst.UIDOfOpPermissionProjectAdmin, - }) + opt.FilterByOptions.Groups = append(opt.FilterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(OpPermissionFieldRangeType), + Operator: pkgConst.FilterOperatorEqual, + Value: OpRangeTypeProject, + }, + pkgConst.FilterCondition{ + Field: string(OpPermissionFieldUID), + Operator: pkgConst.FilterOperatorNotEqual, + Value: pkgConst.UIDOfOpPermissionProjectAdmin, + }, + )) ops, total, err = d.repo.ListOpPermissions(ctx, opt) if err != nil { diff --git a/internal/dms/biz/project.go b/internal/dms/biz/project.go index 69a7a6da..1e6fe58c 100644 --- a/internal/dms/biz/project.go +++ b/internal/dms/biz/project.go @@ -116,10 +116,10 @@ func NewProjectUsecase(log utilLog.Logger, tx TransactionGenerator, repo Project } type ListProjectsOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy ProjectField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy ProjectField + FilterByOptions pkgConst.FilterOptions } func (d *ProjectUsecase) ListProject(ctx context.Context, option *ListProjectsOption, currentUserUid string) (projects []*Project, total int64, err error) { @@ -139,11 +139,14 @@ func (d *ProjectUsecase) ListProject(ctx context.Context, option *ListProjectsOp for _, project := range projects { canViewableId = append(canViewableId, project.UID) } - option.FilterBy = append(option.FilterBy, pkgConst.FilterCondition{ - Field: string(ProjectFieldUID), - Operator: pkgConst.FilterOperatorIn, - Value: canViewableId, - }) + option.FilterByOptions.Groups = append(option.FilterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(ProjectFieldUID), + Operator: pkgConst.FilterOperatorIn, + Value: canViewableId, + }, + )) } diff --git a/internal/dms/biz/role.go b/internal/dms/biz/role.go index 7f0e6628..2fb514ea 100644 --- a/internal/dms/biz/role.go +++ b/internal/dms/biz/role.go @@ -85,10 +85,10 @@ func initRole() []*Role { } type ListRolesOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy RoleField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy RoleField + FilterByOptions pkgConst.FilterOptions } type RoleRepo interface { @@ -279,11 +279,14 @@ func (d *RoleUsecase) InsureOpPermissionsToRole(ctx context.Context, opPermissio func (d *RoleUsecase) ListRole(ctx context.Context, option *ListRolesOption) (roles []*Role, total int64, err error) { // DMS-125:项目管理员为内置角色,不对外展示 - option.FilterBy = append(option.FilterBy, pkgConst.FilterCondition{ - Field: string(RoleFieldUID), - Operator: pkgConst.FilterOperatorNotEqual, - Value: pkgConst.UIDOfRoleProjectAdmin, - }) + option.FilterByOptions.Groups = append(option.FilterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(RoleFieldUID), + Operator: pkgConst.FilterOperatorNotEqual, + Value: pkgConst.UIDOfRoleProjectAdmin, + }, + )) roles, total, err = d.repo.ListRoles(ctx, option) if err != nil { return nil, 0, fmt.Errorf("list roles failed: %v", err) diff --git a/internal/dms/biz/user.go b/internal/dms/biz/user.go index bb50925d..ef3398ee 100644 --- a/internal/dms/biz/user.go +++ b/internal/dms/biz/user.go @@ -167,10 +167,10 @@ func (u *User) GetUID() string { } type ListUsersOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy UserField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy UserField + FilterByOptions pkgConst.FilterOptions } type UserRepo interface { diff --git a/internal/dms/biz/user_group.go b/internal/dms/biz/user_group.go index 748bc274..690ff68f 100644 --- a/internal/dms/biz/user_group.go +++ b/internal/dms/biz/user_group.go @@ -61,10 +61,10 @@ func (u *UserGroup) GetUID() string { } type ListUserGroupsOption struct { - PageNumber uint32 - LimitPerPage uint32 - OrderBy UserGroupField - FilterBy []pkgConst.FilterCondition + PageNumber uint32 + LimitPerPage uint32 + OrderBy UserGroupField + FilterByOptions pkgConst.FilterOptions } type UserGroupRepo interface { diff --git a/internal/dms/pkg/constant/const.go b/internal/dms/pkg/constant/const.go index 36912a77..cb682c61 100644 --- a/internal/dms/pkg/constant/const.go +++ b/internal/dms/pkg/constant/const.go @@ -287,6 +287,49 @@ const ( FilterOperatorIn FilterOperator = "in" ) +type FilterLogic string + +const ( + FilterLogicAnd FilterLogic = "AND" + FilterLogicOr FilterLogic = "OR" +) + +type FilterConditionGroup struct { + Logic FilterLogic + Conditions []FilterCondition + Groups []FilterConditionGroup +} + +type FilterOptions struct { + Logic FilterLogic + Groups []FilterConditionGroup +} + +func NewFilterOptions(logic FilterLogic, groups ...FilterConditionGroup) FilterOptions { + return FilterOptions{ + Logic: logic, + Groups: groups, + } +} + +func NewConditionGroup(logic FilterLogic, conditions ...FilterCondition) FilterConditionGroup { + return FilterConditionGroup{ + Logic: logic, + Conditions: conditions, + } +} + +func ConditionsToFilterOptions(conditions []FilterCondition) FilterOptions { + if len(conditions) == 0 { + return FilterOptions{} + } + + return FilterOptions{ + Logic: FilterLogicAnd, + Groups: []FilterConditionGroup{NewConditionGroup(FilterLogicAnd, conditions...)}, + } +} + type DBServiceSourceName string const ( diff --git a/internal/dms/service/business_tag.go b/internal/dms/service/business_tag.go index b3a9be4e..d88a6430 100644 --- a/internal/dms/service/business_tag.go +++ b/internal/dms/service/business_tag.go @@ -70,7 +70,7 @@ func (d *DMSService) DeleteBusinessTag(ctx context.Context, currentUserUid strin }, } - _, total, err := d.ProjectUsecase.ListProject(ctx, &biz.ListProjectsOption{FilterBy: filterBy}, currentUserUid) + _, total, err := d.ProjectUsecase.ListProject(ctx, &biz.ListProjectsOption{FilterByOptions: pkgConst.ConditionsToFilterOptions(filterBy)}, currentUserUid) if err != nil { return fmt.Errorf("list project failed: %w", err) } diff --git a/internal/dms/service/configuration.go b/internal/dms/service/configuration.go index beba58ec..6a00b516 100644 --- a/internal/dms/service/configuration.go +++ b/internal/dms/service/configuration.go @@ -529,14 +529,16 @@ func (d *DMSService) NotifyMessage(ctx context.Context, req *dmsCommonV1.Notific }() users, _, err := d.UserUsecase.ListUser(ctx, &biz.ListUsersOption{ - FilterBy: []pkgConst.FilterCondition{ - { - Field: string(biz.UserFieldUID), - Operator: pkgConst.FilterOperatorIn, - Value: req.Notification.UserUids, - }, - }, - OrderBy: biz.UserFieldName, + FilterByOptions: pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd, + pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(biz.UserFieldUID), + Operator: pkgConst.FilterOperatorIn, + Value: req.Notification.UserUids, + }, + ), + ), + OrderBy: biz.UserFieldName, PageNumber: 1, LimitPerPage: uint32(len(req.Notification.UserUids)), }) diff --git a/internal/dms/service/data_export_workflow.go b/internal/dms/service/data_export_workflow.go index 7cab7555..5620fcea 100644 --- a/internal/dms/service/data_export_workflow.go +++ b/internal/dms/service/data_export_workflow.go @@ -38,15 +38,17 @@ func (d *DMSService) ListDataExportWorkflow(ctx context.Context, req *dmsV1.List // default order by orderBy := biz.WorkflowFieldCreateTime - filterBy := make([]pkgConst.FilterCondition, 0) - filterBy = append(filterBy, pkgConst.FilterCondition{ + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + + andConditions := make([]pkgConst.FilterCondition, 0) + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.WorkflowFieldWorkflowType), Operator: pkgConst.FilterOperatorEqual, Value: biz.DataExportWorkflowEventType.String(), }) if req.FilterByCreateUserUid != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.WorkflowFieldCreateUserUID), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByCreateUserUid, @@ -54,7 +56,7 @@ func (d *DMSService) ListDataExportWorkflow(ctx context.Context, req *dmsV1.List } if req.FilterCreateTimeFrom != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.WorkflowFieldCreateTime), Operator: pkgConst.FilterOperatorGreaterThanOrEqual, Value: req.FilterCreateTimeFrom, @@ -62,7 +64,7 @@ func (d *DMSService) ListDataExportWorkflow(ctx context.Context, req *dmsV1.List } if req.FilterCreateTimeTo != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.WorkflowFieldCreateTime), Operator: pkgConst.FilterOperatorLessThanOrEqual, Value: req.FilterCreateTimeTo, @@ -70,33 +72,38 @@ func (d *DMSService) ListDataExportWorkflow(ctx context.Context, req *dmsV1.List } if req.ProjectUid != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.WorkflowFieldProjectUID), Operator: pkgConst.FilterOperatorEqual, Value: req.ProjectUid, }) } + if len(andConditions) > 0 { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } + if req.FuzzyKeyword != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ - Field: string(biz.WorkflowFieldName), - Operator: pkgConst.FilterOperatorContains, - Value: req.FuzzyKeyword, - KeywordSearch: true, - }, pkgConst.FilterCondition{ - Field: string(biz.WorkflowFieldUID), - Operator: pkgConst.FilterOperatorContains, - Value: req.FuzzyKeyword, - KeywordSearch: true, - }, - ) + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicOr, + pkgConst.FilterCondition{ + Field: string(biz.WorkflowFieldName), + Operator: pkgConst.FilterOperatorContains, + Value: req.FuzzyKeyword, + }, + pkgConst.FilterCondition{ + Field: string(biz.WorkflowFieldUID), + Operator: pkgConst.FilterOperatorContains, + Value: req.FuzzyKeyword, + }, + )) } listOption := &biz.ListWorkflowsOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, } workflows, total, err := d.DataExportWorkflowUsecase.ListDataExportWorkflows(ctx, listOption, currentUserUid, req.FilterByDBServiceUid, req.FilterCurrentStepAssigneeUserUid, string(req.FilterByStatus), req.ProjectUid) @@ -310,10 +317,10 @@ func (d *DMSService) ListDataExportTaskSQLs(ctx context.Context, req *dmsV1.List }} listOption := &biz.ListDataExportTaskRecordOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: pkgConst.ConditionsToFilterOptions(filterBy), } taskRecords, total, err := d.DataExportWorkflowUsecase.ListDataExportTaskRecords(ctx, listOption, currentUserUid) diff --git a/internal/dms/service/db_service.go b/internal/dms/service/db_service.go index 6315665f..816dfc0f 100644 --- a/internal/dms/service/db_service.go +++ b/internal/dms/service/db_service.go @@ -204,10 +204,10 @@ func (d *DMSService) CheckDBServiceIsConnectableByIds(ctx context.Context, proje }) listOption := &biz.ListDBServicesOption{ - PageNumber: 1, - LimitPerPage: uint32(len(dbServiceList)), - OrderBy: biz.DBServiceFieldName, - FilterBy: filterBy, + PageNumber: 1, + LimitPerPage: uint32(len(dbServiceList)), + OrderBy: biz.DBServiceFieldName, + FilterByOptions: pkgConst.ConditionsToFilterOptions(filterBy), } DBServiceList, _, err := d.DBServiceUsecase.ListDBService(ctx, listOption, projectUID, currentUserUid) @@ -534,10 +534,11 @@ func (d *DMSService) ListDBServices(ctx context.Context, req *dmsCommonV2.ListDB orderBy = biz.DBServiceFieldName } - filterBy := make([]pkgConst.FilterCondition, 0) + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + andConditions := make([]pkgConst.FilterCondition, 0) if req.FilterByEnvironmentTagUID != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldEnvironmentTagUID), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByEnvironmentTagUID, @@ -545,7 +546,7 @@ func (d *DMSService) ListDBServices(ctx context.Context, req *dmsCommonV2.ListDB } if req.FilterByHost != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldHost), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByHost, @@ -553,7 +554,7 @@ func (d *DMSService) ListDBServices(ctx context.Context, req *dmsCommonV2.ListDB } if req.FilterByUID != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldUID), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByUID, @@ -561,7 +562,7 @@ func (d *DMSService) ListDBServices(ctx context.Context, req *dmsCommonV2.ListDB } if biz.IsDMS() && req.IsEnableMasking != nil { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldIsEnableMasking), Operator: pkgConst.FilterOperatorEqual, Value: *req.IsEnableMasking, @@ -569,7 +570,7 @@ func (d *DMSService) ListDBServices(ctx context.Context, req *dmsCommonV2.ListDB } if req.FilterByName != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldName), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByName, @@ -577,7 +578,7 @@ func (d *DMSService) ListDBServices(ctx context.Context, req *dmsCommonV2.ListDB } if req.FilterByPort != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldPort), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByPort, @@ -585,7 +586,7 @@ func (d *DMSService) ListDBServices(ctx context.Context, req *dmsCommonV2.ListDB } if req.FilterByDBType != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldDBType), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByDBType, @@ -593,46 +594,52 @@ func (d *DMSService) ListDBServices(ctx context.Context, req *dmsCommonV2.ListDB } if req.ProjectUid != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldProjectUID), Operator: pkgConst.FilterOperatorEqual, Value: req.ProjectUid, }) } if req.FilterLastConnectionTestStatus != nil { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldLastConnectionStatus), Operator: pkgConst.FilterOperatorEqual, Value: *req.FilterLastConnectionTestStatus, }) } if len(req.FilterByDBServiceIds) > 0 { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.DBServiceFieldUID), Operator: pkgConst.FilterOperatorIn, Value: req.FilterByDBServiceIds, }) } + + if len(andConditions) > 0 { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } + if req.FuzzyKeyword != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ - Field: string(biz.DBServiceFieldPort), - Operator: pkgConst.FilterOperatorContains, - Value: req.FuzzyKeyword, - KeywordSearch: true, - }, pkgConst.FilterCondition{ - Field: string(biz.DBServiceFieldHost), - Operator: pkgConst.FilterOperatorContains, - Value: req.FuzzyKeyword, - KeywordSearch: true, - }, - ) + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicOr, + pkgConst.FilterCondition{ + Field: string(biz.DBServiceFieldPort), + Operator: pkgConst.FilterOperatorContains, + Value: req.FuzzyKeyword, + }, + pkgConst.FilterCondition{ + Field: string(biz.DBServiceFieldHost), + Operator: pkgConst.FilterOperatorContains, + Value: req.FuzzyKeyword, + }, + )) } listOption := &biz.ListDBServicesOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, } hasPermission, err := d.OpPermissionVerifyUsecase.HasViewPermission(ctx, currentUserUid, req.ProjectUid, pkgConst.UIdOfOpPermissionManageProjectDataSource) diff --git a/internal/dms/service/environment_tag.go b/internal/dms/service/environment_tag.go index 63f3cef7..c16e4e0e 100644 --- a/internal/dms/service/environment_tag.go +++ b/internal/dms/service/environment_tag.go @@ -50,7 +50,7 @@ func (d *DMSService) DeleteEnvironmentTag(ctx context.Context, projectUid, curre }, } - _, total, err := d.DBServiceUsecase.ListDBService(ctx, &biz.ListDBServicesOption{FilterBy: filterBy}, projectUid, currentUserUid) + _, total, err := d.DBServiceUsecase.ListDBService(ctx, &biz.ListDBServicesOption{FilterByOptions: pkgConst.ConditionsToFilterOptions(filterBy)}, projectUid, currentUserUid) if err != nil { return fmt.Errorf("list project failed: %w", err) } diff --git a/internal/dms/service/member.go b/internal/dms/service/member.go index 1454b7de..fd46b1f9 100644 --- a/internal/dms/service/member.go +++ b/internal/dms/service/member.go @@ -73,16 +73,19 @@ func (d *DMSService) ListMemberTips(ctx context.Context, projectId string) (repl func (d *DMSService) ListMemberGroupTips(ctx context.Context, projectId string) (reply *dmsV1.ListMemberGroupTipsReply, err error) { orderBy := biz.MemberGroupFieldName - filterBy := []pkgConst.FilterCondition{{ - Field: string(biz.MemberGroupFieldProjectUID), - Operator: pkgConst.FilterOperatorEqual, - Value: projectId, - }} listOption := &biz.ListMemberGroupsOption{ PageNumber: 1, LimitPerPage: 9999, OrderBy: orderBy, - FilterBy: filterBy, + FilterByOptions: pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd, + pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(biz.MemberGroupFieldProjectUID), + Operator: pkgConst.FilterOperatorEqual, + Value: projectId, + }, + ), + ), } memberGroups, _, err := d.MemberGroupUsecase.ListMemberGroups(ctx, listOption, projectId) if nil != err { @@ -116,27 +119,33 @@ func (d *DMSService) ListMembers(ctx context.Context, req *dmsV1.ListMemberReq, orderBy = biz.MemberFieldUserUID } - filterBy := make([]pkgConst.FilterCondition, 0) + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + + andConditions := make([]pkgConst.FilterCondition, 0) if req.FilterByUserUid != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.MemberFieldUserUID), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByUserUid, }) } if req.ProjectUid != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.MemberFieldProjectUID), Operator: pkgConst.FilterOperatorEqual, Value: req.ProjectUid, }) } + if len(andConditions) > 0 { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } + listOption := &biz.ListMembersOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, } members, total, err := d.MemberUsecase.ListMember(ctx, listOption, req.ProjectUid) diff --git a/internal/dms/service/member_group.go b/internal/dms/service/member_group.go index ae6bae6a..d7d63219 100644 --- a/internal/dms/service/member_group.go +++ b/internal/dms/service/member_group.go @@ -27,27 +27,33 @@ func (d *DMSService) ListMemberGroups(ctx context.Context, req *dmsV1.ListMember orderBy = biz.MemberGroupFieldName } - filterBy := make([]pkgConst.FilterCondition, 0) + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + + andConditions := make([]pkgConst.FilterCondition, 0) if req.FilterByName != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.MemberGroupFieldName), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByName, }) } if req.ProjectUid != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.MemberGroupFieldProjectUID), Operator: pkgConst.FilterOperatorEqual, Value: req.ProjectUid, }) } + if len(andConditions) > 0 { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } + listOption := &biz.ListMemberGroupsOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, } memberGroups, total, err := d.MemberGroupUsecase.ListMemberGroups(ctx, listOption, req.ProjectUid) diff --git a/internal/dms/service/op_permission.go b/internal/dms/service/op_permission.go index 4460738b..292ba6d7 100644 --- a/internal/dms/service/op_permission.go +++ b/internal/dms/service/op_permission.go @@ -84,15 +84,12 @@ func (d *DMSService) ListOpPermissions(ctx context.Context, req *dmsV1.ListOpPer orderBy = biz.OpPermissionFieldName } - listOption := &biz.ListOpPermissionsOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - } + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + andConditions := make([]pkgConst.FilterCondition, 0) // 不支持智能调优时,隐藏相关权限 if !conf.IsOptimizationEnabled() { - listOption.FilterBy = append(listOption.FilterBy, + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.OpPermissionFieldUID), Operator: pkgConst.FilterOperatorNotEqual, @@ -106,7 +103,7 @@ func (d *DMSService) ListOpPermissions(ctx context.Context, req *dmsV1.ListOpPer } if req.Service != nil { - listOption.FilterBy = append(listOption.FilterBy, + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.OpPermissionFieldService), Operator: pkgConst.FilterOperatorEqual, @@ -114,16 +111,30 @@ func (d *DMSService) ListOpPermissions(ctx context.Context, req *dmsV1.ListOpPer }) } + if len(andConditions) > 0 { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } + + listOption := &biz.ListOpPermissionsOption{ + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, + } + var ops []*biz.OpPermission var total int64 switch req.FilterByTarget { case dmsV1.OpPermissionTargetAll: - listOption.FilterBy = append(listOption.FilterBy, + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.OpPermissionFieldRangeType), Operator: pkgConst.FilterOperatorNotEqual, Value: biz.OpRangeTypeGlobal, }) + if len(andConditions) > 0 { + listOption.FilterByOptions.Groups = append(listOption.FilterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } ops, total, err = d.OpPermissionUsecase.ListOpPermissions(ctx, listOption) if nil != err { return nil, err diff --git a/internal/dms/service/project.go b/internal/dms/service/project.go index 7c8c74ac..5b5f24b5 100644 --- a/internal/dms/service/project.go +++ b/internal/dms/service/project.go @@ -24,23 +24,25 @@ func (d *DMSService) ListProjects(ctx context.Context, req *dmsCommonV2.ListProj orderBy = biz.ProjectFieldName } - filterBy := make([]pkgConst.FilterCondition, 0) + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + + andConditions := make([]pkgConst.FilterCondition, 0) if req.FilterByName != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.ProjectFieldName), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByName, }) } if req.FilterByUID != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.ProjectFieldUID), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByUID, }) } if req.FilterByProjectPriority != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.ProjectFieldPriority), Operator: pkgConst.FilterOperatorEqual, Value: dmsCommonV1.ToPriorityNum(req.FilterByProjectPriority), @@ -48,48 +50,54 @@ func (d *DMSService) ListProjects(ctx context.Context, req *dmsCommonV2.ListProj } if len(req.FilterByProjectUids) > 0 { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.ProjectFieldUID), Operator: pkgConst.FilterOperatorIn, Value: req.FilterByProjectUids, }) } if req.FilterByDesc != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.ProjectFieldDesc), Operator: pkgConst.FilterOperatorContains, Value: req.FilterByDesc, }) } - // 添加模糊搜索条件 - if req.FuzzyKeyword != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ - Field: string(biz.ProjectFieldName), - Operator: pkgConst.FilterOperatorContains, - Value: req.FuzzyKeyword, - KeywordSearch: true, - }) - } - if req.FilterByBusinessTag != "" { businessTag, err := d.BusinessTagUsecase.GetBusinessTagByName(ctx, req.FilterByBusinessTag) if err != nil { d.log.Errorf("get business tag failed: %v", err) return nil, err } - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.ProjectFieldBusinessTagUID), Operator: pkgConst.FilterOperatorEqual, Value: businessTag.UID, }) } + if len(andConditions) > 0 { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } + + // 添加模糊搜索条件 + if req.FuzzyKeyword != "" { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicOr, + pkgConst.FilterCondition{ + Field: string(biz.ProjectFieldName), + Operator: pkgConst.FilterOperatorContains, + Value: req.FuzzyKeyword, + }, + )) + } + listOption := &biz.ListProjectsOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, } projects, total, err := d.ProjectUsecase.ListProject(ctx, listOption, currentUserUid) diff --git a/internal/dms/service/role.go b/internal/dms/service/role.go index 48fe0e6e..ac25ff25 100644 --- a/internal/dms/service/role.go +++ b/internal/dms/service/role.go @@ -88,29 +88,37 @@ func (d *DMSService) ListRoles(ctx context.Context, req *dmsV1.ListRoleReq) (rep orderBy = biz.RoleFieldCreatedAt } - filterBy := make([]pkgConst.FilterCondition, 0) + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + + andConditions := make([]pkgConst.FilterCondition, 0) if req.FilterByName != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.RoleFieldName), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByName, }) } + if len(andConditions) > 0 { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } + if req.FuzzyKeyword != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ - Field: string(biz.RoleFieldOpPermission), - Operator: pkgConst.FilterOperatorContains, - Value: req.FuzzyKeyword, - KeywordSearch: true, - }) + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicOr, + pkgConst.FilterCondition{ + Field: string(biz.RoleFieldOpPermission), + Operator: pkgConst.FilterOperatorContains, + Value: req.FuzzyKeyword, + }, + )) } listOption := &biz.ListRolesOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, } roles, total, err := d.RoleUsecase.ListRole(ctx, listOption) diff --git a/internal/dms/service/user.go b/internal/dms/service/user.go index deeb1137..4279e741 100644 --- a/internal/dms/service/user.go +++ b/internal/dms/service/user.go @@ -181,9 +181,11 @@ func (d *DMSService) ListUsers(ctx context.Context, req *dmsCommonV1.ListUserReq orderBy = biz.UserFieldName } - filterBy := make([]pkgConst.FilterCondition, 0) + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + + andConditions := make([]pkgConst.FilterCondition, 0) if req.FilterByName != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.UserFieldName), Operator: pkgConst.FilterOperatorEqual, Value: req.FilterByName, @@ -191,37 +193,43 @@ func (d *DMSService) ListUsers(ctx context.Context, req *dmsCommonV1.ListUserReq } if req.FilterByUids != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.UserFieldUID), Operator: pkgConst.FilterOperatorIn, Value: strings.Split(req.FilterByUids, ","), }) } - // 添加模糊搜索条件 - if req.FuzzyKeyword != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ - Field: string(biz.UserFieldName), - Operator: pkgConst.FilterOperatorContains, - Value: req.FuzzyKeyword, - KeywordSearch: true, - }) - } - // 默认为false,不展示已删除用户 if !req.FilterDeletedUser { - filterBy = append(filterBy, pkgConst.FilterCondition{ + andConditions = append(andConditions, pkgConst.FilterCondition{ Field: string(biz.UserFieldDeletedAt), Operator: pkgConst.FilterOperatorIsNull, Value: nil, }) } + if len(andConditions) > 0 { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup(pkgConst.FilterLogicAnd, andConditions...)) + } + + // 添加模糊搜索条件 + if req.FuzzyKeyword != "" { + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicOr, + pkgConst.FilterCondition{ + Field: string(biz.UserFieldName), + Operator: pkgConst.FilterOperatorContains, + Value: req.FuzzyKeyword, + }, + )) + } + listOption := &biz.ListUsersOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, } users, total, err := d.UserUsecase.ListUser(ctx, listOption) @@ -357,20 +365,24 @@ func (d *DMSService) ListUserGroups(ctx context.Context, req *dmsV1.ListUserGrou orderBy = biz.UserGroupFieldName } - filterBy := make([]pkgConst.FilterCondition, 0) + filterByOptions := pkgConst.NewFilterOptions(pkgConst.FilterLogicAnd) + if req.FilterByName != "" { - filterBy = append(filterBy, pkgConst.FilterCondition{ - Field: string(biz.UserGroupFieldName), - Operator: pkgConst.FilterOperatorEqual, - Value: req.FilterByName, - }) + filterByOptions.Groups = append(filterByOptions.Groups, pkgConst.NewConditionGroup( + pkgConst.FilterLogicAnd, + pkgConst.FilterCondition{ + Field: string(biz.UserGroupFieldName), + Operator: pkgConst.FilterOperatorEqual, + Value: req.FilterByName, + }, + )) } listOption := &biz.ListUserGroupsOption{ - PageNumber: req.PageIndex, - LimitPerPage: req.PageSize, - OrderBy: orderBy, - FilterBy: filterBy, + PageNumber: req.PageIndex, + LimitPerPage: req.PageSize, + OrderBy: orderBy, + FilterByOptions: filterByOptions, } groups, total, err := d.UserGroupUsecase.ListUserGroup(ctx, listOption) diff --git a/internal/dms/storage/cb_operation_log.go b/internal/dms/storage/cb_operation_log.go index c09996d5..8f0c0c67 100644 --- a/internal/dms/storage/cb_operation_log.go +++ b/internal/dms/storage/cb_operation_log.go @@ -73,7 +73,7 @@ func (d *CbOperationLogRepo) ListCbOperationLogs(ctx context.Context, opt *biz.L if opt.OrderBy != "" { db = db.Order(fmt.Sprintf("%s DESC", opt.OrderBy)) } - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list cb operation logs: %v", err) @@ -83,7 +83,7 @@ func (d *CbOperationLogRepo) ListCbOperationLogs(ctx context.Context, opt *biz.L // find total { db := tx.WithContext(ctx).Model(&model.CbOperationLog{}) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count cb operation logs: %v", err) } @@ -119,9 +119,10 @@ func (d *CbOperationLogRepo) CleanCbOperationLogOpTimeBefore(ctx context.Context func (d *CbOperationLogRepo) CountOperationLogs(ctx context.Context, opt *biz.ListCbOperationLogOption) (int64, error) { var total int64 + if err := transaction(d.log, ctx, d.db, func(tx *gorm.DB) error { db := tx.WithContext(ctx).Model(&model.CbOperationLog{}) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count cb operation logs: %v", err) } diff --git a/internal/dms/storage/data_export_task.go b/internal/dms/storage/data_export_task.go index 7528a609..f116fd5e 100644 --- a/internal/dms/storage/data_export_task.go +++ b/internal/dms/storage/data_export_task.go @@ -67,7 +67,7 @@ func (d *DataExportTaskRepo) ListDataExportTaskRecord(ctx context.Context, opt * // find models { db := tx.WithContext(ctx).Order(opt.OrderBy) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list data export task records: %v", err) @@ -77,7 +77,7 @@ func (d *DataExportTaskRepo) ListDataExportTaskRecord(ctx context.Context, opt * // find total { db := tx.WithContext(ctx).Model(&model.DataExportTaskRecord{}) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count data export task records: %v", err) } @@ -112,7 +112,7 @@ func (d *DataExportTaskRepo) ListDataExportTasks(ctx context.Context, opt *biz.L // find models { db := tx.WithContext(ctx).Order(opt.OrderBy) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list data export task: %v", err) @@ -122,7 +122,7 @@ func (d *DataExportTaskRepo) ListDataExportTasks(ctx context.Context, opt *biz.L // find total { db := tx.WithContext(ctx).Model(&model.DataExportTask{}) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count data export task: %v", err) } diff --git a/internal/dms/storage/db_service.go b/internal/dms/storage/db_service.go index 328a7b97..3cf474d5 100644 --- a/internal/dms/storage/db_service.go +++ b/internal/dms/storage/db_service.go @@ -57,7 +57,7 @@ func (d *DBServiceRepo) ListDBServices(ctx context.Context, opt *biz.ListDBServi // find models { db := tx.WithContext(ctx).Order(string(opt.OrderBy)) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))).Preload("EnvironmentTag").Find(&models) if err := db.Error; err != nil { return fmt.Errorf("failed to list db service: %v", err) @@ -67,7 +67,7 @@ func (d *DBServiceRepo) ListDBServices(ctx context.Context, opt *biz.ListDBServi // find total { db := tx.WithContext(ctx).Model(&model.DBService{}) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count db service: %v", err) } diff --git a/internal/dms/storage/gateway.go b/internal/dms/storage/gateway.go index e066817f..d12ba407 100644 --- a/internal/dms/storage/gateway.go +++ b/internal/dms/storage/gateway.go @@ -116,7 +116,7 @@ func (r *GatewayRepo) ListGateways(ctx context.Context, opt *biz.ListGatewaysOpt // 查询网关列表 { db := tx.WithContext(ctx).Order(string(opt.OrderBy)) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))).Find(&gateways) if err := db.Error; err != nil { return fmt.Errorf("failed to list gateways: %v", err) @@ -126,7 +126,7 @@ func (r *GatewayRepo) ListGateways(ctx context.Context, opt *biz.ListGatewaysOpt // 查询总数 { db := tx.WithContext(ctx).Model(&model.Gateway{}) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count gateways: %v", err) } diff --git a/internal/dms/storage/member.go b/internal/dms/storage/member.go index 50a50256..4448d5b5 100644 --- a/internal/dms/storage/member.go +++ b/internal/dms/storage/member.go @@ -49,9 +49,7 @@ func (d *MemberRepo) ListMembers(ctx context.Context, opt *biz.ListMembersOption // find models { db := tx.WithContext(ctx).Preload("RoleWithOpRanges").Preload("OpPermissions").Order(opt.OrderBy) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Preload("User.Members.Project").Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list members: %v", err) @@ -61,9 +59,7 @@ func (d *MemberRepo) ListMembers(ctx context.Context, opt *biz.ListMembersOption // find total { db := tx.WithContext(ctx).Model(&model.Member{}) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count members: %v", err) } diff --git a/internal/dms/storage/member_group.go b/internal/dms/storage/member_group.go index 5389dfdb..71728d12 100644 --- a/internal/dms/storage/member_group.go +++ b/internal/dms/storage/member_group.go @@ -31,9 +31,7 @@ func (d *MemberGroupRepo) ListMemberGroups(ctx context.Context, opt *biz.ListMem // find models { db := tx.WithContext(ctx).Preload("RoleWithOpRanges").Preload("Users").Preload("OpPermissions").Order(opt.OrderBy) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err = db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list member groups: %v", err) @@ -43,9 +41,7 @@ func (d *MemberGroupRepo) ListMemberGroups(ctx context.Context, opt *biz.ListMem // find total { db := tx.WithContext(ctx).Model(&model.MemberGroup{}) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err = db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count member groups: %v", err) } diff --git a/internal/dms/storage/op_permission.go b/internal/dms/storage/op_permission.go index b8c1fad6..3cab212e 100644 --- a/internal/dms/storage/op_permission.go +++ b/internal/dms/storage/op_permission.go @@ -89,9 +89,7 @@ func (d *OpPermissionRepo) ListOpPermissions(ctx context.Context, opt *biz.ListO // find models { db := tx.WithContext(ctx).Order(opt.OrderBy) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list opPermissions: %v", err) @@ -101,9 +99,7 @@ func (d *OpPermissionRepo) ListOpPermissions(ctx context.Context, opt *biz.ListO // find total { db := tx.WithContext(ctx).Model(&model.OpPermission{}) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count opPermissions: %v", err) } diff --git a/internal/dms/storage/project.go b/internal/dms/storage/project.go index 7956b0cf..29b38fe7 100644 --- a/internal/dms/storage/project.go +++ b/internal/dms/storage/project.go @@ -63,9 +63,7 @@ func (d *ProjectRepo) ListProjects(ctx context.Context, opt *biz.ListProjectsOpt // find models { db := tx.WithContext(ctx).Order(opt.OrderBy) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list projects: %v", err) @@ -75,9 +73,7 @@ func (d *ProjectRepo) ListProjects(ctx context.Context, opt *biz.ListProjectsOpt // find total { db := tx.WithContext(ctx).Model(&model.Project{}) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count projects: %v", err) } diff --git a/internal/dms/storage/role.go b/internal/dms/storage/role.go index 2c9dacbc..01f87b2a 100644 --- a/internal/dms/storage/role.go +++ b/internal/dms/storage/role.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/actiontech/dms/internal/dms/biz" + pkgConst "github.com/actiontech/dms/internal/dms/pkg/constant" pkgErr "github.com/actiontech/dms/internal/dms/pkg/errors" "github.com/actiontech/dms/internal/dms/storage/model" @@ -137,12 +138,30 @@ func (d *RoleRepo) ReplaceOpPermissionsInRole(ctx context.Context, roleUid strin func (d *RoleRepo) ListRoles(ctx context.Context, opt *biz.ListRolesOption) (roles []*biz.Role, total int64, err error) { // 取出权限条件的值 opPermissionValue := "" - for i := 0; i < len(opt.FilterBy); { - if opt.FilterBy[i].Field == string(biz.RoleFieldOpPermission) { - opPermissionValue = opt.FilterBy[i].Value.(string) - opt.FilterBy = append(opt.FilterBy[:i], opt.FilterBy[i+1:]...) - } else { - i++ + filterByOptionsWithoutOpPermission := pkgConst.FilterOptions{ + Logic: opt.FilterByOptions.Logic, + Groups: make([]pkgConst.FilterConditionGroup, 0, len(opt.FilterByOptions.Groups)), + } + + for _, group := range opt.FilterByOptions.Groups { + newGroup := pkgConst.FilterConditionGroup{ + Logic: group.Logic, + Conditions: make([]pkgConst.FilterCondition, 0, len(group.Conditions)), + Groups: group.Groups, + } + + for _, condition := range group.Conditions { + if condition.Field == string(biz.RoleFieldOpPermission) { + if opPermissionValue == "" { + opPermissionValue = condition.Value.(string) + } + continue + } + newGroup.Conditions = append(newGroup.Conditions, condition) + } + + if len(newGroup.Conditions) > 0 || len(newGroup.Groups) > 0 { + filterByOptionsWithoutOpPermission.Groups = append(filterByOptionsWithoutOpPermission.Groups, newGroup) } } @@ -151,11 +170,7 @@ func (d *RoleRepo) ListRoles(ctx context.Context, opt *biz.ListRolesOption) (rol // find models { db := tx.WithContext(ctx).Order(string(opt.OrderBy) + " DESC") - for _, f := range opt.FilterBy { - if f.Field != string(biz.RoleFieldOpPermission) { - db = gormWhere(db, f) - } - } + db = gormWheresWithOptions(ctx, db, filterByOptionsWithoutOpPermission) if opPermissionValue != "" { db = db.Joins("JOIN role_op_permissions on roles.uid = role_op_permissions.role_uid"). Joins("JOIN op_permissions ON op_permissions.uid = role_op_permissions.op_permission_uid"). @@ -171,11 +186,7 @@ func (d *RoleRepo) ListRoles(ctx context.Context, opt *biz.ListRolesOption) (rol // find total { db := tx.WithContext(ctx).Model(&model.Role{}) - for _, f := range opt.FilterBy { - if f.Field != string(biz.RoleFieldOpPermission) { - db = gormWhere(db, f) - } - } + db = gormWheresWithOptions(ctx, db, filterByOptionsWithoutOpPermission) if opPermissionValue != "" { db = db.Joins("JOIN role_op_permissions on roles.uid = role_op_permissions.role_uid"). Joins("JOIN op_permissions ON op_permissions.uid = role_op_permissions.op_permission_uid"). diff --git a/internal/dms/storage/storage.go b/internal/dms/storage/storage.go index 67134e90..3a74e50f 100644 --- a/internal/dms/storage/storage.go +++ b/internal/dms/storage/storage.go @@ -112,23 +112,73 @@ func gormWhereCondition(condition pkgConst.FilterCondition) (string, interface{} return fmt.Sprintf("%s %s ?", condition.Field, condition.Operator), condition.Value } -func gormWheres(ctx context.Context, db *gorm.DB, conditions []pkgConst.FilterCondition) *gorm.DB { - fuzzyWhere := db.WithContext(ctx) - singleWhere := db.WithContext(ctx) +func gormWheresWithOptions(ctx context.Context, db *gorm.DB, opts pkgConst.FilterOptions) *gorm.DB { + if len(opts.Groups) == 0 { + return db.WithContext(ctx) + } + + db = db.WithContext(ctx) + groupQueries := make([]*gorm.DB, 0, len(opts.Groups)) + + for _, group := range opts.Groups { + groupQuery := buildConditionGroup(db, group) + if groupQuery != nil { + groupQueries = append(groupQueries, groupQuery) + } + } + + if len(groupQueries) == 0 { + return db + } + + result := groupQueries[0] + for i := 1; i < len(groupQueries); i++ { + if opts.Logic == pkgConst.FilterLogicOr { + result = db.Where(result).Or(groupQueries[i]) + } else { + result = db.Where(result).Where(groupQueries[i]) + } + } + + return db.Where(result) +} + +func buildConditionGroup(db *gorm.DB, group pkgConst.FilterConditionGroup) *gorm.DB { + if len(group.Conditions) == 0 && len(group.Groups) == 0 { + return nil + } + + var result *gorm.DB - for _, condition := range conditions { + for i, condition := range group.Conditions { if condition.Table != "" { continue } - if condition.KeywordSearch { - // 模糊查询字段 - fuzzyWhere = fuzzyWhere.Or(gormWhere(singleWhere, condition)) + condQuery := gormWhere(db, condition) + if i == 0 || result == nil { + result = condQuery + } else if group.Logic == pkgConst.FilterLogicOr { + result = db.Where(result).Or(condQuery) } else { - db = gormWhere(db, condition) + result = db.Where(result).Where(condQuery) } } - db = db.Where(fuzzyWhere) - return db + + for _, subGroup := range group.Groups { + subQuery := buildConditionGroup(db, subGroup) + if subQuery == nil { + continue + } + if result == nil { + result = subQuery + } else if group.Logic == pkgConst.FilterLogicOr { + result = db.Where(result).Or(subQuery) + } else { + result = db.Where(result).Where(subQuery) + } + } + + return result } func gormPreload(ctx context.Context, db *gorm.DB, conditions []pkgConst.FilterCondition) *gorm.DB { @@ -147,6 +197,27 @@ func gormPreload(ctx context.Context, db *gorm.DB, conditions []pkgConst.FilterC return db } +func extractPreloadConditions(opts pkgConst.FilterOptions) []pkgConst.FilterCondition { + var conditions []pkgConst.FilterCondition + for _, group := range opts.Groups { + for _, condition := range group.Conditions { + if condition.Table != "" { + conditions = append(conditions, condition) + } + } + for _, subGroup := range group.Groups { + subConditions := extractPreloadConditions(pkgConst.FilterOptions{Groups: []pkgConst.FilterConditionGroup{subGroup}}) + conditions = append(conditions, subConditions...) + } + } + return conditions +} + +func gormPreloadFromOptions(ctx context.Context, db *gorm.DB, opts pkgConst.FilterOptions) *gorm.DB { + conditions := extractPreloadConditions(opts) + return gormPreload(ctx, db, conditions) +} + func fixPageIndices(page_number uint32) int { if page_number <= 0 { page_number = 1 diff --git a/internal/dms/storage/user.go b/internal/dms/storage/user.go index 83895e4d..e9189781 100644 --- a/internal/dms/storage/user.go +++ b/internal/dms/storage/user.go @@ -160,9 +160,7 @@ func (d *UserRepo) ListUsers(ctx context.Context, opt *biz.ListUsersOption) (use // find models { db := tx.Unscoped().WithContext(ctx).Order(opt.OrderBy) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Preload("Members.Project").Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list users: %v", err) @@ -172,9 +170,7 @@ func (d *UserRepo) ListUsers(ctx context.Context, opt *biz.ListUsersOption) (use // find total { db := tx.Unscoped().WithContext(ctx).Model(&model.User{}) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count users: %v", err) } diff --git a/internal/dms/storage/user_group.go b/internal/dms/storage/user_group.go index 7f495227..919cfbed 100644 --- a/internal/dms/storage/user_group.go +++ b/internal/dms/storage/user_group.go @@ -120,9 +120,7 @@ func (d *UserGroupRepo) ListUserGroups(ctx context.Context, opt *biz.ListUserGro // find models { db := tx.WithContext(ctx).Order(opt.OrderBy) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list user groups: %v", err) @@ -132,9 +130,7 @@ func (d *UserGroupRepo) ListUserGroups(ctx context.Context, opt *biz.ListUserGro // find total { db := tx.WithContext(ctx).Model(&model.UserGroup{}) - for _, f := range opt.FilterBy { - db = gormWhere(db, f) - } + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count user groups: %v", err) } diff --git a/internal/dms/storage/workflow.go b/internal/dms/storage/workflow.go index 1a3b273b..1f78ade8 100644 --- a/internal/dms/storage/workflow.go +++ b/internal/dms/storage/workflow.go @@ -67,8 +67,8 @@ func (d *WorkflowRepo) ListDataExportWorkflows(ctx context.Context, opt *biz.Lis // find models { db := tx.WithContext(ctx).Order(fmt.Sprintf("%s DESC", opt.OrderBy)) - db = gormPreload(ctx, db, opt.FilterBy) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormPreloadFromOptions(ctx, db, opt.FilterByOptions) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) db = db.Limit(int(opt.LimitPerPage)).Offset(int(opt.LimitPerPage * (uint32(fixPageIndices(opt.PageNumber))))) if err := db.Find(&models).Error; err != nil { return fmt.Errorf("failed to list Workflows: %v", err) @@ -78,8 +78,8 @@ func (d *WorkflowRepo) ListDataExportWorkflows(ctx context.Context, opt *biz.Lis // find total { db := tx.WithContext(ctx).Model(&model.Workflow{}) - db = gormPreload(ctx, db, opt.FilterBy) - db = gormWheres(ctx, db, opt.FilterBy) + db = gormPreloadFromOptions(ctx, db, opt.FilterByOptions) + db = gormWheresWithOptions(ctx, db, opt.FilterByOptions) if err := db.Count(&total).Error; err != nil { return fmt.Errorf("failed to count Workflows: %v", err) }