Fix ledger queries sample - history and pagination (#288)

Fix history query results.
Fix paginated query results.

Signed-off-by: David Enyeart <enyeart@us.ibm.com>
This commit is contained in:
denyeart 2020-08-10 08:15:34 -04:00 committed by GitHub
parent 17dbe839f1
commit 1d6d557570
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -96,13 +96,19 @@ type Asset struct {
AppraisedValue int `json:"appraisedValue"` AppraisedValue int `json:"appraisedValue"`
} }
// QueryResult structure used for handling result of query // HistoryQueryResult structure used for returning result of history query
type QueryResult struct { type HistoryQueryResult struct {
Record *Asset Record *Asset `json:"record"`
TxId string `json:"txID"` TxID string `json:"txID"`
Timestamp time.Time `json:"timestamp"` Timestamp time.Time `json:"timestamp"`
FetchedRecordsCount int `json:"fetchedRecordsCount"` IsDelete bool `json:"isDelete"`
Bookmark string `json:"bookmark"` }
// PaginatedQueryResult structure used for returning paginated query results and metadata
type PaginatedQueryResult struct {
Records []*Asset `json:"records"`
FetchedRecordsCount int32 `json:"fetchedRecordsCount"`
Bookmark string `json:"bookmark"`
} }
// CreateAsset initializes a new asset in the ledger // CreateAsset initializes a new asset in the ledger
@ -158,13 +164,13 @@ func (t *SimpleChaincode) ReadAsset(ctx contractapi.TransactionContextInterface,
return nil, fmt.Errorf("asset %s does not exist", assetID) return nil, fmt.Errorf("asset %s does not exist", assetID)
} }
var asset *Asset var asset Asset
err = json.Unmarshal(assetBytes, &asset) err = json.Unmarshal(assetBytes, &asset)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return asset, nil return &asset, nil
} }
// DeleteAsset removes an asset key-value pair from the ledger // DeleteAsset removes an asset key-value pair from the ledger
@ -212,12 +218,12 @@ func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorI
if err != nil { if err != nil {
return nil, err return nil, err
} }
var asset *Asset var asset Asset
err = json.Unmarshal(queryResult.Value, &asset) err = json.Unmarshal(queryResult.Value, &asset)
if err != nil { if err != nil {
return nil, err return nil, err
} }
assets = append(assets, asset) assets = append(assets, &asset)
} }
return assets, nil return assets, nil
@ -325,12 +331,7 @@ func getQueryResultForQueryString(ctx contractapi.TransactionContextInterface, q
// The number of fetched records will be equal to or lesser than the page size. // The number of fetched records will be equal to or lesser than the page size.
// Paginated range queries are only valid for read only transactions. // Paginated range queries are only valid for read only transactions.
// Example: Pagination with Range Query // Example: Pagination with Range Query
func (t *SimpleChaincode) GetAssetsByRangeWithPagination( func (t *SimpleChaincode) GetAssetsByRangeWithPagination(ctx contractapi.TransactionContextInterface, startKey string, endKey string, pageSize int, bookmark string) ([]*Asset, error) {
ctx contractapi.TransactionContextInterface,
startKey,
endKey,
bookmark string,
pageSize int) ([]*Asset, error) {
resultsIterator, _, err := ctx.GetStub().GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark) resultsIterator, _, err := ctx.GetStub().GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark)
if err != nil { if err != nil {
@ -349,48 +350,49 @@ func (t *SimpleChaincode) GetAssetsByRangeWithPagination(
// Only available on state databases that support rich query (e.g. CouchDB) // Only available on state databases that support rich query (e.g. CouchDB)
// Paginated queries are only valid for read only transactions. // Paginated queries are only valid for read only transactions.
// Example: Pagination with Ad hoc Rich Query // Example: Pagination with Ad hoc Rich Query
func (t *SimpleChaincode) QueryAssetsWithPagination( func (t *SimpleChaincode) QueryAssetsWithPagination(ctx contractapi.TransactionContextInterface, queryString string, pageSize int, bookmark string) (*PaginatedQueryResult, error) {
ctx contractapi.TransactionContextInterface,
queryString,
bookmark string,
pageSize int) ([]*Asset, error) {
return getQueryResultForQueryStringWithPagination(ctx, queryString, int32(pageSize), bookmark) return getQueryResultForQueryStringWithPagination(ctx, queryString, int32(pageSize), bookmark)
} }
// getQueryResultForQueryStringWithPagination executes the passed in query string with // getQueryResultForQueryStringWithPagination executes the passed in query string with
// pagination info. The result set is built and returned as a byte array containing the JSON results. // pagination info. The result set is built and returned as a byte array containing the JSON results.
func getQueryResultForQueryStringWithPagination( func getQueryResultForQueryStringWithPagination(ctx contractapi.TransactionContextInterface, queryString string, pageSize int32, bookmark string) (*PaginatedQueryResult, error) {
ctx contractapi.TransactionContextInterface,
queryString string,
pageSize int32,
bookmark string) ([]*Asset, error) {
resultsIterator, _, err := ctx.GetStub().GetQueryResultWithPagination(queryString, pageSize, bookmark) resultsIterator, responseMetadata, err := ctx.GetStub().GetQueryResultWithPagination(queryString, pageSize, bookmark)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer resultsIterator.Close() defer resultsIterator.Close()
return constructQueryResponseFromIterator(resultsIterator) assets, err := constructQueryResponseFromIterator(resultsIterator)
if err != nil {
return nil, err
}
return &PaginatedQueryResult{
Records: assets,
FetchedRecordsCount: responseMetadata.FetchedRecordsCount,
Bookmark: responseMetadata.Bookmark,
}, nil
} }
// GetAssetHistory returns the chain of custody for an asset since issuance. // GetAssetHistory returns the chain of custody for an asset since issuance.
func (t *SimpleChaincode) GetAssetHistory(ctx contractapi.TransactionContextInterface, assetID string) ([]QueryResult, error) { func (t *SimpleChaincode) GetAssetHistory(ctx contractapi.TransactionContextInterface, assetID string) ([]HistoryQueryResult, error) {
resultsIterator, err := ctx.GetStub().GetHistoryForKey(assetID) resultsIterator, err := ctx.GetStub().GetHistoryForKey(assetID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer resultsIterator.Close() defer resultsIterator.Close()
var records []QueryResult var records []HistoryQueryResult
for resultsIterator.HasNext() { for resultsIterator.HasNext() {
response, err := resultsIterator.Next() response, err := resultsIterator.Next()
if err != nil { if err != nil {
return nil, err return nil, err
} }
var asset *Asset var asset Asset
err = json.Unmarshal(response.Value, &asset) err = json.Unmarshal(response.Value, &asset)
if err != nil { if err != nil {
return nil, err return nil, err
@ -400,10 +402,11 @@ func (t *SimpleChaincode) GetAssetHistory(ctx contractapi.TransactionContextInte
if err != nil { if err != nil {
return nil, err return nil, err
} }
record := QueryResult{ record := HistoryQueryResult{
TxId: response.TxId, TxID: response.TxId,
Timestamp: timestamp, Timestamp: timestamp,
Record: asset, Record: &asset,
IsDelete: response.IsDelete,
} }
records = append(records, record) records = append(records, record)
} }