mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
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:
parent
8d7f3ca037
commit
2f3e9ffe3e
4 changed files with 34 additions and 27 deletions
|
|
@ -4,8 +4,8 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Running TestApp:
|
// Running TestApp:
|
||||||
// gradle runApp
|
// gradle runApp
|
||||||
|
|
||||||
package application.java;
|
package application.java;
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ public class App {
|
||||||
result = contract.evaluateTransaction("QueryAssets","{\"selector\":{\"docType\":\"asset\",\"owner\":\"Jin Soo\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}");
|
result = contract.evaluateTransaction("QueryAssets","{\"selector\":{\"docType\":\"asset\",\"owner\":\"Jin Soo\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}");
|
||||||
System.out.println("result: " + new String(result));
|
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("\n");
|
||||||
System.out.println("Evaluate Transaction:GetAssetsByRangeWithPagination assets 3-5");
|
System.out.println("Evaluate Transaction:GetAssetsByRangeWithPagination assets 3-5");
|
||||||
result = contract.evaluateTransaction("GetAssetsByRangeWithPagination", "asset3", "asset6", "3","");
|
result = contract.evaluateTransaction("GetAssetsByRangeWithPagination", "asset3", "asset6", "3","");
|
||||||
|
|
|
||||||
|
|
@ -181,8 +181,8 @@ async function main() {
|
||||||
result = await contract.evaluateTransaction('AssetExists', 'asset7');
|
result = await contract.evaluateTransaction('AssetExists', 'asset7');
|
||||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||||
|
|
||||||
console.log('\n--> Submit Transaction: TransferAsset, transfer asset(asset2) to new owner(Tom)');
|
console.log('\n--> Submit Transaction: TransferAsset, transfer asset(asset2) to new owner(Max)');
|
||||||
await contract.submitTransaction('TransferAsset', 'asset2', 'Tom');
|
await contract.submitTransaction('TransferAsset', 'asset2', 'Max');
|
||||||
console.log('*** Result: committed');
|
console.log('*** Result: committed');
|
||||||
|
|
||||||
console.log('\n--> Evaluate Transaction: ReadAsset, function returns information about an asset with ID(asset2)');
|
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())}`);
|
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||||
|
|
||||||
// Rich Query with Pagination (Only supported if CouchDB is used as state database)
|
// Rich Query with Pagination (Only supported if CouchDB is used as state database)
|
||||||
console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Tom" assets');
|
console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Max" assets');
|
||||||
result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Tom"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', '');
|
result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Max"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', '');
|
||||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||||
|
|
||||||
// Recover the bookmark from previous query. Normally it will be inside a variable.
|
// Recover the bookmark from previous query. Normally it will be inside a variable.
|
||||||
const resultJson = JSON.parse(result.toString());
|
const resultJson = JSON.parse(result.toString());
|
||||||
|
|
||||||
console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Tom" assets next page');
|
console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Max" assets next page');
|
||||||
result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Tom"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', resultJson.ResponseMetadata.Bookmark);
|
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(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||||
|
|
||||||
console.log('\n--> Submit Transaction: TransferAssetByColor, transfer all yellow assets to new owner(Michel)');
|
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"]}');
|
result = await contract.evaluateTransaction('QueryAssets', '{"selector":{"docType":"asset","owner":"Jin Soo"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}');
|
||||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||||
|
|
||||||
// Rich Query with Pagination (Only supported if CouchDB is used as state database)
|
// Range Query with Pagination
|
||||||
console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 1 of assets from asset3 to asset6 (asset3, asset4)');
|
console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 1 of assets from asset2 to asset6 (asset2, asset3)');
|
||||||
result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset3', 'asset6', '2', '');
|
result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset2', 'asset6', '2', '');
|
||||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||||
|
|
||||||
// Rich Query with Pagination (Only supported if CouchDB is used as state database)
|
// Range Query with Pagination
|
||||||
console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 2 of assets from asset3 to asset6 (asset4, asset5)');
|
console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 2 of assets from asset2 to asset6 (asset4, asset5)');
|
||||||
result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset3', 'asset6', '2', 'asset4');
|
result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset2', 'asset6', '2', 'asset4');
|
||||||
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
|
||||||
|
|
||||||
console.log('*** all tests completed');
|
console.log('*** all tests completed');
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ type Asset struct {
|
||||||
// HistoryQueryResult structure used for returning result of history query
|
// HistoryQueryResult structure used for returning result of history query
|
||||||
type HistoryQueryResult struct {
|
type HistoryQueryResult struct {
|
||||||
Record *Asset `json:"record"`
|
Record *Asset `json:"record"`
|
||||||
TxId string `json:"txId"`
|
TxId string `json:"txId"`
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
IsDelete bool `json:"isDelete"`
|
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.
|
// 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(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 {
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryAssetsWithPagination uses a query string, page size and a bookmark to perform a query
|
// QueryAssetsWithPagination uses a query string, page size and a bookmark to perform a query
|
||||||
|
|
|
||||||
|
|
@ -266,10 +266,9 @@ class Chaincode extends Contract {
|
||||||
|
|
||||||
results.results = await this._GetAllResults(iterator, false);
|
results.results = await this._GetAllResults(iterator, false);
|
||||||
|
|
||||||
results.ResponseMetadata = {
|
results.fetchedRecordsCount = metadata.fetchedRecordsCount;
|
||||||
RecordsCount: metadata.fetchedRecordsCount,
|
|
||||||
Bookmark: metadata.bookmark,
|
results.bookmark = metadata.bookmark;
|
||||||
};
|
|
||||||
|
|
||||||
return JSON.stringify(results);
|
return JSON.stringify(results);
|
||||||
}
|
}
|
||||||
|
|
@ -289,10 +288,9 @@ class Chaincode extends Contract {
|
||||||
|
|
||||||
results.results = await this._GetAllResults(iterator, false);
|
results.results = await this._GetAllResults(iterator, false);
|
||||||
|
|
||||||
results.ResponseMetadata = {
|
results.fetchedRecordsCount = metadata.fetchedRecordsCount;
|
||||||
RecordsCount: metadata.fetchedRecordsCount,
|
|
||||||
Bookmark: metadata.bookmark,
|
results.bookmark = metadata.bookmark;
|
||||||
};
|
|
||||||
|
|
||||||
return JSON.stringify(results);
|
return JSON.stringify(results);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue