mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-18 07:55:10 +00:00
[FAB-9386] Remove Marbles sample reference to Fauxton
Remove marbles sample chaincode references to Fauxton and outdated "data" wrapper. This change also synchronizes the marbles sample chaincode with fabric/examples/marbles02, for example it adds pagination support that is in fabric/examples/marbles02. Change-Id: Ie80c66d7b2f97081d21c5ea889b159e398b64777 Signed-off-by: Chris Elder <chris.elder@us.ibm.com>
This commit is contained in:
parent
9c6aceed38
commit
e7a1b76edb
1 changed files with 181 additions and 78 deletions
|
|
@ -1,20 +1,5 @@
|
|||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// ====CHAINCODE EXECUTION SAMPLES (CLI) ==================
|
||||
|
|
@ -33,8 +18,11 @@ under the License.
|
|||
// peer chaincode query -C myc1 -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'
|
||||
|
||||
// Rich Query (Only supported if CouchDB is used as state database):
|
||||
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesByOwner","tom"]}'
|
||||
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"tom\"}}"]}'
|
||||
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesByOwner","tom"]}'
|
||||
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"tom\"}}"]}'
|
||||
|
||||
// Rich Query with Pagination (Only supported if CouchDB is used as state database):
|
||||
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesWithPagination","{\"selector\":{\"owner\":\"tom\"}}","3",""]}'
|
||||
|
||||
// INDEXES TO SUPPORT COUCHDB RICH QUERIES
|
||||
//
|
||||
|
|
@ -73,23 +61,15 @@ under the License.
|
|||
// http://127.0.0.1:5984/
|
||||
|
||||
// Index for docType, owner.
|
||||
// Note that docType and owner fields must be prefixed with the "data" wrapper
|
||||
//
|
||||
// Index definition for use with Fauxton interface
|
||||
// {"index":{"fields":["data.docType","data.owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
|
||||
//
|
||||
// Example curl command line to define index in the CouchDB channel_chaincode database
|
||||
// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[\"data.docType\",\"data.owner\"]},\"name\":\"indexOwner\",\"ddoc\":\"indexOwnerDoc\",\"type\":\"json\"}" http://hostname:port/myc1_marbles/_index
|
||||
// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[\"docType\",\"owner\"]},\"name\":\"indexOwner\",\"ddoc\":\"indexOwnerDoc\",\"type\":\"json\"}" http://hostname:port/myc1_marbles/_index
|
||||
//
|
||||
|
||||
// Index for docType, owner, size (descending order).
|
||||
// Note that docType, owner and size fields must be prefixed with the "data" wrapper
|
||||
//
|
||||
// Index definition for use with Fauxton interface
|
||||
// {"index":{"fields":[{"data.size":"desc"},{"data.docType":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeSortDoc", "name":"indexSizeSortDesc","type":"json"}
|
||||
//
|
||||
// Example curl command line to define index in the CouchDB channel_chaincode database
|
||||
// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"data.size\":\"desc\"},{\"data.docType\":\"desc\"},{\"data.owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1_marbles/_index
|
||||
// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"size\":\"desc\"},{\"docType\":\"desc\"},{\"owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1_marbles/_index
|
||||
|
||||
// Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database):
|
||||
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}'
|
||||
|
|
@ -164,6 +144,10 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
|
|||
return t.getHistoryForMarble(stub, args)
|
||||
} else if function == "getMarblesByRange" { //get marbles based on range query
|
||||
return t.getMarblesByRange(stub, args)
|
||||
} else if function == "getMarblesByRangeWithPagination" {
|
||||
return t.getMarblesByRangeWithPagination(stub, args)
|
||||
} else if function == "queryMarblesWithPagination" {
|
||||
return t.queryMarblesWithPagination(stub, args)
|
||||
}
|
||||
|
||||
fmt.Println("invoke did not find func: " + function) //error
|
||||
|
|
@ -360,6 +344,59 @@ func (t *SimpleChaincode) transferMarble(stub shim.ChaincodeStubInterface, args
|
|||
return shim.Success(nil)
|
||||
}
|
||||
|
||||
// ===========================================================================================
|
||||
// constructQueryResponseFromIterator constructs a JSON array containing query results from
|
||||
// a given result iterator
|
||||
// ===========================================================================================
|
||||
func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorInterface) (*bytes.Buffer, error) {
|
||||
// buffer is a JSON array containing QueryResults
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString("[")
|
||||
|
||||
bArrayMemberAlreadyWritten := false
|
||||
for resultsIterator.HasNext() {
|
||||
queryResponse, err := resultsIterator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Add a comma before array members, suppress it for the first array member
|
||||
if bArrayMemberAlreadyWritten == true {
|
||||
buffer.WriteString(",")
|
||||
}
|
||||
buffer.WriteString("{\"Key\":")
|
||||
buffer.WriteString("\"")
|
||||
buffer.WriteString(queryResponse.Key)
|
||||
buffer.WriteString("\"")
|
||||
|
||||
buffer.WriteString(", \"Record\":")
|
||||
// Record is a JSON object, so we write as-is
|
||||
buffer.WriteString(string(queryResponse.Value))
|
||||
buffer.WriteString("}")
|
||||
bArrayMemberAlreadyWritten = true
|
||||
}
|
||||
buffer.WriteString("]")
|
||||
|
||||
return &buffer, nil
|
||||
}
|
||||
|
||||
// ===========================================================================================
|
||||
// addPaginationMetadataToQueryResults adds QueryResponseMetadata, which contains pagination
|
||||
// info, to the constructed query results
|
||||
// ===========================================================================================
|
||||
func addPaginationMetadataToQueryResults(buffer *bytes.Buffer, responseMetadata *pb.QueryResponseMetadata) *bytes.Buffer {
|
||||
|
||||
buffer.WriteString("[{\"ResponseMetadata\":{\"RecordsCount\":")
|
||||
buffer.WriteString("\"")
|
||||
buffer.WriteString(fmt.Sprintf("%v", responseMetadata.FetchedRecordsCount))
|
||||
buffer.WriteString("\"")
|
||||
buffer.WriteString(", \"Bookmark\":")
|
||||
buffer.WriteString("\"")
|
||||
buffer.WriteString(responseMetadata.Bookmark)
|
||||
buffer.WriteString("\"}}]")
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
// ===========================================================================================
|
||||
// getMarblesByRange performs a range query based on the start and end keys provided.
|
||||
|
||||
|
|
@ -386,32 +423,10 @@ func (t *SimpleChaincode) getMarblesByRange(stub shim.ChaincodeStubInterface, ar
|
|||
}
|
||||
defer resultsIterator.Close()
|
||||
|
||||
// buffer is a JSON array containing QueryResults
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString("[")
|
||||
|
||||
bArrayMemberAlreadyWritten := false
|
||||
for resultsIterator.HasNext() {
|
||||
queryResponse, err := resultsIterator.Next()
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
// Add a comma before array members, suppress it for the first array member
|
||||
if bArrayMemberAlreadyWritten == true {
|
||||
buffer.WriteString(",")
|
||||
}
|
||||
buffer.WriteString("{\"Key\":")
|
||||
buffer.WriteString("\"")
|
||||
buffer.WriteString(queryResponse.Key)
|
||||
buffer.WriteString("\"")
|
||||
|
||||
buffer.WriteString(", \"Record\":")
|
||||
// Record is a JSON object, so we write as-is
|
||||
buffer.WriteString(string(queryResponse.Value))
|
||||
buffer.WriteString("}")
|
||||
bArrayMemberAlreadyWritten = true
|
||||
buffer, err := constructQueryResponseFromIterator(resultsIterator)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
buffer.WriteString("]")
|
||||
|
||||
fmt.Printf("- getMarblesByRange queryResult:\n%s\n", buffer.String())
|
||||
|
||||
|
|
@ -554,38 +569,126 @@ func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString
|
|||
}
|
||||
defer resultsIterator.Close()
|
||||
|
||||
// buffer is a JSON array containing QueryRecords
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString("[")
|
||||
|
||||
bArrayMemberAlreadyWritten := false
|
||||
for resultsIterator.HasNext() {
|
||||
queryResponse, err := resultsIterator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Add a comma before array members, suppress it for the first array member
|
||||
if bArrayMemberAlreadyWritten == true {
|
||||
buffer.WriteString(",")
|
||||
}
|
||||
buffer.WriteString("{\"Key\":")
|
||||
buffer.WriteString("\"")
|
||||
buffer.WriteString(queryResponse.Key)
|
||||
buffer.WriteString("\"")
|
||||
|
||||
buffer.WriteString(", \"Record\":")
|
||||
// Record is a JSON object, so we write as-is
|
||||
buffer.WriteString(string(queryResponse.Value))
|
||||
buffer.WriteString("}")
|
||||
bArrayMemberAlreadyWritten = true
|
||||
buffer, err := constructQueryResponseFromIterator(resultsIterator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer.WriteString("]")
|
||||
|
||||
fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String())
|
||||
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// ====== Pagination =========================================================================
|
||||
// Pagination provides a method to retrieve records with a defined pagesize and
|
||||
// start point (bookmark). An empty string bookmark defines the first "page" of a query
|
||||
// result. Paginated queries return a bookmark that can be used in
|
||||
// the next query to retrieve the next page of results. Paginated queries extend
|
||||
// rich queries and range queries to include a pagesize and bookmark.
|
||||
//
|
||||
// Two examples are provided in this example. The first is getMarblesByRangeWithPagination
|
||||
// which executes a paginated range query.
|
||||
// The second example is a paginated query for rich ad-hoc queries.
|
||||
// =========================================================================================
|
||||
|
||||
// ====== Example: Pagination with Range Query ===============================================
|
||||
// getMarblesByRangeWithPagination performs a range query based on the start & end key,
|
||||
// page size and a bookmark.
|
||||
|
||||
// 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.
|
||||
// ===========================================================================================
|
||||
func (t *SimpleChaincode) getMarblesByRangeWithPagination(stub shim.ChaincodeStubInterface, args []string) pb.Response {
|
||||
|
||||
if len(args) < 4 {
|
||||
return shim.Error("Incorrect number of arguments. Expecting 4")
|
||||
}
|
||||
|
||||
startKey := args[0]
|
||||
endKey := args[1]
|
||||
//return type of ParseInt is int64
|
||||
pageSize, err := strconv.ParseInt(args[2], 10, 32)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
bookmark := args[3]
|
||||
|
||||
resultsIterator, responseMetadata, err := stub.GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
defer resultsIterator.Close()
|
||||
|
||||
buffer, err := constructQueryResponseFromIterator(resultsIterator)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
|
||||
bufferWithPaginationInfo := addPaginationMetadataToQueryResults(buffer, responseMetadata)
|
||||
|
||||
fmt.Printf("- getMarblesByRange queryResult:\n%s\n", bufferWithPaginationInfo.String())
|
||||
|
||||
return shim.Success(buffer.Bytes())
|
||||
}
|
||||
|
||||
// ===== Example: Pagination with Ad hoc Rich Query ========================================================
|
||||
// queryMarblesWithPagination uses a query string, page size and a bookmark to perform a query
|
||||
// for marbles. Query string matching state database syntax is passed in and executed as is.
|
||||
// The number of fetched records would be equal to or lesser than the specified page size.
|
||||
// Supports ad hoc queries that can be defined at runtime by the client.
|
||||
// If this is not desired, follow the queryMarblesForOwner example for parameterized queries.
|
||||
// Only available on state databases that support rich query (e.g. CouchDB)
|
||||
// Paginated queries are only valid for read only transactions.
|
||||
// =========================================================================================
|
||||
func (t *SimpleChaincode) queryMarblesWithPagination(stub shim.ChaincodeStubInterface, args []string) pb.Response {
|
||||
|
||||
// 0
|
||||
// "queryString"
|
||||
if len(args) < 3 {
|
||||
return shim.Error("Incorrect number of arguments. Expecting 3")
|
||||
}
|
||||
|
||||
queryString := args[0]
|
||||
//return type of ParseInt is int64
|
||||
pageSize, err := strconv.ParseInt(args[1], 10, 32)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
bookmark := args[2]
|
||||
|
||||
queryResults, err := getQueryResultForQueryStringWithPagination(stub, queryString, int32(pageSize), bookmark)
|
||||
if err != nil {
|
||||
return shim.Error(err.Error())
|
||||
}
|
||||
return shim.Success(queryResults)
|
||||
}
|
||||
|
||||
// =========================================================================================
|
||||
// getQueryResultForQueryStringWithPagination executes the passed in query string with
|
||||
// pagination info. Result set is built and returned as a byte array containing the JSON results.
|
||||
// =========================================================================================
|
||||
func getQueryResultForQueryStringWithPagination(stub shim.ChaincodeStubInterface, queryString string, pageSize int32, bookmark string) ([]byte, error) {
|
||||
|
||||
fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString)
|
||||
|
||||
resultsIterator, responseMetadata, err := stub.GetQueryResultWithPagination(queryString, pageSize, bookmark)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resultsIterator.Close()
|
||||
|
||||
buffer, err := constructQueryResponseFromIterator(resultsIterator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bufferWithPaginationInfo := addPaginationMetadataToQueryResults(buffer, responseMetadata)
|
||||
|
||||
fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", bufferWithPaginationInfo.String())
|
||||
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func (t *SimpleChaincode) getHistoryForMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
|
||||
|
||||
if len(args) < 1 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue