简体   繁体   中英

Sequelize and response request GraphQL

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM