github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/query_response_generator.go (about) 1 /* 2 Copyright hechain. 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 commonledger "github.com/hechain20/hechain/common/ledger" 12 pb "github.com/hyperledger/fabric-protos-go/peer" 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 pendingQueryResults := txContext.GetPendingQueryResult(iterID) 23 totalReturnCount := txContext.GetTotalReturnCount(iterID) 24 25 for { 26 // if the total count has been reached, return the result and prevent the Next() being called 27 if *totalReturnCount >= totalReturnLimit { 28 return createQueryResponse(txContext, iterID, isPaginated, pendingQueryResults, *totalReturnCount) 29 } 30 31 queryResult, err := iter.Next() 32 switch { 33 case err != nil: 34 chaincodeLogger.Errorf("Failed to get query result from iterator") 35 txContext.CleanupQueryContext(iterID) 36 return nil, err 37 38 case queryResult == nil: 39 40 return createQueryResponse(txContext, iterID, isPaginated, pendingQueryResults, *totalReturnCount) 41 42 case !isPaginated && pendingQueryResults.Size() == q.MaxResultLimit: 43 // if explicit pagination is not used 44 // if the max number of results is queued up, cut batch, then add current result to pending batch 45 // MaxResultLimit is for batching between chaincode shim and handler 46 // MaxResultLimit does not limit the records returned to the client 47 batch := pendingQueryResults.Cut() 48 if err := pendingQueryResults.Add(queryResult); err != nil { 49 txContext.CleanupQueryContext(iterID) 50 return nil, err 51 } 52 *totalReturnCount++ 53 return &pb.QueryResponse{Results: batch, HasMore: true, Id: iterID}, nil 54 55 default: 56 if err := pendingQueryResults.Add(queryResult); err != nil { 57 txContext.CleanupQueryContext(iterID) 58 return nil, err 59 } 60 *totalReturnCount++ 61 } 62 } 63 } 64 65 func createQueryResponse(txContext *TransactionContext, iterID string, isPaginated bool, pendingQueryResults *PendingQueryResult, totalReturnCount int32) (*pb.QueryResponse, error) { 66 batch := pendingQueryResults.Cut() 67 68 if isPaginated { 69 // when explicit pagination is enabled, return the batch with the responseMetadata 70 bookmark := txContext.CleanupQueryContextWithBookmark(iterID) 71 responseMetadata := createResponseMetadata(totalReturnCount, bookmark) 72 responseMetadataBytes, err := proto.Marshal(responseMetadata) 73 if err != nil { 74 return nil, err 75 } 76 return &pb.QueryResponse{Results: batch, HasMore: false, Id: iterID, Metadata: responseMetadataBytes}, nil 77 } 78 79 // if explicit pagination is not used, then the end of the resultset has been reached, return the batch 80 txContext.CleanupQueryContext(iterID) 81 return &pb.QueryResponse{Results: batch, HasMore: false, Id: iterID}, nil 82 } 83 84 func createResponseMetadata(returnCount int32, bookmark string) *pb.QueryResponseMetadata { 85 responseMetadata := &pb.QueryResponseMetadata{} 86 responseMetadata.Bookmark = bookmark 87 responseMetadata.FetchedRecordsCount = int32(returnCount) 88 return responseMetadata 89 }