Merge pull request #2060 from wanyaoqi/feature/wyq/support-get-model-distinct-field

feature: support get model distinct field
This commit is contained in:
yunion-ci-robot
2019-08-02 12:13:04 +08:00
committed by GitHub
6 changed files with 156 additions and 1 deletions
+3 -1
View File
@@ -17,11 +17,11 @@ package db
import (
"context"
"net/http"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/sqlchemy"
"time"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/object"
@@ -108,6 +108,8 @@ type IModelManager interface {
/* name uniqueness scope, system/domain/project, default is system */
NamespaceScope() rbacutils.TRbacScope
ResourceScope() rbacutils.TRbacScope
QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error)
}
type IModel interface {
+86
View File
@@ -26,6 +26,7 @@ import (
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/object"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
@@ -263,6 +264,91 @@ func (manager *SModelBaseManager) ResourceScope() rbacutils.TRbacScope {
return rbacutils.ScopeSystem
}
func (manager *SModelBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
return q, nil
}
func (manager *SModelBaseManager) AllowGetPropertyDistinctField(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return true
}
func (manager *SModelBaseManager) GetPropertyDistinctField(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
im, ok := manager.GetVirtualObject().(IModelManager)
if !ok {
im = manager
}
fn, err := query.GetArray("field")
efs, _ := query.GetArray("extra_field")
fields := make([]string, len(fn))
// validate field
for i, f := range fn {
fields[i], err = f.GetString()
if err != nil {
return nil, httperrors.NewInputParameterError("can't get string field")
}
var hasField = false
for _, field := range manager.getTable().Fields() {
if field.Name() == fields[i] {
hasField = true
break
}
}
if !hasField {
return nil, httperrors.NewBadRequestError("model has no field %s", fields[i])
}
}
var res = jsonutils.NewDict()
q := im.Query()
q, err = ListItemQueryFilters(im, ctx, q, userCred, query, policy.PolicyActionList)
if err != nil {
return nil, err
}
var backupQuery = *q
// query field
for i := 0; i < len(fields); i++ {
var nq = backupQuery
nq.AppendField(nq.Field(fields[i]))
of, err := nq.Distinct().AllStringMap()
if err == sql.ErrNoRows {
continue
}
if err != nil && err != sql.ErrNoRows {
return nil, httperrors.NewInternalServerError("Query database error %s", err)
}
ofa := make([]string, len(of))
for j := 0; j < len(of); j++ {
ofa[j] = of[j][fields[i]]
}
res.Set(fields[i], jsonutils.Marshal(ofa))
}
// query extra field
for i := 0; i < len(efs); i++ {
nq := backupQuery
fe, _ := efs[i].GetString()
nqp, err := im.QueryDistinctExtraField(&nq, fe)
if err != nil {
return nil, err
}
ef, err := nqp.AllStringMap()
if err == sql.ErrNoRows {
continue
}
efa := make([]string, len(ef))
for i := 0; i < len(ef); i++ {
efa[i] = ef[i][fe]
}
if err != nil && err != sql.ErrNoRows {
return nil, httperrors.NewInternalServerError("Query database error %s", err)
}
res.Set(fe, jsonutils.Marshal(efa))
}
return res, nil
}
func (model *SModelBase) GetId() string {
return ""
}