Is there any way to differentiate between null and undefined in GraphQL? - graphql

I find it really annoying that String can mean undefined, and null as well.
It's especially difficult when mapping through an object.
type Filters {
id: String
name: String
}
can be
{ id: 'id', name: null }
{ id: null, name: null }
{ name: null }
{ id: 'id' }
etc.
I'm looking for a way which defines an input as either the user defines it in the specified type, or not at all.
Is it possible in a not too dirty way?

Related

Apollo - Updating cache when some fields in some results are missing

For the following query, in some objects in the results array, some of the requested fields might not be present in the response (for example photo or address), which causes the data of my useQuery to be undefined (without any error or warning).
people(xyz: { q: $q, offset: $offset, rows: $rows }) {
results {
uri <--- this is a field of type ID!
name
photo
address {
city
country
}
}
}
My fix is to specifically check if the field exists in the incoming data and provide a fallback value, i.e.: pass a type policy for Person to be {keyFields: false} and do this in the merge function:
newItem = {...item};
newItem.photo = item.photo ?? null;
newItem.address = item.address ?? {city: "", country: ""};
Is the reason for having to do this that there's no id field in the Person type (instead, uri is of type ID!)?
Can I handle this in a better way?
Found a better way on Apollo GraphQL's GitHub.
I'd still appreciate a solution where I don't have to go over each type's nullable field in turn, if there is one.
function nullable() {
// Create a generic field policy that allows any field to be null by default:
return {
read(existing = null) {
return existing;
},
};
}
new InMemoryCache({
typePolicies: {
Person: {
fields: {
photo: nullable(),
address: nullable(),
},
},
Address: { // If there's the case of either city or country missing
fields: {
city: nullable(),
country: nullable(),
}
}
},
})

How to define graphql query in schema with exactly one of two parameters required [duplicate]

I'm just getting to grips with GraphQL,
I have set up the following query:
​
type: UserType,
args: {
id: { name: 'id', type: new GraphQLNonNull(GraphQLID) },
email: { name: 'email', type: new GraphQLNonNull(GraphQLString) }
},
resolve: (root, { id, email }, { db: { User } }, fieldASTs) => {
...
}
I would like to be able to pass either an 'id' or 'email' to the query, however, with this setup it requires both an id and email to be passed.
Is there a way to set up the query so only one argument is required, either id or email, but not both?
There's no built-in way to do that in GraphQL. You need to make your arguments nullable (by removing the GraphQLNonNull wrapper type from both of them) and then, inside your resolver, you can just do a check like:
resolve: (root, { id, email }, { db: { User } }, fieldASTs) => {
if (!id && !email) return Promise.reject(new Error('Must pass in either an id or email'))
if (id && email) return Promise.reject(new Error('Must pass in either an id or email, but not both.'))
// the rest of your resolver
}
Define an interface credentials and have that implemented as id or email.

Get list of types from operation variables

I have an operation and I want to get a list containing its variables and types.
Eg. given the operation
query getResource($id: ID!, $title: String) {
resource(id: $id, title: $title) {
id
title
content
}
}
I want to get something like this
[{type: "ID", required: true, name: "id"}, {type: "String", required: false, name: "title"}]
Is this easily attainable?
Edit: I guess what I want to do is to go from a VariableDefinitionNode to an object containing all the information I want, such as type, defaultValue, required, name.
You should be able to implement this if you change your schema (assuming you can generate this data on the server into this shape)
type Query {
resource ($id: ID!, $title: String): [Variable]
}
type Variable {
type: String!
required: Boolean!
name: String!
...
}
This is a very generalised syntax however, returning an array of values like that. If the structure of your resources is known, you would be better off defining that and removing the name parameter as it becomes redundant. (I'm thinking about lookups inside your client-side application)
type Query {
resource ($id: ID!, $title: String): Resource
}
type Resource {
id: Variable!
title: Variable
content: Variable
}
type Variable {
type: String!
required: Boolean!
...
}

How do I set up GraphQL query so one or another argument is required, but not both

I'm just getting to grips with GraphQL,
I have set up the following query:
​
type: UserType,
args: {
id: { name: 'id', type: new GraphQLNonNull(GraphQLID) },
email: { name: 'email', type: new GraphQLNonNull(GraphQLString) }
},
resolve: (root, { id, email }, { db: { User } }, fieldASTs) => {
...
}
I would like to be able to pass either an 'id' or 'email' to the query, however, with this setup it requires both an id and email to be passed.
Is there a way to set up the query so only one argument is required, either id or email, but not both?
There's no built-in way to do that in GraphQL. You need to make your arguments nullable (by removing the GraphQLNonNull wrapper type from both of them) and then, inside your resolver, you can just do a check like:
resolve: (root, { id, email }, { db: { User } }, fieldASTs) => {
if (!id && !email) return Promise.reject(new Error('Must pass in either an id or email'))
if (id && email) return Promise.reject(new Error('Must pass in either an id or email, but not both.'))
// the rest of your resolver
}
Define an interface credentials and have that implemented as id or email.

Sequelize include with multiple where condition

I have a bit of problem for using Sequelize with include. The problem is that my model uses two primary keys in child table.
So it goes like this
Parent table
User : Id, ...
Post : Id, UserId(foreign key, binds to user id), ...
Post Hash Tag : HashTag, PostId(foreign key, binds to Post id), UserId(foreign key, binds to user id of Post table)
So the table hierarchy looks like this
user - post - post hash tag
Now when I try to do like this,
Post.findAll(
include: {
model: post hash tag
}
)
then it only searches the post hash tags for where post id of post hash tag table is equal to post id of post table
So I added like this
Post.findAll(
include: {
model: post hash tag
where: {
col1: models.sequelize.where(models.sequelize.col('POST.USER_ID'), '=', models.sequelize.col('POST_HASH_TAG.USER_ID'))
}
}
);
Then it will gives a problem at 'where' clause that Post.USER_ID cannot be found.
If I change col1 value to Post.userId then now it solves the above error but gives another error at 'on' clause
Do you have any idea how I can solve this?
The full model is given here
User
sequelize.define('User', {
id: { type: DataTypes.STRING(6), field: 'ID', primaryKey : true }
)
Post - I know multiple primary declaration is not working correctly, so don't bother to consider too much
sequelize.define('Post', {
id: { type: DataTypes.STRING(6), field: 'ID', primaryKey: true },
userId: { type: DataTypes.STRING(6), field: 'USER_ID', primaryKey: true }
)
Post hash tag
sequelize.define('PostHashTag', {
postId: { type: DataTypes.STRING(6), field: 'POST_ID', primaryKey: true },
hashTag: { type: DataTypes.STRING(20), field: 'HASH_TAG', primaryKey: true },
userId: { type: DataTypes.STRING(6), field: 'USER_ID', primaryKey: true }
}
)
and the query I used is
Post.findAll({
attributes: ['id', 'userId'],
where: {
userId: userId,
id: { $lt: postId }
},
include: [{
model: models.PostHashTag,
attributes: ['hashTag'],
where: {
col1: models.sequelize.where(models.sequelize.col('Post.USER_ID'), '=', models.sequelize.col('PostHashTag.userId'))
}]).then(...)
I found an answer by myself... col1:
models.sequelize.where(models.sequelize.col('Post.USER_ID'), '=', models.sequelize.col('PostHashTag.userId'))
this should be
userId: models.sequelize.where(models.sequelize.col('POST.userId'), '=', models.sequelize.col('POST_HASH_TAG.USER_ID'))
this will work. The physical names of table and column used in parenthesis

Resources