Fix ledger queries sample (#655)

-Go chaincode - Paginated range query should return the bookmark so that next page can be requested
-Javascript chaincode - Make query return JSON consistent with Go chaincode
-Javascript app was broken at bookmark query due to invalid JSON parsing from inconsistent chaincode responses
-Javascript and Java app had incorrect comments

Signed-off-by: David Enyeart <enyeart@us.ibm.com>
This commit is contained in:
Dave Enyeart 2022-03-09 03:49:03 -05:00 committed by GitHub
parent 8d7f3ca037
commit 2f3e9ffe3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 27 deletions

View file

@ -128,7 +128,7 @@ public class App {
result = contract.evaluateTransaction("QueryAssets","{\"selector\":{\"docType\":\"asset\",\"owner\":\"Jin Soo\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}");
System.out.println("result: " + new String(result));
// Rich Query with Pagination (Only supported if CouchDB is used as state database)
// Range Query with Pagination
System.out.println("\n");
System.out.println("Evaluate Transaction:GetAssetsByRangeWithPagination assets 3-5");
result = contract.evaluateTransaction("GetAssetsByRangeWithPagination", "asset3", "asset6", "3","");

View file

@ -181,8 +181,8 @@ async function main() {
result = await contract.evaluateTransaction('AssetExists', 'asset7');
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
console.log('\n--> Submit Transaction: TransferAsset, transfer asset(asset2) to new owner(Tom)');
await contract.submitTransaction('TransferAsset', 'asset2', 'Tom');
console.log('\n--> Submit Transaction: TransferAsset, transfer asset(asset2) to new owner(Max)');
await contract.submitTransaction('TransferAsset', 'asset2', 'Max');
console.log('*** Result: committed');
console.log('\n--> Evaluate Transaction: ReadAsset, function returns information about an asset with ID(asset2)');
@ -190,15 +190,15 @@ async function main() {
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
// Rich Query with Pagination (Only supported if CouchDB is used as state database)
console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Tom" assets');
result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Tom"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', '');
console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Max" assets');
result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Max"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', '');
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
// Recover the bookmark from previous query. Normally it will be inside a variable.
const resultJson = JSON.parse(result.toString());
console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Tom" assets next page');
result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Tom"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', resultJson.ResponseMetadata.Bookmark);
console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Max" assets next page');
result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Max"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', resultJson.bookmark);
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
console.log('\n--> Submit Transaction: TransferAssetByColor, transfer all yellow assets to new owner(Michel)');
@ -224,14 +224,14 @@ async function main() {
result = await contract.evaluateTransaction('QueryAssets', '{"selector":{"docType":"asset","owner":"Jin Soo"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}');
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
// Rich Query with Pagination (Only supported if CouchDB is used as state database)
console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 1 of assets from asset3 to asset6 (asset3, asset4)');
result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset3', 'asset6', '2', '');
// Range Query with Pagination
console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 1 of assets from asset2 to asset6 (asset2, asset3)');
result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset2', 'asset6', '2', '');
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
// Rich Query with Pagination (Only supported if CouchDB is used as state database)
console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 2 of assets from asset3 to asset6 (asset4, asset5)');
result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset3', 'asset6', '2', 'asset4');
// Range Query with Pagination
console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 2 of assets from asset2 to asset6 (asset4, asset5)');
result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset2', 'asset6', '2', 'asset4');
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
console.log('*** all tests completed');

View file

@ -99,7 +99,7 @@ type Asset struct {
// HistoryQueryResult structure used for returning result of history query
type HistoryQueryResult struct {
Record *Asset `json:"record"`
TxId string `json:"txId"`
TxId string `json:"txId"`
Timestamp time.Time `json:"timestamp"`
IsDelete bool `json:"isDelete"`
}
@ -331,15 +331,24 @@ func getQueryResultForQueryString(ctx contractapi.TransactionContextInterface, q
// 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.
// Example: Pagination with Range Query
func (t *SimpleChaincode) GetAssetsByRangeWithPagination(ctx contractapi.TransactionContextInterface, startKey string, endKey string, pageSize int, bookmark string) ([]*Asset, error) {
func (t *SimpleChaincode) GetAssetsByRangeWithPagination(ctx contractapi.TransactionContextInterface, startKey string, endKey string, pageSize int, bookmark string) (*PaginatedQueryResult, error) {
resultsIterator, _, err := ctx.GetStub().GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark)
resultsIterator, responseMetadata, err := ctx.GetStub().GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark)
if err != nil {
return nil, err
}
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
}
// QueryAssetsWithPagination uses a query string, page size and a bookmark to perform a query

View file

@ -266,10 +266,9 @@ class Chaincode extends Contract {
results.results = await this._GetAllResults(iterator, false);
results.ResponseMetadata = {
RecordsCount: metadata.fetchedRecordsCount,
Bookmark: metadata.bookmark,
};
results.fetchedRecordsCount = metadata.fetchedRecordsCount;
results.bookmark = metadata.bookmark;
return JSON.stringify(results);
}
@ -289,10 +288,9 @@ class Chaincode extends Contract {
results.results = await this._GetAllResults(iterator, false);
results.ResponseMetadata = {
RecordsCount: metadata.fetchedRecordsCount,
Bookmark: metadata.bookmark,
};
results.fetchedRecordsCount = metadata.fetchedRecordsCount;
results.bookmark = metadata.bookmark;
return JSON.stringify(results);
}