fabric-samples/commercial-paper/organization/digibank/contract/lib/queries.js
Arnaud J Le Hors 6d043af487 Add repolinter support
Fix link in SECURITY file, and add missing copyright and license
notices.

To check, run: repolinter --rulesetUrl https://github.com/hyperledger-labs/hyperledger-community-management-tools/raw/main/repo_structure/repolint.json

Signed-off-by: Arnaud J Le Hors <lehors@us.ibm.com>
2021-04-23 15:35:20 -04:00

217 lines
9.3 KiB
JavaScript

/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const State = require('../ledger-api/state.js');
//const CommercialPaper = require('./paper.js');
/**
* Query Class for query functions such as history etc
*
*/
class QueryUtils {
constructor(ctx, listName) {
this.ctx = ctx;
this.name = listName;
//this.supportedTypes = {};
}
// =========================================================================================
// getAssetHistory takes the composite key as arg, gets returns results as JSON to 'main contract'
// =========================================================================================
/**
* Get Asset History for a commercial paper
* @param {String} issuer the CP issuer
* @param {String} paperNumber commercial paper number
*/
async getAssetHistory(issuer, paperNumber) {
let ledgerKey = await this.ctx.stub.createCompositeKey(this.name, [issuer, paperNumber]);
const resultsIterator = await this.ctx.stub.getHistoryForKey(ledgerKey);
let results = await this.getAllResults(resultsIterator, true);
return results;
}
// ===========================================================================================
// queryKeyByPartial performs a partial query based on the namespace and asset key prefix provided
// Read-only function results are not typically submitted to ordering. If the read-only
// results are submitted to ordering, or if the query is used in an update transaction
// and submitted to ordering, then the committing peers will re-execute to guarantee that
// result sets are stable between endorsement time and commit time. The transaction is
// invalidated by the committing peers if the result set has changed between endorsement
// time and commit time.
//
// ===========================================================================================
/**
* queryOwner commercial paper
* @param {String} assetspace the asset space (eg MagnetoCorp's assets)
*/
async queryKeyByPartial(assetspace) {
if (arguments.length < 1) {
throw new Error('Incorrect number of arguments. Expecting 1');
}
// ie namespace + prefix to assets etc eg
// "Key":"org.papernet.paperMagnetoCorp0001" (0002, etc)
// "Partial":'org.papernet.paperlistMagnetoCorp"' (using partial key, find keys "0001", "0002" etc)
const resultsIterator = await this.ctx.stub.getStateByPartialCompositeKey(this.name, [assetspace]);
let method = this.getAllResults;
let results = await method(resultsIterator, false);
return results;
}
// ===== Example: Parameterized rich query =================================================
// queryKeyByOwner queries for assets based on a passed in owner.
// This is an example of a parameterized query accepting a single query parameter (owner).
// Only available on state databases that support rich query (e.g. CouchDB)
// =========================================================================================
/**
* queryKeyByOwner commercial paper
* @param {String} owner commercial paper owner
*/
async queryKeyByOwner(owner) {
//
let self = this;
if (arguments.length < 1) {
throw new Error('Incorrect number of arguments. Expecting owner name.');
}
let queryString = {};
queryString.selector = {};
// queryString.selector.docType = 'indexOwnerDoc';
queryString.selector.owner = owner;
// set to (eg) '{selector:{owner:MagnetoCorp}}'
let method = self.getQueryResultForQueryString;
let queryResults = await method(this.ctx, self, JSON.stringify(queryString));
return queryResults;
}
// ===== Example: Ad hoc rich query ========================================================
// queryAdhoc uses a query string to perform a query for marbles..
// Query string matching state database syntax is passed in and executed as is.
// Supports ad hoc queries that can be defined at runtime by the client.
// If this is not desired, follow the queryKeyByOwner example for parameterized queries.
// Only available on state databases that support rich query (e.g. CouchDB)
// example passed using VS Code ext: ["{\"selector\": {\"owner\": \"MagnetoCorp\"}}"]
// =========================================================================================
/**
* query By AdHoc string (commercial paper)
* @param {String} queryString actual MangoDB query string (escaped)
*/
async queryByAdhoc(queryString) {
if (arguments.length < 1) {
throw new Error('Incorrect number of arguments. Expecting ad-hoc string, which gets stringified for mango query');
}
let self = this;
if (!queryString) {
throw new Error('queryString must not be empty');
}
let method = self.getQueryResultForQueryString;
let queryResults = await method(this.ctx, self, JSON.stringify(queryString));
return queryResults;
}
// WORKER functions are below this line: these are called by the above functions, where iterator is passed in
// =========================================================================================
// getQueryResultForQueryString woerk function executes the passed-in query string.
// Result set is built and returned as a byte array containing the JSON results.
// =========================================================================================
/**
* Function getQueryResultForQueryString
* @param {Context} ctx the transaction context
* @param {any} self within scope passed in
* @param {String} the query string created prior to calling this fn
*/
async getQueryResultForQueryString(ctx, self, queryString) {
// console.log('- getQueryResultForQueryString queryString:\n' + queryString);
const resultsIterator = await ctx.stub.getQueryResult(queryString);
let results = await self.getAllResults(resultsIterator, false);
return results;
}
/**
* Function getAllResults
* @param {resultsIterator} iterator within scope passed in
* @param {Boolean} isHistory query string created prior to calling this fn
*/
async getAllResults(iterator, isHistory) {
let allResults = [];
let res = { done: false, value: null };
while (true) {
res = await iterator.next();
let jsonRes = {};
if (res.value && res.value.value.toString()) {
if (isHistory && isHistory === true) {
//jsonRes.TxId = res.value.tx_id;
jsonRes.TxId = res.value.txId;
jsonRes.Timestamp = res.value.timestamp;
jsonRes.Timestamp = new Date((res.value.timestamp.seconds.low * 1000));
let ms = res.value.timestamp.nanos / 1000000;
jsonRes.Timestamp.setMilliseconds(ms);
if (res.value.is_delete) {
jsonRes.IsDelete = res.value.is_delete.toString();
} else {
try {
jsonRes.Value = JSON.parse(res.value.value.toString('utf8'));
// report the commercial paper states during the asset lifecycle, just for asset history reporting
switch (jsonRes.Value.currentState) {
case 1:
jsonRes.Value.currentState = 'ISSUED';
break;
case 2:
jsonRes.Value.currentState = 'PENDING';
break;
case 3:
jsonRes.Value.currentState = 'TRADING';
break;
case 4:
jsonRes.Value.currentState = 'REDEEMED';
break;
default: // else, unknown named query
jsonRes.Value.currentState = 'UNKNOWN';
}
} catch (err) {
console.log(err);
jsonRes.Value = res.value.value.toString('utf8');
}
}
} else { // non history query ..
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Record = res.value.value.toString('utf8');
}
}
allResults.push(jsonRes);
}
// check to see if we have reached the end
if (res.done) {
// explicitly close the iterator
console.log('iterator is done');
await iterator.close();
return allResults;
}
} // while true
}
}
module.exports = QueryUtils;