I am trying to run my test for my chaincode and this is what I am getting.
return useIdentity(aliceIdentity)
.then(() => {
// Submit the transaction.
const transaction = factory.newTransaction('com.james.demo', 'UpdateAppointment');
transaction.asset = factory.newRelationship('com.james.demo', 'Appointment', '2', '11/2/2017', '08:19','new','3');
transaction.newValue = '50';
return businessNetworkConnection.submitTransaction(transaction);
})
.should.be.rejectedWith(/does not have .* access to resource/);
I get this:
AssertionError: expected promise to be rejected with an error matching /does not have .* access to resource/ but it was fulfilled with undefined
This is what my code looks like:
/**
* Sample transaction processor function.
* #param {com.james.demo.UpdateAppointment} tx The sample transaction instance.
* #transaction
*/
function UpdateAppointment(tx, patient, doctor, origAppointment) {
// Save the old value of the asset.
var oldValue = tx.asset.value;
// Update the asset with the new value.
tx.asset.value = tx.newValue;
// Get the asset registry for the asset.
return getAssetRegistry('com.james.demo.Appointment')
.then(function (assetRegistry) {
// Update the asset in the asset registry.
return assetRegistry.update(tx.asset);
})
.then(function () {
console.log(JSON.stringify(tx));
});
}
This is the rule:
rule DoctorHasFullAccessToTheirAssets {
description: "Allow all participants full access to their assets"
participant(p): "com.james.demo.Doctor"
operation: ALL
resource(r): "com.james.demo.Appointment"
condition: (r.doctor.getIdentifier() === p.getIdentifier())
action: ALLOW
}
This is appointment
asset Appointment identified by appointmentId {
o String appointmentId
o String appointmentDate optional
o String appointmentTime optional
o String status optional
--> Doctor doctor optional
--> Patient owner optional
o String value optional
}
And doctor:
participant Doctor identified by npiId {
o String npiId
o String firstName
o String lastName
}
Inside UpdateAppointment I have a console.log command that isn't being executed, it appears. so I am thinking that my function isn't actually being executed.
Having multiple parameters in my UpdateAppointment, is that incorrect?
How do I get this test to pass?
I didn't see your modeled transaction ie com.james.demo.UpdateAppointment in your post. But you would just pass the UpdateAppointment transaction instance so:
function UpdateAppointment(tx) {
...
}
Then reference your patient, doctor (participants) and appointments (Asset listing, for example) via relationships in your transaction definition.
Check out this sample-network logic https://github.com/hyperledger/composer-sample-networks/blob/master/packages/trade-network/lib/logic.js and also how the relationships are modeled in the transaction (ie may be a similar thing for you: relationship of Appointment to: Patient (appointee and participant), doctor (participant in the appointment), origAppointment (Patient can have one-to-many relationship with appointments as a listing?). Anyway, you know your use case better. Point being, your transaction instance has the means to know who the participants are and what the asset instance is, when the transaction logic is being executed, via the Transaction Processor function - see more here https://hyperledger.github.io/composer/reference/js_scripts.html
hope this helps..
Related
I could be extremely wrong from the jump, but I am under the impression that when using GraphQL / Prisma / PostgreSQL as I am, many-to-many relationships can be implicit, however, I am having an extremely hard time doing this and an even harder time finding any helpful documentation online.
I am trying to make a new Model, DailyRoster which is just a date and an array of Driver instances. There needs to be a DailyRoster for every day, thus this makes it a many-to-many relationship, as Drivers can have a DailyRoster for every day, and a DailyRoster will have multiple drivers. This being said, the two models look like this inside of the schema.prisma file.
model Driver {
id String #id #unique #default(uuid())
/ * A whole bunch of irrelevant props * /
ownerId String
owner Owner #relation(fields: [ownerId], references: [id])
managers Manager[]
accidents Accident[]
messages Messages[]
notifiedMessages NotifiedMessages[]
dspId String?
dsp Dsp? #relation(fields: [dspId], references: [id])
weeklyReport WeeklyReport[]
chatrooms Chatroom[]
dailyRosters DailyRoster[]
}
model DailyRoster{
id String #id #unique #default(uuid())
date String #unique
drivers Driver[]
}
There are no errors or red syntax markers / lines on the code here, so I believe this is okay. Then, my mutation function on the backend looks as follows...
const createDailyRoster = async () => {
try{
return await db.dailyRoster.create({
data: {
date: date
}
})
}catch(err){
console.log(err)
}
}
const updateDailyRoster = async (rosterId) => {
return driverIds.forEach( async (driverId) => {
console.log(driverId)
try{
return await db.dailyRoster.update({
where: {
id: rosterId
},
data: {
drivers: {
connect: {
id: driverId
}
}
}
})
}
catch(err){
console.log(err)
}
})
}
Now, whenever I run the mutation and it first creates a DailyRoster with nothing but a date and an ID. Then, using the array of driverIds provided, it runs a forEach loop on the array and is supposed to connect the Drivers to the DailyRoster one by one, but it never gets this far, instead returning the following error on its first driver connection attempt:
An operation failed because it depends on one or more records that were required but not found. Expected 1 records to be connected, found only 0.
Please, someone with a better understanding of GraphQL / Prisma, help me out, am I doing something wrong with the connections or is it a schema related issue?
I am using the #return(MyConcept) in transaction function defination i.e in cto file.
Based on certain conditions in the transaction fuunction, I want the return type to be dynamic i.e sometimes it may return MyConcept1 and sometimes MyConcept2 or sometimes even null.
How can I achieve this?
use a 'master' Concept to hold the other optional Concepts
example:
participant Publisher identified by id {
o String id
}
asset myAsset identified by id {
o String id
o String value
}
concept MyConcept1 {
o String value
}
concept MyConcept2 {
o String value optional
}
concept MyConcept {
o MyConcept1 myc1 optional
o MyConcept2 myc2 optional
}
#returns(MyConcept)
transaction myTransaction {
--> myAsset
etc
}
my Transaction could return anything in that Concept you set
eg.
/**
* Handle a transaction that returns a concept.
* #param {org.sample.MyTransaction} transaction The transaction.
* #returns {org.sample.MyConcept} The concept.
* #transaction
*/
async function myTransaction(transaction) {
// other stuff
const factory = getFactory();
// assign values
var conceptData1 = factory.newConcept('org.sample', 'MyConcept1');
conceptData1.value = transaction.myAsset.value; // etc
//
// return master (you define myConceptdata) based on what was set .. some of which could be blank
return myConceptdata;
}
Within a transaction processor function within my hyperledger composer application I used the following line of code (in order to get the patient with the email address 'adam#gmail.com'):
let result = await query('selectPatientByEmail', {
"email": "adam#gmail.com"
});
The query is defined in the queries.qry file as follows:
query selectPatientByEmail {
description: "Select the patient with the given email address"
statement:
SELECT org.comp.app.Patient
WHERE (email == _$email) }
A Patient is defined as follows in the model.cto file:
participant Patient identified by id {
o String id
o String firstName
o String lastName
o String email
}
The problem is this: when I try to access the id of the returned patient, this is not possible. That is, result.id is "undefined"
How can I access the id of the patient returned?
This question is related to the following question:
how to define BusinessNetworkConnection in hyperledger-composer transaction processor?
remember that the results are going to be an array of JS objects.
So you would use a for loop to step through the results - then you can acccess any attribute of the object (per your model) eg.
let result = await query('selectPatientByEmail', {
"email": "adam#gmail.com"
});
for (var n = 0; n < result.length; n++) {
console.log("Patient Id is " + result[n].id );
// alternative : console.log("Patient Id is " + result[n].getIdentifier());
console.log("Patient Email is " + result[n].email);
}
The participant Patient that you have defined their is no attribute with name email. So The query selectPatientByEmail will always return the Empty Object {}. When you are calling result.id equivalent to {}.id which will be undefined
Following the tutorial, there is the query
query selectCommoditiesByOwner {
description: "Select all commodities based on their owner"
statement:
SELECT org.acme.biznet.Commodity
WHERE (owner == _$owner)
}
But nowhere is an example explaining how to request it
For the parameter owner, I tryed with the node variable owner
owner.toUri()
owner.getFullyQualifiedIdentifier()
"resource:" + owner.getFullyQualifiedIdentifier()
But nothing works
Does somebody has a working example?
Example on how to 'request it' is shown in the REST API section of the Queries tutorial https://hyperledger.github.io/composer/tutorials/queries
If you mean: request it from within a Transaction Processor function, using the APIs - there is an example in the same tutorial, of calling a Query function eg.
/**
* Remove all high volume commodities
* #param {org.acme.biznet.RemoveHighQuantityCommodities} remove - the remove to be processed
* #transaction
*/
function removeHighQuantityCommodities(remove) {
return getAssetRegistry('org.acme.biznet.Commodity')
.then(function (assetRegistry) {
return query('selectCommoditiesWithHighQuantity')
.then(function (results) {
// process results objects etc
so using your query - you might do something like:
var tx_owner = tx.owner; // passed into the Transaction Processor for example
return query('selectCommoditiesByOwner', {
"owner": tx_owner // eg "resource:org.acme.trading.Trader#trader1"
})
.then(function (results) {
// do something
hope this helps. See further reference here -> https://hyperledger.github.io/composer//reference/query-language
Model:
namespace org.acme.model
enum CustomerSegment {
o P
o E
}
asset Account identified by Account_No {
o String Account_No
--> Customer Account_Holder
o String Account_Type
o Integer Balance
}
participant Customer identified by Customer_ID {
o String Customer_ID
o String First_Name
o CustomerSegment Customer_Segment
}
transaction UpdateCustomerSegment{
--> Account A
--> Customer C
}
transaction changeBalance{
--> Account A
o Integer newBalance
}
event UCS_Event{
-->Account A
o String oldsegment
o String newsegment
}
event BalanceChangEvent{
-->Account A
o Integer oldbalance
o Integer newbalance
}
Script:
/**
* Place an order for a vehicle
* #param {org.acme.model.UpdateCustomerSegment} ucs - the transaction that calculated Customer Segment
* #transaction
*/
function UpdateCustomerSegment(ucs)
{
var CustomerID=ucs.C.Customer_ID;
var oldCS=ucs.C.Customer_Segment;
if(ucs.A.Balance>3000)
ucs.C.Customer_Segment="E"
else
ucs.C.Customer_Segment="P"
var cust = getParticipantRegistry('org.acme.model.Customer')
.then(function(participantRegistry){
return participantRegistry.update(ucs.C);
})
.then(function(){
//Emit Event
var event_g= getFactory().newEvent('org.acme.model','UCS_Event');
event_g.A=ucs.A;
event_g.oldsegment=oldCS;
event_g.newsegment=ucs.C.Customer_Segment
emit(event_g);
})
return cust;
}
What I need to do is -
Pass only the Account No. to the transaction.
the transaction should fetch the appropriate Customer - where customer ID is same as Account's Account Holder, and update the Customer's Customer Segment
which I am unable to do. is it even doable. I am new, so not sure.
in the above transaction I am passing both the Account No. and Customer ID
2nd Question
Can we update a Participant & Asset both in the same transaction ? if yes how.
3rd Question:
how to call one transaction from within another.
Your model looks good, now you need to write a Transaction Processor function that subscribes to UpdateCustomerSegment transaction and that implements your logic to change the customer segment of the customer, and then persist the customer.
The basic-sample-network includes a similar simple transaction processor:
/**
* Sample transaction processor function.
* #param {org.acme.sample.SampleTransaction} tx The sample transaction instance.
* #transaction
*/
function sampleTransaction(tx) {
// Save the old value of the asset.
var oldValue = tx.asset.value;
// Update the asset with the new value.
tx.asset.value = tx.newValue;
// Get the asset registry for the asset.
return getAssetRegistry('org.acme.sample.SampleAsset')
.then(function (assetRegistry) {
// Update the asset in the asset registry.
return assetRegistry.update(tx.asset);
})
.then(function () {
// Emit an event for the modified asset.
var event = getFactory().newEvent('org.acme.sample', 'SampleEvent');
event.asset = tx.asset;
event.oldValue = oldValue;
event.newValue = tx.newValue;
emit(event);
});
}