Add pagination for query to get records #58
@ -321,6 +321,53 @@ func (k Keeper) RecordsFromAttributes(
|
|||||||
return records, nil
|
return records, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PaginatedRecordsFromAttributes gets a list of records whose attributes match all provided values
|
||||||
|
// with pagination.
|
||||||
|
func (k Keeper) PaginatedRecordsFromAttributes(
|
||||||
|
ctx sdk.Context,
|
||||||
|
attributes []*registrytypes.QueryRecordsRequest_KeyValueInput,
|
||||||
|
all bool,
|
||||||
|
pagination *query.PageRequest,
|
||||||
|
) ([]registrytypes.Record, *query.PageResponse, error) {
|
||||||
|
resultRecordIds := []string{}
|
||||||
|
for i, attr := range attributes {
|
||||||
|
suffix, err := QueryValueToJSON(attr.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
mapKey := collections.Join(attr.Key, string(suffix))
|
||||||
|
recordIds, err := k.getAttributeMapping(ctx, mapKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
resultRecordIds = recordIds
|
||||||
|
} else {
|
||||||
|
resultRecordIds = getIntersection(recordIds, resultRecordIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paginatedResultRecordIds, pageRes := paginate(resultRecordIds, pagination)
|
||||||
|
|
||||||
|
records := []registrytypes.Record{}
|
||||||
|
for _, id := range paginatedResultRecordIds {
|
||||||
|
record, err := k.GetRecordById(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if record.Deleted {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !all && len(record.Names) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
records = append(records, record)
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, pageRes, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO not recursive, and only should be if we want to support querying with whole sub-objects,
|
// TODO not recursive, and only should be if we want to support querying with whole sub-objects,
|
||||||
// which seems unnecessary.
|
// which seems unnecessary.
|
||||||
func QueryValueToJSON(input *registrytypes.QueryRecordsRequest_ValueInput) ([]byte, error) {
|
func QueryValueToJSON(input *registrytypes.QueryRecordsRequest_ValueInput) ([]byte, error) {
|
||||||
@ -734,6 +781,38 @@ func (k Keeper) tryTakeRecordRent(ctx sdk.Context, record registrytypes.Record)
|
|||||||
return k.SaveRecord(ctx, record)
|
return k.SaveRecord(ctx, record)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// paginate implements basic pagination over a list of objects
|
||||||
|
func paginate[T any](data []T, pagination *query.PageRequest) ([]T, *query.PageResponse) {
|
||||||
|
pageReq := initPageRequestDefaults(pagination)
|
||||||
|
|
||||||
|
offset := pageReq.Offset
|
||||||
|
limit := pageReq.Limit
|
||||||
|
countTotal := pageReq.CountTotal
|
||||||
|
|
||||||
|
totalItems := uint64(len(data))
|
||||||
|
start := offset
|
||||||
|
end := offset + limit
|
||||||
|
|
||||||
|
if start > totalItems {
|
||||||
|
if countTotal {
|
||||||
|
return []T{}, &query.PageResponse{Total: 0}
|
||||||
|
} else {
|
||||||
|
return []T{}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if end > totalItems {
|
||||||
|
end = totalItems
|
||||||
|
}
|
||||||
|
|
||||||
|
paginatedItems := data[start:end]
|
||||||
|
|
||||||
|
if countTotal {
|
||||||
|
return paginatedItems, &query.PageResponse{Total: end - start}
|
||||||
|
} else {
|
||||||
|
return paginatedItems, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getIntersection(a []string, b []string) []string {
|
func getIntersection(a []string, b []string) []string {
|
||||||
result := []string{}
|
result := []string{}
|
||||||
if len(a) < len(b) {
|
if len(a) < len(b) {
|
||||||
@ -760,3 +839,26 @@ func contains(arr []string, str string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/cosmos/cosmos-sdk/blob/v0.50.3/types/query/pagination.go#L141
|
||||||
|
// initPageRequestDefaults initializes a PageRequest's defaults when those are not set.
|
||||||
|
func initPageRequestDefaults(pageRequest *query.PageRequest) *query.PageRequest {
|
||||||
|
// if the PageRequest is nil, use default PageRequest
|
||||||
|
if pageRequest == nil {
|
||||||
|
pageRequest = &query.PageRequest{}
|
||||||
|
}
|
||||||
|
|
||||||
|
pageRequestCopy := *pageRequest
|
||||||
|
if len(pageRequestCopy.Key) == 0 {
|
||||||
|
pageRequestCopy.Key = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if pageRequestCopy.Limit == 0 {
|
||||||
|
pageRequestCopy.Limit = query.DefaultLimit
|
||||||
|
|
||||||
|
// count total results when the limit is zero/not supplied
|
||||||
|
pageRequestCopy.CountTotal = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pageRequestCopy
|
||||||
|
}
|
||||||
|
@ -43,7 +43,12 @@ func (qs queryServer) Records(c context.Context, req *registrytypes.QueryRecords
|
|||||||
var pageResp *query.PageResponse
|
var pageResp *query.PageResponse
|
||||||
var err error
|
var err error
|
||||||
if len(attributes) > 0 {
|
if len(attributes) > 0 {
|
||||||
records, err = qs.k.RecordsFromAttributes(ctx, attributes, all)
|
if req.Pagination != nil {
|
||||||
|
records, pageResp, err = qs.k.PaginatedRecordsFromAttributes(ctx, attributes, all, req.Pagination)
|
||||||
|
} else {
|
||||||
|
records, err = qs.k.RecordsFromAttributes(ctx, attributes, all)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user