I'm working with Hyperledger Composer and when i submit a transaction , i have to add manually the ID of Asset and Participiant. Is there a way to set up these ID automatically Without add it whenever i have to submit a transaction? Is there a javascript example code of smart contract ? Thanks.
CTO file
participant Patient identified by ID_P {
o String ID_P
o String name
o String surname
o String Birth regex=/[0-9]+\-[0-9]+\-[0-9]/
o String CF regex=/[A-Z0-9]{11}/
}
asset Health_Provision identified by ID_CF {
o String ID_CF
o Type type
o String[] Date regex=/[0-9]+\-[0-9]+\-[0-9]/
o String NoteFromToDoctor
o String NoteFromToCup
o String Receipt
o String SignNRE
o String Priority
o String Name
o String Surname
o String CF
o String Birth
o String Exemption
o RequestSubstitution substate
o Make_Health_Provision_Prescription[] requests optional
o Make_Health_Provision_Reservation[] reqs optional
--> Patient Applicant
--> Doctor doctor
--> CUP cup
}
transaction SendPrescription {
o String NoteFromToDoctor
o RequestSubstitution substate
--> Health_Provision IDCF
--> Patient Applicant
--> Doctor newDoctor
}
Logic.js
function SendPrescription(tx) {
var IDCF = tx.IDCF;
tx.IDCF.doctor = tx.newDoctor;
return getAssetRegistry('org.example.healthdata.Health_Provision')
.then(function (assetRegistry) {
return assetRegistry.update(tx.IDCF);
});
I explain better : when i submit the send prescription transaction , i have to add manually the ID Asset every time i want to submit a transaction. But i want to automate this transition and i don't understand how i could do that.
In this image , when i have to submit the transaction , there are random numbers associated to Asset ID , Patient ID and Doctor ID. I have to add mandatorily the ID of my Asset ,Patient and Doctor manually every time i submit the transaction? In your opinion can i automate that?
enter image description here
Related
In my hyperledger composer app I want to write a named query that returns all persons with two specified hobbies.
The model for "Person" is the following:
participant Person identified by id {
o String id
o String firstName
o String lastName
o String email
--> Hobby[] hobbies optional
}
The model for "Hobby" is the following:
asset Hobby identified by id {
o String id
o String name
}
The named query has the following structure:
query selectPersonsByHobbies {
description: "Select all persons with the two specified hobbies."
statement:
SELECT org.comp.myapp.Person
WHERE //not sure what to put here//
}
I'm not sure what to put after the "WHERE" operator in order to achieve what I want.
Is this correct?:
query selectPersonsByHobbies {
description: "Select all persons with the two specified hobbies."
statement:
SELECT org.comp.myapp.Person
WHERE (hobbies CONTAINS ((name == _$hobby1) AND (name == _$hobby2)))
}
Or is the following correct?:
query selectPersonsByHobbies {
description: "Select all persons with the two specified hobbies."
statement:
SELECT org.comp.myapp.Person
WHERE (hobbies CONTAINS (name == _$hobby1) AND CONTAINS (name == _$hobby2))
}
UPDATE:
Following the answer suggested by Paul O'Mahony, here is how I understand the situation:
Given the following model for "Person":
participant Person identified by id {
o String id
o String firstName
o String lastName
o String email
o Hobby[] hobbies optional
}
and the following model for Hobby:
asset Hobby identified by id {
o String id
o String name
}
the following query would succeed in returning all persons with the two specified hobbies:
query selectPersonsByHobbies {
description: "Select all persons with the two specified hobbies."
statement:
SELECT org.comp.myapp.Person
WHERE ( hobbies CONTAINS [ _$hobby1, _$hobby2] )
}
.... the parameter values sent with the query (and to be inserted for _$hobby1 and _$hobby2, respectively) would have be the Ids of the respective hobbies, correct?
You can't presently, in the Composer Query language, use an aggregate 'AND' in Concepts for CONTAINS currently in the fashion you suggest (OR is fine, but AND you can't) - the name field is compared for each class entry (and it can't be both at the same time with AND). In 0.19.12 onwards of Composer - you could use a getnativeAPI() from a readonly Trxn Processor function to make the equivalent CONTAINS call natively to CouchDB query language.
The AND (as requested above) would work if the field was a String array eg String[] hobbies eg.
query selectPersonsByHobbies {
description: "Select all persons with the two specified hobbies."
statement:
SELECT org.comp.myapp.Person
WHERE ( hobbies CONTAINS [ _$hobby1, _$hobby2] )
}
but your field on Person would have to be Hobby[] hobbies optional (ie not an array of relationships ie relationship IDs as it is presently - ).
In my hyperledger composer app I want to write a named query that returns all persons with a certain hobby.
The model for "Person" is the following:
participant Person identified by id {
o String id
o String firstName
o String lastName
o String email
--> Hobby[] hobbies optional
}
The model for "Hobby" is the following:
asset Hobby identified by name {
o String name
}
The named query has the following structure:
query selectPersonsByHobby {
description: "Select all persons with a certain hobby."
statement:
SELECT org.comp.myapp.Person
WHERE //don't know what to put here//
}
I don't know what to put after the "WHERE" operator in order to achieve what I want.
I want something like the following:
query selectPersonsByHobby {
description: "Select all persons with a certain hobby."
statement:
SELECT org.comp.myapp.Person
WHERE (hobbies.contains(_$hobby))
}
Is this even possible ?
The short answer is that this query should work:
query selectConsultantsBySkill {
description: "Select all persons with a certain hobby."
statement:
SELECT org.comp.myapp.Person
WHERE (hobbies CONTAINS _$targetHobby)
}
But note that because your hobbies is an array of Relationships the targetHobby parameter will have to be something like resource:org.acme.Hobby#cycling . In a production scenario you would be 'calling' the query from a UI program so you could pre-pend the relationship syntax.
I guess this is just a test example, but I wonder if Hobby needs to be a relationship? It would be easier if not.
You could alternatively use a concept (and even an enumerated type within the concept!). Here is an example of a modified model and query with a concept:
participant Person identified by id {
o String id
o String firstName
o String lastName
o String email
o Interest[] passTime
}
concept Interest {
o String name
o String description
}
query selectConsultantsBySkill {
description: "Select all persons with a certain hobby."
statement:
SELECT org.comp.myapp.Person
WHERE (passTime CONTAINS (name == _$targetHobby ))
}
My model.cto file -
namespace org.acme.mynetwork
participant Client identified by ClientId {
o String ClientId
o String ClientName
o String[] Policies
o String[] RFQAraay
}
participant Insurer identified by InsurerId {
o String InsurerId
o String InsurerName
o String[] RFQArray
o String[] Quotes
o String[] Policies
}
asset RFQ identified by RFQId {
o String RFQId
o String ClientId
o String InsurerName
o String TypeOfInsurance
o String RiskAmunt
o String Status
o String currentOwner
o String[] Quotes
o String[] SelectedInsurer
o String LeadInsurer
o String[] FinalInsurer
}
participant Broker identified by BrokerId {
o String BrokerId
o String BrokerName
o String[] Clients
}
asset Quote identified by QuoteId {
o String QuoteId
o String InsurerName
o String InsurerId
o String Premium
o String Capacity
o String RFQId
}
transaction GenerateRFQ {
o String RFQId
o String ClientId
o String InsurerName
o String TypeOfInsurance
o String RiskAmount
o String[] InsurerAddresses
}
My Script.js file
/**
* Insurance script file
* #param {org.acme.mynetwork.GenerateRFQ} generate - the trade to be processed
* #transaction
*/
function generateRFQ(generate){
var RFQId = generate.RFQId ;
var today = new Date();
var y = today.getFullYear();
var m = today.getMonth();
var d = today.getDate();
return getAssetRegistry('org.acme.mynetwork.RFQ').then(function(assetRegistry){
var RFQregistry = assetRegistry;
RFQregistry.RFQId = generate.RFQId;
RFQregistry.ClientId = generate.ClientId
RFQregistry.InsuredName = generate.InsurerName;
RFQregistry.TypeOfInsurance = generate.TypeOfInsurance;
RFQregistry.RiskAmount = generate.RiskAmount;
RFQregistry.Status = "RFQ fired on "+ d + m + y;
RFQregistry. Insurer = generate.InsurerAddresses;
return assetRegistry.update(RFQregistry);
})
}
I'm using online playground. Submitting this transaction gives me an error:
Could not find any functions to execute for transaction org.acme.mynetwork.GenerateRFQ#ae28a855-ba3c-48fe-9404-291ad95b24c7
I've tried changing its name but still no good. However SampleTransaction business logic is working fine.
your problem is that you have not modeled a transaction (in your .cto file) called GenerateRFQ as in: org.acme.mynetwork.GenerateRFQ in your decorator.
So add the following (below) to your model file - then do a composer network update to update your business network (and chaincode) to recognise the newly modeled transaction (that you call in your script).
transaction GenerateRFQ {
...add your model elements or relationships here
}
There is one issue I noticed in your script (which needs to be under the /lib subdirectory of your network project). You assign a new Date() - this is non-deterministic code, so each peer that would execute this will execute the 'date' function and get a different timestamp.
Also - other things that you may wish to consider - (based on the model you posted here):
Clients should be a relationship to Broker - see a sample network here -> https://github.com/hyperledger/composer-sample-networks/blob/master/packages/trade-network/models/trading.cto for an example of relationships. There may be in fact more relationships to consider in your model (eg one to many etc). Lastly your transaction should ideally have a relationship back to the participants and assets that are being 'referenced' in your code (eg. Client, Insurer etc). Again, look at the model file link I sent you to get an idea - also look at the other samples here -> https://github.com/hyperledger/composer-sample-networks/tree/master/packages for pointers and review the model language guide here -> https://hyperledger.github.io/composer/unstable/reference/cto_language.html
I have the following working query which selects based on the key and value of a joined map.
#Query("select e from Entity e join e.dataAttributes da where " +
"(key(da) =:attrKey1 and :attrVal1 in (value(da)) )")
List<Entity> findByAttrributeValues(#Param("attrKey1") String attrKey1,
#Param("attrVal1") String attrVal1);
I would like to select based on 2 keys and 2 values, but am having difficulties. The following likely very naiieve attempt returns no results:
#Query("select e from Entity e join e.dataAttributes da where " +
"(key(da) =:attrKey1 and :attrVal1 in (value(da)) ) and " +
"(key(da) =:attrKey2 and :attrVal2 in (value(da)) )")
List<Entity> findByTwoAttrributeValues(#Param("attrKey1") String attrKey1,
#Param("attrVal1") String attrVal1,
#Param("attrKey2") String attrKey2,
#Param("attrVal2") String attrVal2);
I'm new to JPA, any guidence would be appreciated
So I have this solution :
#Query("select e from Entity e join e.dataAttributes da join e.dataAttributes da2 where " +
"(key(da) =:attrKey1 and :attrVal1 in (value(da)) ) and " +
"(key(da2) =:attrKey2 and :attrVal2 in (value(da2)) )")
List<Entity> findByTwoAttrributeValues(#Param("attrKey1") String attrKey1,
#Param("attrVal1") String attrVal1,
#Param("attrKey2") String attrKey2,
#Param("attrVal2") String attrVal2);
I needed to join again onto the dataAttributes with a second identifier. Works as expected now. Might not be the prettiest. If there's a better way let me know
Here is some psuedo code for my table:
List<IColumn<Foo>> columns = new ArrayList<IColumn<Foo>>();
columns.add(new PropertyColumn<Foo>(Model.of("Name"), "name", "name"));
columns.add(new PropertyColumn<Foo>(Model.of("Leader"), "leader.lastName",
leader.fullName"));
fooTable = new AjaxFallbackDefaultDataTable<Foo>("fooTable", columns,
provider, 10);
The class Foo contains among other fields:
private String name;
private User leader;
And class User contains Strings userName, password, firstName, lastName, email, along with:
public String getFullName() {
// Use blank strings in place of "null" literals
String f = firstName != null ? firstName: "";
String l = lastName != null ? lastName: "";
return (l + ", " + f);
}
Every Foo has a name, and every User has has a first and last name. However, not every Foo has a leader, so in the table above, there are several null/ blank values for leader. When the table is sorted by leader by clicking the column header, all Foo's without a leader are missing. When sorted again by name, they return, with blanks for leader.
Is there anyway to fix this? A preference where nulls always sort last would be best, but I'll take anything where they don't just disappear.
The correct sorting is a responsibility of the SortableDataProvider. If it is making items disappear, you should revise it's logic.