region: make CustomizeFilterList logically

This commit is contained in:
Zexi Li
2018-10-27 14:29:08 +08:00
parent 5be11457af
commit 2cbf21655d
5 changed files with 112 additions and 21 deletions
+38 -7
View File
@@ -433,26 +433,57 @@ func listItems(manager IModelManager, ctx context.Context, userCred mcclient.Tok
q = q.Desc(orderByField)
}
}
if limit > 0 {
q = q.Limit(int(limit))
customizeFilters, err := manager.CustomizeFilterList(ctx, q, userCred, queryDict)
if err != nil {
return nil, err
}
if offset > 0 {
q = q.Offset(int(offset))
if customizeFilters.IsEmpty() {
if limit > 0 {
q = q.Limit(int(limit))
}
if offset > 0 {
q = q.Offset(int(offset))
}
}
retList, err := query2List(manager, ctx, userCred, q, queryDict)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
retConut := len(retList)
retList, err = manager.CustomizeFilterList(ctx, userCred, queryDict, retList)
// apply customizeFilters
retList, err = customizeFilters.DoApply(retList)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
if len(retList) != retConut {
totalCnt = int64(len(retList))
}
retResult := modules.ListResult{Data: retList, Total: int(totalCnt), Limit: int(limit), Offset: int(offset)}
return &retResult, nil
paginate := false
if !customizeFilters.IsEmpty() {
// query not use Limit and Offset, do manual pagination
paginate = true
}
return calculateListResult(retList, totalCnt, limit, offset, paginate), nil
}
func calculateListResult(data []jsonutils.JSONObject, total, limit, offset int64, paginate bool) *modules.ListResult {
if paginate {
// do offset first
if offset != 0 {
if total > offset {
data = data[offset:]
} else {
data = []jsonutils.JSONObject{}
}
}
// do limit
if total > limit {
data = data[:limit]
}
}
retResult := modules.ListResult{Data: data, Total: int(total), Limit: int(limit), Offset: int(offset)}
return &retResult
}
func (dispatcher *DBModelDispatcher) List(ctx context.Context, query jsonutils.JSONObject, ctxId string) (*modules.ListResult, error) {
+1 -1
View File
@@ -29,7 +29,7 @@ type IModelManager interface {
AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool
ValidateListConditions(ctx context.Context, userCred mcclient.TokenCredential, query *jsonutils.JSONDict) (*jsonutils.JSONDict, error)
ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error)
CustomizeFilterList(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, retList []jsonutils.JSONObject) ([]jsonutils.JSONObject, error)
CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*CustomizeListFilters, error)
ExtraSearchConditions(ctx context.Context, q *sqlchemy.SQuery, like string) []sqlchemy.ICondition
// fetch hook
+60
View File
@@ -0,0 +1,60 @@
package db
import (
"yunion.io/x/jsonutils"
)
type CustomizeListFilterFunc func(item jsonutils.JSONObject) (bool, error)
type CustomizeListFilters struct {
filters []CustomizeListFilterFunc
}
func NewCustomizeListFilters() *CustomizeListFilters {
return &CustomizeListFilters{
filters: []CustomizeListFilterFunc{},
}
}
func (f *CustomizeListFilters) Append(funcs ...CustomizeListFilterFunc) *CustomizeListFilters {
f.filters = append(f.filters, funcs...)
return f
}
func (f CustomizeListFilters) Len() int {
return len(f.filters)
}
func (f CustomizeListFilters) IsEmpty() bool {
return f.Len() == 0
}
func (f CustomizeListFilters) DoApply(objs []jsonutils.JSONObject) ([]jsonutils.JSONObject, error) {
filteredObjs := []jsonutils.JSONObject{}
for _, obj := range objs {
ok, err := f.singleApply(obj)
if err != nil {
return nil, err
}
if ok {
filteredObjs = append(filteredObjs, obj)
}
}
return filteredObjs, nil
}
func (f CustomizeListFilters) singleApply(obj jsonutils.JSONObject) (bool, error) {
if f.IsEmpty() {
return true, nil
}
for _, filter := range f.filters {
ok, err := filter(obj)
if err != nil {
return false, err
}
if !ok {
return false, nil
}
}
return true, nil
}
+2 -2
View File
@@ -75,8 +75,8 @@ func (manager *SModelBaseManager) ListItemFilter(ctx context.Context, q *sqlchem
return q, nil
}
func (manager *SModelBaseManager) CustomizeFilterList(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, retList []jsonutils.JSONObject) ([]jsonutils.JSONObject, error) {
return retList, nil
func (manager *SModelBaseManager) CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*CustomizeListFilters, error) {
return NewCustomizeListFilters(), nil
}
func (manager *SModelBaseManager) ExtraSearchConditions(ctx context.Context, q *sqlchemy.SQuery, like string) []sqlchemy.ICondition {
+11 -11
View File
@@ -1291,28 +1291,28 @@ func (self *SNetwork) isManaged() bool {
}
}
func (manager *SNetworkManager) CustomizeFilterList(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, retList []jsonutils.JSONObject) ([]jsonutils.JSONObject, error) {
func (manager *SNetworkManager) CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*db.CustomizeListFilters, error) {
filters := db.NewCustomizeListFilters()
if query.Contains("ip") {
ip, _ := query.GetString("ip")
ipInt, err := netutils.NewIPV4Addr(ip)
if err != nil {
return nil, err
}
ret := make([]jsonutils.JSONObject, 0)
for i := 0; i < len(retList); i++ {
guestIpStart, _ := retList[i].GetString("guest_ip_start")
guestIpEnd, _ := retList[i].GetString("guest_ip_end")
ipFilter := func(obj jsonutils.JSONObject) (bool, error) {
guestIpStart, _ := obj.GetString("guest_ip_start")
guestIpEnd, _ := obj.GetString("guest_ip_end")
guestIpStartInt, _ := netutils.NewIPV4Addr(guestIpStart)
guestIpEndInt, _ := netutils.NewIPV4Addr(guestIpEnd)
ipRange := netutils.NewIPV4AddrRange(guestIpStartInt, guestIpEndInt)
if ipRange.Contains(ipInt) {
ret = append(ret, retList[i])
}
return ipRange.Contains(ipInt), nil
}
return ret, nil
} else {
return manager.SStatusStandaloneResourceBaseManager.CustomizeFilterList(ctx, userCred, query, retList)
filters.Append(ipFilter)
}
return filters, nil
}
func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {