How to add an array of objects that I receive to an array inside of a struct? - struct

I am using Solidity with Hardhat and I am trying to loop through an array that I am receiving and adding it to an array that is inside of a struct. But I keep getting errors like:
Error: invalid address or ENS name (argument="name", value={"country":"United States","signature":"USA-123456","date":"5/6/2022"}, code=INVALID_ARGUMENT, version=contracts/5.6.2)
I have the following code in my Contract:
contract GlobalPassport {
event EmitPassportInfo(address[] citizenship);
struct PassportInfo {
address[] citizenship;
}
PassportInfo[] public citizen;
function createNewPassport(address[] memory _citizenship) public {
citizen.push(PassportInfo(_citizenship));
emit EmitPassportInfo(_citizenship);
}
}
And I am calling the function like this:
const person = {
citizenship: [
{
country: 'United States',
signature: 'USA-123456', // global country code known to everyone
date: timestamp
},
{
country: 'Colombia',
signature: 'COL-123456', // global country code known to everyone
date: timestamp
},
],
}
await globalPassportContract.createNewPassport(person.citizenship)
Could anyone point me in a good direction for this?

Related

Django Graphene writing mutations with multiple layers of nested foreign keys

How do you write the schema and query for nested foreign keys? I checked the docs and found no examples of how to do this. So here was my attempt based on github and stackoverflow answers lets say I have these models:
class Address(models.Model):
name = models.CharField()
class Person(models.Model):
name = models.CharField()
address = models.ForeignKey('Address', on_delete=models.CASCADE, blank=False, null=False)
class Blog(models.Model):
person = models.ForeignKey('Person', on_delete=models.CASCADE, blank=False, null=False)
text = models.TextField()
I tried writing a schema like this:
class AddressInput(graphene.InputObjectType):
name = graphene.String(required=True)
class PersonInput(graphene.InputObjectType):
name = graphene.String(required=True)
address =graphene.Field(AddressInput)
class CreateNewBlog(graphene.Mutation):
blog=graphene.Field(BlogType)
class Arguments:
address_data = AddressInput()
person_data = PersonInput()
text = graphene.String()
#staticmethod
def mutate(root, info, person_data=None, address_data=None, **input):
address = Address.objects.create(name=address_data.name)
person = Person.objects.create(address=address, name=person_data.name)
blog = Blog.objects.create(person =person, text=input['text'])
blog.save()
return CreateNewBlog(blog=blog)
and I used a query like this:
mutation {
CreateNewBlog(person: { address: {name: "aaa"},
name: "First Last" }, text: "hi hi") {
Blog {
person{
name
address{
name
}
},
text
}
}
}
I got this error message:
{
"errors": [
{
"message": "'NoneType' object has no attribute 'name'",
"locations": [
{
"line": 32,
"column": 9
}
],
"path": [
"CreateNewBlog"
]
}
],
"data": {
"CreateNewBlog": null
}
}
I think the issue is in the way I wrote the schema.py file. Where it does not work to nest InputFields inside another InputField. Is there any other ways to write a single mutation?
Okay, a few things here. Firstly, you should generate your schema.graphql file, because that'll show you the actual final shape of the schema being built by Graphene, which would've made your debugging easier. Or you could use GraphiQL to test out your queries and lets its documentation and autocomplete do the heavy lifting for you.
But on to the specifics, your Graphene mutation definition is going to be generating a mutation that looks like this:
input AddressInput {
name: String!
}
input PersonInput {
name: String!
address: AddressInput
}
type CreateNewBlogOutput {
blog: Blog
}
type Mutation {
CreateNewBlog(addressData: AddressInput, personData: PersonInput, text: String): CreateNewBlogOutput!
}
Worth noting that there are two ways for you to supply an AddressInput here, one at root, and one inside PersonInput. This probably isn't what you're intending to do. Secondly, none of the root arguments are required, which is contributing to your error message being fairly unhelpful, because the problem is you're calling the mutation incorrect parameters but the query validator is letting it through because your types are very permissive.
I believe that if you were to run the mutation like the following, it'd actually work:
mutation {
CreateNewBlog(
personData: {
address: {
name: "aaa"
},
name: "First Last"
},
text: "hi hi"
) {
blog {
person {
name
address {
name
}
}
text
}
}
}
I only made two changes here, person was changed to personData (to match your mutation definition, Graphene does the conversation from snake case to camel case automatically), and Blog to blog in the field selection.
But lets go a little further, here's how I would have made the mutation.
class AddressInput(graphene.InputObjectType):
name = graphene.String(required=True)
class PersonInput(graphene.InputObjectType):
name = graphene.String(required=True)
address = AddressInput(required=True)
class CreateNewBlogInput(graphene.InputObjectType):
person = PersonInput(required=True)
text = graphene.String(required=True)
class CreateNewBlogPayload(graphene.ObjectType):
blog = graphene.Field(BlogType, required=True)
class CreateNewBlog(graphene.Mutation):
class Arguments:
input_data = CreateNewBlogInput(required=True, name="input")
Output = CreateNewBlogPayload
#staticmethod
def mutate(root, info, input_data):
address = Address.objects.create(name=input_data.person.address.name)
person = Person.objects.create(address=address, name=input_data.person.name)
blog = Blog.objects.create(person=person, text=input_data.text)
blog.save()
return CreateNewBlogPayload(blog=blog)
I'd also change CreateNewBlog to createNewBlog when constructing Graphene's mutation object, because the GraphQL convention is to use lower camel case for mutations.
Then you'd run it like this:
mutation {
createNewBlog(
input: {
person: {
address: {
name: "aaa"
},
name: "First Last"
}
text: "hi hi"
}
) {
blog {
person {
name
address {
name
}
}
text
}
}
}
Why wrap the entire input in a single input field? Mainly because it makes calling the mutation easier in the client when using variables, you can just provide single input arg of the correct shape rather than multiple.
// So instead of this
mutation OldCreateNewBlog($person: PersonInput, $text: String) {
createNewBlog(
personData: $person
text: $text
) {
blog {
person {
name
address {
name
}
}
text
}
}
}
// You have this
mutation NewCreateNewBlog($input: CreateNewBlogInput!) {
createNewBlog(
input: $input
) {
blog {
person {
name
address {
name
}
}
text
}
}
}
The latter makes it easier to change the input shape over time and only have to make the change in one place in client code.

What is the name of the code format with spaces before attributes to keep them starting from the same column?

We can see a kind of code format like this Object:
{
name: "Jason",
age: 28
gender: "male"
}
Or in Ruby, we can define a factory like this:
FactoryBot.define do
factory :company do
email { FFaker::Internet.email }
phone { FFaker::PhoneNumber.short_phone_number }
status { :processing }
name { FFaker::Company.name }
identity_no { FFaker::Identification.ssn }
end
end
The space between key and value (or method and attribute) are dynamically changing according to the longest key name (or method name).
How do you name this kind of format? And how can I do this in Vim?

GraphQL arguments on Object in query

I want to execute a query like this:
{
houses(owner: "Thomas") {
id
color
cars(type: "Sports Car") {
name
year
}
}
}
But this returns an error:
"message": "Unknown argument \"type\" on field \"cars\" of type \"House\".",
However, I'm able to execute this properly:
cars(type: "Sports Car") {
name
year
}
Is what I'm trying to do even possible?
Thanks in advance!
Make sure that you have your resolver for cars set up as a sub query of houses. The result from the houses query should be passed as the root argument to the cars sub query.
type House {
id
color
cars( type: String! ): [ Car ]
}
type Car {
name
year
}
Your resolver might look like:
Query: {
async houses( root, args, context ) {
return { ... houses ... }
}
},
houses: {
async cars( root, args, context ) {
return { ... cars ... }
}
}
Then create a resolver for cars that is nested underneath the houses query. Here's an article on it if you are using graphql-tools from Apollo: Writing resolvers with graphql-tools
Hope this helps!

How do I use a remote method in one model to return info from another model?

So I've set up something really simple to learn how to use Loopback.
The models are as follows:
Person
- based on built in User model
food_pref
typeId (number)
personId (number)
food_type
type (string)
Relationships:
Person has many food_prefs (foreign key: personId)
food_pref belongs to Person (foreign key: personId)
food_pref belongs to food_type (foreign key: typeId)
An auto-generated method gets created that returns the food_prefs based on the id of the Person.
People/{id}/foodPrefs
This returns:
[
{
"typeId": 0,
"personId": 0,
"id": 0
}
]
What I want to do is add a separate remote method called "getPrefs" that returns the name of the type under food_type based on the typeId in food_pref.
So let's say typeId is 1 and id 1 in food_types is Italian Food then the remote method would return this:
{
"type": "Italian Food"
}
I was told to use Person.js and add something along these lines but I'm really confused about the include statement as well as what to do inside the brackets. Often it crashes with an error saying: Error: Relation "food_pref" is not defined for Person model, see what they recommended below:
module.exports = function(Person) {
Person.getPrefs = function(personId, cb) {
Person.findById(personId, { include: { food_pref: "food_type" } }, function(err, user) {
if (err) throw err;
});
}
Person.remoteMethod (
'getPrefs',
{
http: {path: '/getPrefs', verb: 'get'},
accepts: {arg: 'personId', type: 'number', http: { source: 'query' } },
returns: {arg: 'type', type: 'string'}
}
);
};
What am I doing wrong here?
Edit:
According to strongloop documentation when you define a personal remote method, strongloop automatically provides a callback that will returns datas if needed.
See below updated code
You want to include the food_pref relation as well as the food_type realation inside this food_pref. Get this into your getPrefs custom method:
Person.getPrefs = function(personId, cb) {
Person.findById(personId, {
include: [{
relation: 'food_pref',
scope: {
include: {
relation: 'food_type'
}}}
]},
function(err, personFound) {
if (err)
console.log(err);
else {
cb(null, personFound)
}
});
};
What it does: your personal method is called with the personId argument and a cb argument (automatically passed by strongloop !). Your method finds the right person by id, includes the relations (name of the type of food as well), then when the result has been fetched, the callback inside "Person.findById" calls the callback 'cb' with datas fetched (here personFound)
Person.remoteMethod(
'getPrefs', {
http: {path: '/:personId/getPrefs', verb: 'get'},
accepts: [{arg: 'personId', type: 'number'}],
returns: {arg: 'person', type: 'object'},
description: ['a person object']
}
);
Then the returned object should contain the name of the type of food.
Make sure you include the right relation names you have in your Person.json and so on.
If you just want the name of food pref, follow the same idea with different methods:
just send the string inside your object to the automatic callback argument 'cb' (and modify the registration to announce the kind of return your method sends)
search directly inside food_type table with a "where" condition (where personId = the id of the person you are looking for)
Take a look at the link at the link to strongloop doc as it is pretty and detailed regarding remote methods.
Hope it helped.

How do I limit the properties of a query based of a common subproperty?

Given the schema:
{
_id: ObjectID,
city:
{ units:
{ abc: {},
def: { tuid : String },
...
xxx: { tuid : String }
}
}
I would like to return, for a particular _id, all the properties of units who's subproperty tuid is, for example, 123.
I have searched for information about this but array operations keep popping up instead of what I need.
Thank you.

Resources