github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/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  }