support get model distinct field

This commit is contained in:
wanyaoqi
2019-08-01 21:34:33 +08:00
parent 9e915526cb
commit 2051e618f5
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 ""
}
+17
View File
@@ -475,6 +475,23 @@ func (manager *SGuestManager) OrderByExtraFields(ctx context.Context, q *sqlchem
return q, nil
}
func (manager *SGuestManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
switch field {
case "account":
hosts := HostManager.Query().SubQuery()
cloudproviders := CloudproviderManager.Query().SubQuery()
cloudaccounts := CloudaccountManager.Query().SubQuery()
q = q.Join(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id")))
q = q.Join(cloudproviders, sqlchemy.Equals(hosts.Field("manager_id"), cloudproviders.Field("id")))
q = q.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id")))
q.GroupBy(cloudaccounts.Field("name"))
q.AppendField(cloudaccounts.Field("name", "account"))
default:
return nil, httperrors.NewBadRequestError("unsupport field %s", field)
}
return q, nil
}
func (guest *SGuest) GetHypervisor() string {
if len(guest.Hypervisor) == 0 {
return api.HYPERVISOR_DEFAULT
+20
View File
@@ -1666,6 +1666,26 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.
return q, nil
}
func (manager *SNetworkManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
switch field {
case "account":
vpcs := VpcManager.Query().SubQuery()
wires := WireManager.Query().SubQuery()
cloudproviders := CloudproviderManager.Query().SubQuery()
cloudaccounts := CloudaccountManager.Query().Distinct().SubQuery()
q = q.Join(wires, sqlchemy.Equals(q.Field("wire_id"), wires.Field("id")))
q = q.Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id")))
q = q.Join(cloudproviders, sqlchemy.Equals(vpcs.Field("manager_id"), cloudproviders.Field("id")))
q = q.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id")))
q.GroupBy(cloudaccounts.Field("name"))
q.AppendField(cloudaccounts.Field("name", "account"))
default:
return nil, httperrors.NewBadRequestError("unsupport field %s", field)
}
return q, nil
}
func (manager *SNetworkManager) InitializeData() error {
// set network status
networks := make([]SNetwork, 0)
+15
View File
@@ -224,6 +224,21 @@ func (man *SRouteTableManager) ValidateCreateData(ctx context.Context, userCred
return man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data)
}
func (manager *SRouteTableManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
switch field {
case "account":
cloudproviders := CloudproviderManager.Query().SubQuery()
cloudaccounts := CloudaccountManager.Query().Distinct().SubQuery()
q = q.Join(cloudproviders, sqlchemy.Equals(q.Field("manager_id"), cloudproviders.Field("id")))
q = q.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id")))
q.GroupBy(cloudaccounts.Field("name"))
q.AppendField(cloudaccounts.Field("name", "account"))
default:
return nil, httperrors.NewBadRequestError("unsupport field %s", field)
}
return q, nil
}
func (rt *SRouteTable) AllowPerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowPerform(userCred, rt, "purge")
}
+15
View File
@@ -674,6 +674,21 @@ func (manager *SVpcManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQue
return q, nil
}
func (manager *SVpcManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
switch field {
case "account":
cloudproviders := CloudproviderManager.Query().SubQuery()
cloudaccounts := CloudaccountManager.Query().Distinct().SubQuery()
q = q.Join(cloudproviders, sqlchemy.Equals(q.Field("manager_id"), cloudproviders.Field("id")))
q = q.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id")))
q.GroupBy(cloudaccounts.Field("name"))
q.AppendField(cloudaccounts.Field("name", "account"))
default:
return nil, httperrors.NewBadRequestError("unsupport field %s", field)
}
return q, nil
}
func (self *SVpc) SyncRemoteWires(ctx context.Context, userCred mcclient.TokenCredential) error {
ivpc, err := self.GetIVpc()
if err != nil {