Graphql ID resolves as string even if it's integer - graphql

I'm new to graphql and hope someone can explain me this ID type that is always string.
As sad in docs:
The ID scalar type represents a unique identifier, often used to re-fetch an object or as a key for a cache.
If you use, for example, some caching client like Apollo, each type
should have at least one ID. This allows us to perform a normalization
of queries, making it possible for us to update things in Apollo
internal redux store automatically based on the unique id
Ok, so i can use int, but how then i get my id as integer on client side?
Reason is simple, let's say i have Book type with id of type ID and author_id relation of type Int. Also i have Author type with id of type ID. And after i fetch book and author i will have book.author_id int and author.id string, but it's the same number!
What should i do? Use everywhere ID even for many to many relations? Make new scalar ID type that can be used as ID for re-fetch but will be of type Int?

From the spec:
The ID type is serialized in the same way as a String; however, it is not intended to be human‐readable. While it is often numeric, it should always serialize as a String... GraphQL is agnostic to ID format, and serializes to string to ensure consistency across many formats ID could represent, from small auto‐increment numbers, to large 128‐bit random numbers, to base64 encoded values, or string values of a format like GUID.
It's unclear why the client would care about comparing IDs in this context -- columns like author_id should generally be hidden from the client anyway, with the schema only exposing the related entity, not fields that are only used to link entities. That said, an ID is just an ID and a client shouldn't care whether it's a string or an integer as long as it's consistent. If you have one field returning an integer (Book.author_id) and another returning a string (Author.id), then that's a problem on the part of your schema.
The ID scalar can be used for any number of fields, not just the one field (which may or may not be named id). Similarly, if you want to use Int or String as the type for your id field you can -- this will not impact Apollo's ability to cache your results.

In apollo you can use typePolicies to determintate what field is used as unique identifier. That will resolve a pain of ID! type conversion to string.
const typePolicies = {
Book: {
keyFields: ['id'],
},
BookTag: {
keyFields: ['book_id', 'tag_id'],
}
}
return new ApolloClient({
cache: new InMemoryCache({ typePolicies }),
})

Related

many to many in gorm v2 error on foreign key

I'm finding it difficult to define many to many relationship using Gorm in following cases
features(feature_id, name, slug)
operations(operation_id, name, slug)
feature_operations(feature_id, operation_id)
type Feature struct {
FeatureID int64 `gorm:"primaryKey;column:feature_id" json:"feature_id"`
Name string `validate:"required" json:"name"`
Slug string `json:"slug"`
Status string `json:"status"`
Operations []Operation `gorm:"many2many:feature_operations;foreignKey:feature_id"`
appModels.BaseModel
}
When using feature_id, I get error
column feature_operations.feature_feature_id does not exist
When using id, I get error
invalid foreign key: id
Looks like you are not using the convention that gorm suggests where you name your primary key columns just id
so in your case your foreignKey should be the name of the field and you also need to use References to specify column that you want to reference. See the example here:
https://gorm.io/docs/many_to_many.html#Override-Foreign-Key
What you need is this:
type Feature struct {
FeatureID int64 `gorm:"primaryKey;column:feature_id"`
Name string
Slug string
Operations []Operation `gorm:"many2many:feature_operations;foreignKey:FeatureID;References:OperationID"`
}
type Operation struct {
OperationID int64 `gorm:"primaryKey;column:operation_id"`
Name string
Slug string
}
After this the join table will be FEATURE_OPERATIONS with two columns FEATURE_FEATURE_ID AND OPERATION_OPERATION_ID
If you dont like the redundant column names then you need to use the two additional attributes joinForeignKey and joinReferences to choose your own names for the columns like so:
gorm:"many2many:feature_operations;foreignKey:FeatureID;joinForeignKey:FeatureID;References:OperationID;joinReferences:OperationID"
All this extra work is needed because your primary keys are FEATURE_ID and OPERATION_ID instead of just ID
If you can rename the column to follow the convention, you will notice life is much easier with gorm

Getting a "Duplicate column name 'id'" error when using gorm's AutoMigrate [duplicate]

While creating primary key from gorm model it return with error “duplicate column name: “id””
my model looks like
type User struct {
gorm.Model
Id string gorm:"primary_key;"
FirstName string
LastName string
}
any idea what is the issue with above model
Gorm uses ID as the primary key by default. It is part of the gorm.Model you are embedding.
When embedding the gorm.Model, you should leave ID out as gorm already includes it. The alternative is to remove the embedded gorm.Model and specify ID yourself.
To quote the gorm conventions page:
gorm.Model is a basic GoLang struct which includes the following
fields: ID, CreatedAt, UpdatedAt, DeletedAt.
It may be embeded into your model or you may build your own model
without it.
The reasons this fails on schema creation as opposed to compilation is that a lot of databases (CockroachDB included) do case insensitive checking unless you quote the object names (Id matches id, but "Id" does not). This results in two separate column names that match when compared with case insensitivity.

Issue while creating primary key from gorm model

While creating primary key from gorm model it return with error “duplicate column name: “id””
my model looks like
type User struct {
gorm.Model
Id string gorm:"primary_key;"
FirstName string
LastName string
}
any idea what is the issue with above model
Gorm uses ID as the primary key by default. It is part of the gorm.Model you are embedding.
When embedding the gorm.Model, you should leave ID out as gorm already includes it. The alternative is to remove the embedded gorm.Model and specify ID yourself.
To quote the gorm conventions page:
gorm.Model is a basic GoLang struct which includes the following
fields: ID, CreatedAt, UpdatedAt, DeletedAt.
It may be embeded into your model or you may build your own model
without it.
The reasons this fails on schema creation as opposed to compilation is that a lot of databases (CockroachDB included) do case insensitive checking unless you quote the object names (Id matches id, but "Id" does not). This results in two separate column names that match when compared with case insensitivity.

Is it a bad practice to use an Input Type for a graphql Query?

I have seen that inserting an Input Type is recommended in the context of mutations but does not say anything about queries.
For instance, in learn tutorial just say:
This is particularly valuable in the case of mutations, where you might want to pass in a whole object to be created
I have this query:
type query {
person(personID: ID!): Person
brazilianPerson(rg: ID!): BrazilizanPerson
foreignerPerson(passport: ID!): ForeignerPerson
}
Instead of having a different type just because of the name (rg, passport) of the fields, or put one more argument like type in query, I could not just have the Person with an documentNr field and do an Input type like that?
input PersonInput {
documentNr : ID!
type: PersonType # this type is Foreign or Brazilian and with this I k
}
PersonType is a enum and with him I know if the document is a rg or a passport.
No, there is nothing incorrect about your approach. The GraphQL spec allows any field to have an argument and allows any argument to accept an Input Object Type, regardless of the operation. In fact, the differences between a query and a mutation are largely symbolic.
It's worth pointing out that any field can accept an argument -- not just ones at the root level. So if it suited your needs, you could easily set up a schema that would allow queries like:
query {
person(id: 1) {
powers(onlyMutant: true) {
name
}
}
}

What is the difference between unique_index and unique?

What is the difference between unique_index and unique in GORM?
I am using MySQL 8.0, I cannot find the description about the difference between unique_index & unique form manual.
From here, see specifically the Email and MemberNumber fields:
Declaring Models
Models are usually just normal Golang structs, basic Go types, or pointers of them. sql.Scanner and driver.Valuer interfaces are also supported.
Model Example:
type User struct {
gorm.Model
Name string
Age sql.NullInt64
Birthday *time.Time
Email string `gorm:"type:varchar(100);unique_index"`
Role string `gorm:"size:255"` // set field size to 255
MemberNumber *string `gorm:"unique;not null"` // set member number to unique and not null
Num int `gorm:"AUTO_INCREMENT"` // set num to auto incrementable
Address string `gorm:"index:addr"` // create index with name `addr` for address
IgnoreMe int `gorm:"-"` // ignore this field
}
unique is a database constraint that (in this case) prevents the multiple record have the same value for MemberNumber. If such an insert or update is made, the operation will not succeed and return an error.
unique_index will create a database index that also ensures that no two values can be the same. It will do the same, but create an index.
In your case: MySQL will use a unique index behind the scenes when using a unique constraint. So when using MySQL, there is no difference when using unique and using unique index.
If you use other database management systems there might be differences.
The differences (if any) will be handled by the database management system internally. For practical purposes you can regard them as the same. The differences will be documented for each database management system.

Resources