I try to have a response on my request GraphQL.
I tried many things but currently I have always the Sequence response, and no the Buckets response (belongs To relation).
I have 2 tables :
Sequence [id | is_active]
Bucket [id | fk_language_id | fk_sequence_id | is_active]
model/sequence.js
'use strict';
module.exports = (sequelize, DataTypes) => {
// define sequence
const Sequence = sequelize.define('sequence', {
is_active: {type: DataTypes.BOOLEAN}
});
Sequence.associate = function (models) {
models.Sequence.hasMany(models.Bucket, {
foreignKey: 'fk_sequence_id'
});
return Sequence;
};
model/bucket.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const Bucket = sequelize.define('bucket', {
code : {type: DataTypes.STRING},
is_active: {type: DataTypes.BOOLEAN}
});
Bucket.associate = function (models) {
models.Bucket.belongsTo(models.Language, {
foreignKey: 'fk_language_id',
});
models.Bucket.belongsTo(models.Sequence, {
foreignKey: 'fk_sequence_id',
});
};
return Bucket;
};
schema.js
# Sequence
type Sequence {
id: Int!,
code: String,
buckets: [Bucket],
is_active: Boolean
}
# Bucket
type Bucket {
id: Int!,
code: String
blocks: [Block]
is_active: Boolean
}
# SequenceInput
input SequenceInput {
buckets: [BucketInput],
is_active: Boolean
}
# BucketInput
input BucketInput {
code: String,
fk_language_id: Int,
fk_sequence_id: Int,
is_active: Boolean
}
type Query {
sequences: [Sequence]
sequence(id: Int): Sequence
buckets: [Bucket]
bucket(id: Int): Bucket
}
type Mutation {
createSequence(input: SequenceInput): Sequence,
}
Request GraphQL
mutation {
createSequence(input: {
is_active: false,
buckets: [
{fk_language_id: 2, code: "Test"}
]
}) {
is_active,
buckets {
id,
code
}
}
}
But I have this result, the Buckets doesn't load :
{
"data": {
"createSequence": {
"is_active": false,
"buckets": []
}
}
}
my mutation :
...
Sequence : {
buckets(sequence) {
return models.Bucket.findAll({
where: {id: sequence.id}
});
},
...
},
...
Mutation : {
createSequence(_, {input}) {
let sequenceId = 0;
// Create Sequence
return models.Sequence.create(input)
.then((sequence) => {
sequenceId = sequence.id;
console.log('sequence created');
// Create Bucket
// Foreach on buckets
return Promise.map(input.buckets, function (bucket) {
bucket.fk_sequence_id = sequenceId;
console.log('bucket created');
return models.Bucket.create(bucket);
})
})
.then(() => {
console.log('load created', sequenceId);
return models.Sequence.findOne({
where : {id: sequenceId},
include: [
{
model: models.Bucket,
where: { fk_sequence_id: sequenceId }
}
]
}).then((response) => {
console.log(response);
return response;
})
});
},
}
The final console.log show many informations...
sequence {
dataValues:
{ id: 416,
is_active: false,
created_at: 2019-03-29T20:33:56.196Z,
updated_at: 2019-03-29T20:33:56.196Z,
buckets: [ [Object] ] },
_previousDataValues:
{ id: 416,
is_active: false,
created_at: 2019-03-29T20:33:56.196Z,
updated_at: 2019-03-29T20:33:56.196Z,
buckets: [ [Object] ] },
_changed: {},
_modelOptions:
{ timestamps: true,
validate: {},
freezeTableName: true,
underscored: false,
paranoid: false,
rejectOnEmpty: false,
whereCollection: { id: 416 },
schema: null,
schemaDelimiter: '',
defaultScope: {},
scopes: {},
indexes: [],
name: { plural: 'sequences', singular: 'sequence' },
omitNull: false,
createdAt: 'created_at',
updatedAt: 'updated_at',
sequelize:
Sequelize {
options: [Object],
config: [Object],
dialect: [Object],
queryInterface: [Object],
models: [Object],
modelManager: [Object],
connectionManager: [Object],
importCache: [Object],
test: [Object] },
hooks: {} },
_options:
{ isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
include: [ [Object] ],
includeNames: [ 'buckets' ],
includeMap: { buckets: [Object] },
includeValidated: true,
attributes: [ 'id', 'is_active', 'created_at', 'updated_at' ],
raw: true },
isNewRecord: false,
buckets:
[ bucket {
dataValues: [Object],
_previousDataValues: [Object],
_changed: {},
_modelOptions: [Object],
_options: [Object],
isNewRecord: false } ] }
Your mutation resolver returns a Promise, which resolves into a Model instance. The promise in question is returned on this line:
return models.Sequence.create(input)
.
As such, the server will wait until that promise is resolved before passing the value forward. Other actions were also waiting on that promise, but they were not the promises returned, so they will not be waited for.
All you have to do is wait for all of your operations to finish before resolving your promise.
createSequence: async (parent, { input }) => {
const sequence = await models.Sequence.create({
is_active: input.is_active
})
if (!input.buckets) return sequence
// You may have to modify your Sequence.buckets resolver to avoid fetching buckets again.
sequence.buckets = await Promise.all(input.buckets.map(bucket => {
// You can avoid these if checks by implementing stricter input types.
// e.g. buckets: [BucketInput!]!
if (!bucket) return null
return models.Bucket.create({
...bucket,
fk_sequence_id: sequence.id
})
}))
return sequence
}
Also, make sure your Sequence.buckets
resolver isn't overwriting buckets with faulty data. The resolver you've provided will try to match bucket primary keys with a sequence primary key instead of matching the correct foreign keys with a primary key.
Here's a resolver that will work:
buckets: (parent) => (
parent.buckets // This line may conflict with some of your code and cause problems.
|| models.Bucket.findAll({
where: {fk_sequence_id: parent.id}
})
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.