mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix(region): query distinct fields (#20300)
This commit is contained in:
@@ -50,4 +50,28 @@ func init() {
|
||||
fmt.Println(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type DistinctFieldsOption struct {
|
||||
MODULE string `help:"module name"`
|
||||
Field []string `help:"distinct field name to query"`
|
||||
ExtraField []string `help:"distinct field name to query"`
|
||||
ExtraResource string
|
||||
}
|
||||
R(&DistinctFieldsOption{}, "distinct-fields", "Query values of a distinct fields for a module", func(s *mcclient.ClientSession, args *DistinctFieldsOption) error {
|
||||
mod, err := modulebase.GetModule(s, args.MODULE)
|
||||
if err != nil || mod == nil {
|
||||
if err != nil {
|
||||
return fmt.Errorf("module %s not found %s", args.MODULE, err)
|
||||
}
|
||||
return fmt.Errorf("No module %s found", args.MODULE)
|
||||
}
|
||||
params := jsonutils.Marshal(args)
|
||||
result, err := mod.Get(s, "distinct-fields", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -383,6 +383,12 @@ type DistinctFieldInput struct {
|
||||
ExtraField []string
|
||||
}
|
||||
|
||||
type DistinctFieldsInput struct {
|
||||
Field []string
|
||||
ExtraField []string
|
||||
ExtraResource string
|
||||
}
|
||||
|
||||
type PostpaidExpireInput struct {
|
||||
Duration string `json:"duration"`
|
||||
ExpireTime time.Time `json:"expire_time"`
|
||||
|
||||
@@ -132,6 +132,7 @@ type IModelManager interface {
|
||||
|
||||
// 如果error为非空,说明没有匹配的field,如果为空,说明匹配上了
|
||||
QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error)
|
||||
QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error)
|
||||
|
||||
GetPagingConfig() *SPagingConfig
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/gotypes"
|
||||
"yunion.io/x/pkg/object"
|
||||
"yunion.io/x/pkg/util/rbacscope"
|
||||
"yunion.io/x/pkg/util/version"
|
||||
@@ -228,6 +229,10 @@ func (manager *SModelBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, fi
|
||||
return q, httperrors.ErrNotFound
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
|
||||
return q, httperrors.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*CustomizeListFilters, error) {
|
||||
return NewCustomizeListFilters(), nil
|
||||
}
|
||||
@@ -394,10 +399,6 @@ func (manager *SModelBaseManager) ResourceScope() rbacscope.TRbacScope {
|
||||
return rbacscope.ScopeSystem
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) AllowGetPropertyDistinctField(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) GetPagingConfig() *SPagingConfig {
|
||||
return nil
|
||||
}
|
||||
@@ -480,6 +481,94 @@ func (manager *SModelBaseManager) GetPropertyDistinctField(ctx context.Context,
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) GetPropertyDistinctFields(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
im, ok := manager.GetVirtualObject().(IModelManager)
|
||||
if !ok {
|
||||
im = manager
|
||||
}
|
||||
input := &apis.DistinctFieldsInput{}
|
||||
query.Unmarshal(input)
|
||||
if len(input.Field) == 0 && (len(input.ExtraResource) == 0 || len(input.ExtraField) == 0) {
|
||||
return nil, httperrors.NewMissingParameterError("field")
|
||||
}
|
||||
// validate field
|
||||
for _, fd := range input.Field {
|
||||
var hasField = false
|
||||
for _, field := range manager.getTable().Fields() {
|
||||
if field.Name() == fd {
|
||||
hasField = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasField {
|
||||
return nil, httperrors.NewBadRequestError("model has no field %s", fd)
|
||||
}
|
||||
}
|
||||
var err error
|
||||
q := im.Query()
|
||||
q, err = ListItemQueryFilters(im, ctx, q, userCred, query, policy.PolicyActionList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := jsonutils.NewDict()
|
||||
fields := jsonutils.NewArray()
|
||||
if len(input.Field) > 0 {
|
||||
sq := q.Copy()
|
||||
// query field
|
||||
for i := 0; i < len(input.Field); i++ {
|
||||
sq = sq.AppendField(sq.Field(input.Field[i]))
|
||||
}
|
||||
rows, err := sq.Distinct().Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
mMap, err := sq.Row2Map(rows)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Row2Map")
|
||||
}
|
||||
fields.Add(jsonutils.Marshal(mMap))
|
||||
}
|
||||
}
|
||||
result.Set("fields", fields)
|
||||
|
||||
extraFields := jsonutils.NewArray()
|
||||
if len(input.ExtraResource) > 0 && len(input.ExtraField) > 0 {
|
||||
// query extra field
|
||||
sq := q.Copy()
|
||||
em := GetModelManager(input.ExtraResource)
|
||||
if gotypes.IsNil(em) {
|
||||
return nil, httperrors.NewInputParameterError("invalid extra_resource %s", input.ExtraResource)
|
||||
}
|
||||
for _, field := range input.ExtraField {
|
||||
if gotypes.IsNil(em.TableSpec().ColumnSpec(field)) {
|
||||
return nil, httperrors.NewInputParameterError("resource %s does not have field %s", input.ExtraResource, field)
|
||||
}
|
||||
}
|
||||
sq, err := im.QueryDistinctExtraFields(sq, input.ExtraResource, input.ExtraField)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := sq.Distinct().Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
mMap, err := sq.Row2Map(rows)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Row2Map")
|
||||
}
|
||||
extraFields.Add(jsonutils.Marshal(mMap))
|
||||
}
|
||||
}
|
||||
result.Set("extra_fields", extraFields)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) BatchPreValidate(
|
||||
ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider,
|
||||
query jsonutils.JSONObject, data *jsonutils.JSONDict, count int,
|
||||
|
||||
@@ -808,6 +808,17 @@ func (manager *SGuestManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field
|
||||
return q, httperrors.ErrNotFound
|
||||
}
|
||||
|
||||
func (manager *SGuestManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
|
||||
switch resource {
|
||||
case NetworkManager.Keyword():
|
||||
guestnets := GuestnetworkManager.Query("guest_id", "network_id").SubQuery()
|
||||
q = q.LeftJoin(guestnets, sqlchemy.Equals(q.Field("id"), guestnets.Field("guest_id")))
|
||||
|
||||
return manager.SNetworkResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
|
||||
}
|
||||
return q, httperrors.ErrNotFound
|
||||
}
|
||||
|
||||
func (manager *SGuestManager) initHostname() error {
|
||||
guests := []SGuest{}
|
||||
q := manager.Query().IsNullOrEmpty("hostname")
|
||||
|
||||
@@ -178,6 +178,19 @@ func (manager *SNetworkResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.
|
||||
return q, httperrors.ErrNotFound
|
||||
}
|
||||
|
||||
func (manager *SNetworkResourceBaseManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
|
||||
switch resource {
|
||||
case NetworkManager.Keyword():
|
||||
netQuery := NetworkManager.Query().SubQuery()
|
||||
for _, field := range fields {
|
||||
q = q.AppendField(netQuery.Field(field))
|
||||
}
|
||||
q = q.Join(netQuery, sqlchemy.Equals(q.Field("network_id"), netQuery.Field("id")))
|
||||
return q, nil
|
||||
}
|
||||
return q, httperrors.ErrNotFound
|
||||
}
|
||||
|
||||
func (manager *SNetworkResourceBaseManager) OrderByExtraFields(
|
||||
ctx context.Context,
|
||||
q *sqlchemy.SQuery,
|
||||
|
||||
Reference in New Issue
Block a user