mirror of
https://github.com/rancher/norman.git
synced 2025-04-28 03:20:08 +00:00
This change gives norman the ability to filter api requests based on the default value of fields. Before, it would filter on the actual data in the resource, and then apply default values to the resource before returning. Issue: https://github.com/rancher/rancher/issues/13418
122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"sort"
|
|
|
|
"github.com/rancher/norman/types"
|
|
"github.com/rancher/norman/types/convert"
|
|
)
|
|
|
|
func QueryFilter(opts *types.QueryOptions, schema *types.Schema, data []map[string]interface{}) []map[string]interface{} {
|
|
return ApplyQueryOptions(opts, schema, data)
|
|
}
|
|
|
|
func ApplyQueryOptions(options *types.QueryOptions, schema *types.Schema, data []map[string]interface{}) []map[string]interface{} {
|
|
data = ApplyQueryConditions(options.Conditions, schema, data)
|
|
data = ApplySort(options.Sort, data)
|
|
return ApplyPagination(options.Pagination, data)
|
|
}
|
|
|
|
func ApplySort(sortOpts types.Sort, data []map[string]interface{}) []map[string]interface{} {
|
|
name := sortOpts.Name
|
|
if name == "" {
|
|
name = "id"
|
|
}
|
|
|
|
sort.Slice(data, func(i, j int) bool {
|
|
left, right := i, j
|
|
if sortOpts.Order == types.DESC {
|
|
left, right = j, i
|
|
}
|
|
|
|
return convert.ToString(data[left][name]) < convert.ToString(data[right][name])
|
|
})
|
|
|
|
return data
|
|
}
|
|
|
|
func ApplyQueryConditions(conditions []*types.QueryCondition, schema *types.Schema, data []map[string]interface{}) []map[string]interface{} {
|
|
var result []map[string]interface{}
|
|
|
|
outer:
|
|
for _, item := range data {
|
|
for _, condition := range conditions {
|
|
if !condition.Valid(schema, item) {
|
|
continue outer
|
|
}
|
|
}
|
|
|
|
result = append(result, item)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func ApplyPagination(pagination *types.Pagination, data []map[string]interface{}) []map[string]interface{} {
|
|
if pagination == nil || pagination.Limit == nil {
|
|
return data
|
|
}
|
|
|
|
limit := *pagination.Limit
|
|
if limit < 0 {
|
|
limit = 0
|
|
}
|
|
|
|
total := int64(len(data))
|
|
|
|
// Reset fields
|
|
pagination.Next = ""
|
|
pagination.Previous = ""
|
|
pagination.Partial = false
|
|
pagination.Total = &total
|
|
pagination.First = ""
|
|
|
|
if len(data) == 0 {
|
|
return data
|
|
}
|
|
|
|
// startIndex is guaranteed to be a valid index
|
|
startIndex := int64(0)
|
|
if pagination.Marker != "" {
|
|
for i, item := range data {
|
|
id, _ := item["id"].(string)
|
|
if id == pagination.Marker {
|
|
startIndex = int64(i)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
previousIndex := startIndex - limit
|
|
if previousIndex <= 0 {
|
|
previousIndex = 0
|
|
}
|
|
nextIndex := startIndex + limit
|
|
if nextIndex > int64(len(data)) {
|
|
nextIndex = int64(len(data))
|
|
}
|
|
|
|
if previousIndex < startIndex {
|
|
pagination.Previous, _ = data[previousIndex]["id"].(string)
|
|
}
|
|
|
|
if nextIndex > startIndex && nextIndex < int64(len(data)) {
|
|
pagination.Next, _ = data[nextIndex]["id"].(string)
|
|
}
|
|
|
|
if startIndex > 0 || nextIndex < int64(len(data)) {
|
|
pagination.Partial = true
|
|
}
|
|
|
|
if pagination.Partial {
|
|
pagination.First, _ = data[0]["id"].(string)
|
|
|
|
lastIndex := int64(len(data)) - limit
|
|
if lastIndex > 0 && lastIndex < int64(len(data)) {
|
|
pagination.Last, _ = data[lastIndex]["id"].(string)
|
|
}
|
|
}
|
|
|
|
return data[startIndex:nextIndex]
|
|
}
|