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
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)
}
"""
)
}
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.
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.
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))
})
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: ...
]