Altering fabcar example hyperledger-fabric - hyperledger

I have been playing around with the hyperledger-fabric samples/fabcar example for a while and I am able to add more fields and functions in the fabcar.go but when I change the fields entirely. I am getting errors in deployment.
Here is an example of the changes I have made in fabcar.go.
type Car struct {
Name string `json:"Name"`
College string `json:"College"`
DOB string `json:"DOB"`
SecretCode string `json:"SecretCode"`
}
func (s *SmartContract) initLedger(APIstub shim.ChaincodeStubInterface) sc.Response {
cars := []Car{
Car{Name: "name1", College: "college1", DOB: "dob1", SecretCode: "secretcode1"},
Car{Name: "name2", College: "college2", DOB: "dob2", SecretCode: "secretcode2"},
Car{Name: "name3", College: "college3", DOB: "dob3", SecretCode: "secretcode3"},
Car{Name: "name4", College: "college4", DOB: "dob4", SecretCode: "secretcode4"},
}
i := 0
for i < len(cars) {
fmt.Println("i is ", i)
carAsBytes, _ := json.Marshal(cars[i])
APIstub.PutState("CAR"+strconv.Itoa(i), carAsBytes)
fmt.Println("Added", cars[i])
i = i + 1
}
return shim.Success(nil)
}
Here is the error that I get when I run startFabric.sh:
>Error: Error endorsing chaincode: rpc error: code = Unknown desc = Error starting container: Failed to generate platform-specific docker build: Error returned from build: 2 "# github.com/fabcar
chaincode/input/src/github.com/fabcar/fabcar.go:132: unknown Car field 'Make' in struct literal
chaincode/input/src/github.com/fabcar/fabcar.go:132: unknown Car field 'Model' in struct literal
chaincode/input/src/github.com/fabcar/fabcar.go:132: unknown Car field 'Colour' in struct literal
chaincode/input/src/github.com/fabcar/fabcar.go:132: unknown Car field 'Owner' in struct literal
chaincode/input/src/github.com/fabcar/fabcar.go:193: car.Owner undefined (type Car has no field or method Owner)
chaincode/input/src/github.com/fabcar/fabcar.go:211: car.Colour undefined (type Car has no field or method Colour)
"
I am using Mac OSX yosemite and I have tried cleaning the docker by removing all the data and starting again and I have also tried renaming the go file but nothing works. What am I doing wrong here?
output of go build command:
>go build
../../../../../go/src/github.com/hyperledger/fabric/protos/peer/admin.pb.go:74:8: use of vendored package not allowed
../../../../../go/src/github.com/hyperledger/fabric/protos/peer/admin.pb.go:77:8: use of vendored package not allowed
../../../../../go/src/github.com/hyperledger/fabric/protos/peer/chaincode.pb.go:9:8: use of vendored package not allowed
../../../../../go/src/github.com/hyperledger/fabric/protos/peer/init.go:21:2: use of vendored package not allowed
../../../../../go/src/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go:25:2: use of vendored package not allowed
../../../../../go/src/github.com/hyperledger/fabric/protos/peer/admin.pb.go:80:2: use of vendored package not allowed
../../../../../go/src/github.com/hyperledger/fabric/protos/peer/admin.pb.go:81:2: use of vendored package not allowed
../../../../../go/src/github.com/hyperledger/fabric/common/flogging/grpclogger.go:21:2: use of vendored package not allowed

It seems like you having a compilation error, while you changed structure of the Car to be
type Car struct {
Name string `json:"Name"`
College string `json:"College"`
DOB string `json:"DOB"`
SecretCode string `json:"SecretCode"`
}
While many function remained in fabcar.go are still trying to use this struct "old fashion" way, assuming previous model:
type Car struct {
Make string `json:"make"`
Model string `json:"model"`
Colour string `json:"colour"`
Owner string `json:"owner"`
}
For example:
func (s *SmartContract) createCar(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) != 5 {
return shim.Error("Incorrect number of arguments. Expecting 5")
}
var car = Car{Make: args[1], Model: args[2], Colour: args[3], Owner: args[4]}
carAsBytes, _ := json.Marshal(car)
APIstub.PutState(args[0], carAsBytes)
return shim.Success(nil)
}
I would suggest instead reusing declaration of Car struct just create your own and use it properly:
type Student struct {
Name string `json:"Name"`
College string `json:"College"`
DOB string `json:"DOB"`
SecretCode string `json:"SecretCode"`
}
And
func (s *SmartContract) initLedger(APIstub shim.ChaincodeStubInterface) sc.Response {
cars := []Student{
Student{Name: "name1", College: "college1", DOB: "dob1", SecretCode: "secretcode1"},
Student{Name: "name2", College: "college2", DOB: "dob2", SecretCode: "secretcode2"},
Student{Name: "name3", College: "college3", DOB: "dob3", SecretCode: "secretcode3"},
Student{Name: "name4", College: "college4", DOB: "dob4", SecretCode: "secretcode4"},
}
i := 0
for i < len(cars) {
fmt.Println("i is ", i)
carAsBytes, _ := json.Marshal(cars[i])
APIstub.PutState("CAR"+strconv.Itoa(i), carAsBytes)
fmt.Println("Added", cars[i])
i = i + 1
}
return shim.Success(nil)
}

well, check this link fabcar.go chaincode of hyperledger does not accept the changes and modification and always run previous chaincode, u will find the answer there, when u interact with the source code, don't forget to delete its previously used modules to completely imply ur code change!

Related

Processing temporary properties returned by map projections

Consider the following database schema:
type Actor {
actorId: ID!
name: String
movies: [Movie!]! #relationship(type: "ACTED_IN", direction: OUT)
}
type Movie {
movieId: ID!
title: String
description: String
year: Int
actors(limit: Int = 10): [Actor!]! #relationship(type: "ACTED_IN", direction: IN)
}
Now, I want to know what the top movies with most number of actors, along with the counts. The following Cypher works perfectly in Neo4j:
type Query {
getMoviesWithMostActors(limit: Int = 5): [Movie]
(
statement: """
MATCH (movie:Movie)
MATCH (movie) <-[act:ACTED_IN]- (:Actor)
WITH movie, count(act) AS actorCount
ORDER BY actorCount DESCENDING
LIMIT $limit
RETURN movie {.*, numActors: actorCount}
"""
)
}
However, it fails in GraphQL playground. I tried the following:
query {
this_works: getMoviesWithMostActorsbase(limit: 2) {
movieId
}
this_does_not_work: getMoviesWithMostActorsbase(limit: 2) {
movieId
numActors
}
}
This returned: GRAPHQL_VALIDATION_FAILED.
"GraphQLError: Cannot query field \"numActors\" on type \"Movie\"."
My question is how do I return temporary properties without modifying the type definitions itself. And since this is a dummy example and in fact I need to do it with multiple types of nodes and with different types of scoring (int/float/array), I want to know how to do it without frequently editing the schema whenever I want to add a new query.
Known Workarounds
Extend schema with multiple nullable properties.
Schema needs to be changed with every new query
Return a map and simulate a node object, as shown below.
Need to add 2 more types for every single type of nodes
Actual object types are lost
type MovieData {
identity: Int!
labels: [String]!
properties: Movie!
}
type MovieWithScore {
movieData: MovieData!
movieScore: String!
}
type Query {
getMoviesWithMostActors(limit: Int = 5): [MovieWithScore]
(
statement: """
MATCH (movie:Movie)
MATCH (movie) <-[act:ACTED_IN]- (:Actor)
WITH movie, count(act) AS actorCount
ORDER BY actorCount DESCENDING
LIMIT $limit
RETURN {
movieData: movie,
movieScore: 'number of actors: ' + toString(actorCount)
}
"""
)
}

Command line arguments parsing in ballerina similar to argparse in python

Is there any way to parse the command line arguments in ballerina? From what I have seen you can use only positional arguments. What I would like to do is something like this:
//main.bal
public function main(string? name, int? age) returns error? {
if (name is string && age is int) {
io:println("Hello " + name);
io:println("Age " + age.toString());
}
}
And then run the programm as follows:
bal run main.bal -- --name John --age=18
But this does not work, because it takes "--name" as the first positional argument and "John" as the second positional argument. So it throws an error:
error: invalid argument 'John' for parameter 'age', expected integer value
And if I run it as follows then it runs:
bal run main.bal -- John 18
The arguments can be passed by name if they are specified for options.
If the arguments are part of a record like
public type Details record {|
string name?;
int age?;
|};
and the main function has an included record parameter of this type to specify options
public function main(*Details f) {
string? name = f?.name;
int? age = f?.age;
if name is string && age is int {
io:println("Hello ", name);
io:println("Age ", age);
}
}
it can be run as follows
$ bal run main.bal -- --name=Jo --age=25
This was introduced in Swan Lake Alpha5 and the release note provides more information - https://ballerina.io/downloads/swan-lake-release-notes/swan-lake-alpha5/#improved-command-line-argument-parsing.
You can use configurable support for this.
Check this example:
import ballerina/io;
configurable string name = ?;
configurable int age = ?;
public function main() returns error? {
io:println("Hello " + name);
io:println("Age " + age.toString());
}
Then while running you can provide values as following:
bal run main.bal -- -Cname="Ballerina" -Cage=5
The result is
Hello Ballerina
Age 5
Check this guide for more details.

How to execute graphql #relation directive for various objects

I have the following typeDefs:
const typeDefs = `
type Movie {
genres: String
movieId: Int!
title: String
seenBy: [User] #cypher(statement: "with $this as m match (m)<-[:RATED]-(u:User) return u")
}
type User {
userId: Int!
name: String
seen: [Movie] #relation(name: "RATED", direction: "OUT")
recommended(first: Int = 5): [Movie] #cypher(statement: "with $this as u match (u)-->(:Movie)<--(:User)-->(reco:Movie) where not (u)-[:RATED]->(reco) return reco, count(*) as score order by score desc limit $first")
}
type Query {
movieById(movieId: Int!): Movie,
movieBySubstring(subString: String!): [Movie]
userById(userId: Int!): User
userBySubstring(subString: String!): [User]
}
`;
The problem are the fields on Movie and User with directives on it (seenBy, seen and recommended).
When I execute the queries movieById or userById and return only one object, the directives work fine.
However, when executing movieBySubstring or userBySubstring and return an array of objects, I get the error
Resolve function for \"Movie.seenBy\" returned undefined
Is there a way to do this?
I found a workaround for the problem. I had implemented custom resolvers for the movieBySubstring and userBySubstring queries and this was what caused the problem.
The solution was to use the #cypher directive in the query definition like so:
type Query {
movieById(movieId: Int!): Movie
moviesBySubstring(subString: String!): [Movie] #cypher (statement: "match (m:Movie) where m.title contains $subString return m")
userById(userId: Int!): User
usersBySubstring(subString: String!): [User] #cypher (statement: "match (u:User) where u.name contains $subString return u")
}
This solved the problem for me, however as I'm not experienced with cypher or neo4j I don't know if at some point this might hit limitations.

Neo4j: Relating a node to a specific node with the same name

I have a list of all of the US states and towns. States can have the same town names so I'm checking to make sure each town is connected to their respected state.
I have events connected to a town, but the problem is that my events are connecting to multiple towns in different states. How can I connect my new event to a town within a certain state?
This is my schema.
type State {
stateName: String!
stateAbbreviation: String!
towns: [Town] #relation(name: "STATE_OUT", direction: "OUT")
}
type Town {
state: String!
name: String!
events: [CraftShowEvent]
}
type Event {
name: String!
day: String!
month: String!
time: String!
town: String!
state: String!
}
when you are creating the graph database, make sure you have this data model between "Town" node and "Event" node
EVENT -> [] -> Town
WHERE
EVENT.town = Town.Name
AND
EVENT.state = Town.state
I just wanted to update my question in case anyone else ran into this. I was using neo4j and graphql which automatically generate the queries and mutations based on my graphql schema.
Instead I made modifications and used the #cypher directive. I needed more control of how my data was saved.
type Mutation {
setBatchTown(listOfTowns: [BatchTown]): Town
#cypher(statement:"""
UNWIND $listOfTowns AS el
MERGE (t:Town {name: el.name, state: el.state})
WITH t
MATCH (s:State)
WHERE t.state = s.name
CREATE (t)-[:STATE_OUT]->(s)
""")
setEvent(event: InputEvent): Event
#cypher(statement:"""
MERGE (e:Event { name: $event.name, day: $event.day, month: $event.month, time: $event.time, town: $event.town, state: $event.state })
WITH e
MATCH (s:State), (t:Town {name: e.town, state: e.state})
WHERE e.state = s.name AND e.town = t.name
MERGE (e)-[:TOWN_OF]->(t)
RETURN t
""")
}
Then when I make a request I could do something like this.
client.mutate({ variables: {
listOfTowns: [{
name: 'town1'
state: 'VA'
},
{
name: 'town2'
state: 'WA'
}]
}, mutation: CREATE_STATE_MUTATION })
.then(() => resolve())
.catch(err => reject(err))
})

How to create a custom Grails query

I'm new to Grails and I've some troubles with queries. I got two domain classes like this:
class Cliente {
String nombre
String cuit
String localidad
String establecimiento
static hasMany = [facturas: Factura]
}
class Factura {
String Proveedor
int sucursal
String numero
String letraFactura
Cliente cliente
Date fecha
String tipo
}
I want to list all elements in facturas with client name:
Result expected:
Proveedor|sucursal|numero|cliente_nombre|fecha
I've tried some different ways but always get the cliente_id not cliente_nombre.
I think I know what you are asking: given a client name, return a list of factura's, with the stipulation that the list of fields should contain the client name rather than the client id.
import org.hibernate.criterion.CriteriaSpecification
// given a client name
def clientNameToSearch = 'some name'
def crit = Factura.createCriteria()
def results = crit.list() {
createAlias('cliente', 'cli')
eq('cli.nombre', clientNameToSearch)
// optional transformer to output a map rather than a list
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
projections {
property('Proveedor', 'Proveedor')
property('sucursal', 'sucursal')
property('numero', 'numero')
property('cli.nombre', 'clienteNombre')
property('fecha', 'fecha')
}
}
results would then contain a list of maps, with each map having this structure:
[
Proveedor: ...,
sucursal: ...,
numero: ...,
clienteNombre: ...,
fecha: ...
]

Resources