github.com/true-sqn/fabric@v2.1.1+incompatible/core/chaincode/query_response_generator.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package chaincode 8 9 import ( 10 "github.com/golang/protobuf/proto" 11 pb "github.com/hyperledger/fabric-protos-go/peer" 12 commonledger "github.com/hyperledger/fabric/common/ledger" 13 ) 14 15 type QueryResponseGenerator struct { 16 MaxResultLimit int 17 } 18 19 // BuildQueryResponse takes an iterator and fetch state to construct QueryResponse 20 func (q *QueryResponseGenerator) BuildQueryResponse(txContext *TransactionContext, iter commonledger.ResultsIterator, 21 iterID string, isPaginated bool, totalReturnLimit int32) (*pb.QueryResponse, error) { 22 23 pendingQueryResults := txContext.GetPendingQueryResult(iterID) 24 totalReturnCount := txContext.GetTotalReturnCount(iterID) 25 26 for { 27 // if the total count has been reached, return the result and prevent the Next() being called 28 if *totalReturnCount >= totalReturnLimit { 29 return createQueryResponse(txContext, iterID, isPaginated, pendingQueryResults, *totalReturnCount) 30 } 31 32 queryResult, err := iter.Next() 33 switch { 34 case err != nil: 35 chaincodeLogger.Errorf("Failed to get query result from iterator") 36 txContext.CleanupQueryContext(iterID) 37 return nil, err 38 39 case queryResult == nil: 40 41 return createQueryResponse(txContext, iterID, isPaginated, pendingQueryResults, *totalReturnCount) 42 43 case !isPaginated && pendingQueryResults.Size() == q.MaxResultLimit: 44 // if explicit pagination is not used 45 // if the max number of results is queued up, cut batch, then add current result to pending batch 46 // MaxResultLimit is for batching between chaincode shim and handler 47 // MaxResultLimit does not limit the records returned to the client 48 batch := pendingQueryResults.Cut() 49 if err := pendingQueryResults.Add(queryResult); err != nil { 50 txContext.CleanupQueryContext(iterID) 51 return nil, err 52 } 53 *totalReturnCount++ 54 return &pb.QueryResponse{Results: batch, HasMore: true, Id: iterID}, nil 55 56 default: 57 if err := pendingQueryResults.Add(queryResult); err != nil { 58 txContext.CleanupQueryContext(iterID) 59 return nil, err 60 } 61 *totalReturnCount++ 62 } 63 } 64 } 65 66 func createQueryResponse(txContext *TransactionContext, iterID string, isPaginated bool, pendingQueryResults *PendingQueryResult, totalReturnCount int32) (*pb.QueryResponse, error) { 67 68 batch := pendingQueryResults.Cut() 69 70 if isPaginated { 71 // when explicit pagination is enabled, return the batch with the responseMetadata 72 bookmark := txContext.CleanupQueryContextWithBookmark(iterID) 73 responseMetadata := createResponseMetadata(totalReturnCount, bookmark) 74 responseMetadataBytes, err := proto.Marshal(responseMetadata) 75 if err != nil { 76 return nil, err 77 } 78 return &pb.QueryResponse{Results: batch, HasMore: false, Id: iterID, Metadata: responseMetadataBytes}, nil 79 } 80 81 // if explicit pagination is not used, then the end of the resultset has been reached, return the batch 82 txContext.CleanupQueryContext(iterID) 83 return &pb.QueryResponse{Results: batch, HasMore: false, Id: iterID}, nil 84 85 } 86 87 func createResponseMetadata(returnCount int32, bookmark string) *pb.QueryResponseMetadata { 88 responseMetadata := &pb.QueryResponseMetadata{} 89 responseMetadata.Bookmark = bookmark 90 responseMetadata.FetchedRecordsCount = int32(returnCount) 91 return responseMetadata 92 }