(Cela peut être un double de # 312)
Un fichier de migration comme celui-ci:
exports.up = function(knex, Promise) {
var first = knex.schema.createTable('first', function(table) {
table.increments('id');
table.string('name');
});
var second = first.then(function() {
return knex.schema.createTable('second', function(table) {
table.increments('id');
table.string('name');
});
});
return Promise.all([first, second]);
};
exports.down = function(knex, Promise) {
};
donne la sortie suivante:
{ __cid: '__cid1',
sql: 'create table "first" ("id" serial primary key, "name" varchar(255))',
bindings: [] }
{ __cid: '__cid2',
sql: 'create table "first" ("id" serial primary key, "name" varchar(255))',
bindings: [] }
{ __cid: '__cid3',
sql: 'create table "second" ("id" serial primary key, "name" varchar(255))',
bindings: [] }
error: duplicate key value violates unique constraint "pg_type_typname_nsp_index"
at Connection.parseE (/home/sohum/node_modules/pg/lib/connection.js:526:11)
at Connection.parseMessage (/home/sohum/node_modules/pg/lib/connection.js:356:17)
at Socket.<anonymous> (/home/sohum/node_modules/pg/lib/connection.js:105:22)
at Socket.EventEmitter.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:745:14)
at Socket.EventEmitter.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:407:10)
at emitReadable (_stream_readable.js:403:5)
at readableAddChunk (_stream_readable.js:165:9)
at Socket.Readable.push (_stream_readable.js:127:10)
Je ne pense pas que vous devriez retourner Promise.all([first, second]);
, puisque vous avez déjà enchaîné second
à first
. Pourriez-vous essayer de n'essayer que return first
? Puisque votre deuxième createTable
est à l'intérieur d'un then
qui est enchaîné de first
, il n'est pas nécessaire de l'ajouter à Promise.all
, car il sera exécuté de toute façon pendant que first
est en cours de résolution.
La spécification de la promesse dit qu'une fois qu'une promesse est remplie, elle ne devrait plus jamais l'être, et toutes les futures invocations de then
devraient renvoyer le résultat mis en cache. Si first
et second
sont tous deux remplis, alors Promise.all([first, second])
devrait être ~ un no-op.
return first
a le même comportement - c'est-à-dire qu'il essaie de créer les tables first
, first
et second
, ce qui est encore plus faux ne jamais être un code qui évalue réellement quoi que ce soit à l'intérieur de la fonction passée à first.then
dans ce scénario.
Ok, ça semble bizarre. Ne pas utiliser Promise.all
pourrait cependant donner un petit coup de pouce aux performances;)
Mais oui, cela semble être faux. Je vais marquer cela comme un bug pour le moment et attendre que @tgriesser intervienne. Merci d'avoir signalé!
Haha, je ne me soucie pas particulièrement de la performance d'un tick dans mes migrations: p
Désolé, j'ai fait une mauvaise déclaration ci-dessus - return first
devrait toujours créer la deuxième table, c'est juste que le résultat de l'appel de .then
sur le résultat de la fonction ne l'attendra pas. Ce qui, sans - cela ne devrait certainement pas faire first
, first
, second
!
Je ne suis pas sûr de bien comprendre: pourquoi la 2ème table n'attendrait-elle pas la création de la première? Puisque vous enchaînez la première promesse en utilisant then
elles seront effectivement exécutées en série. Cela ne devrait pas être un problème.
La création de la deuxième table le sera, oui, mais le résultat de la fonction exports.up
ne le sera pas. C'est-à-dire que si vous appelez exports.up().then
, c'est la même chose que d'appeler first.then
et non second.then
- car il _is_ first.then
!
Ah, vous avez mal compris - ouais vous avez raison!
Donc la confusion ici est que la méthode createTable
ne retourne pas de promesse, mais renvoie plutôt un objet SchemaBuilder
, qui est un "thenable", c'est-à-dire appeler .then
sur le object retournera une promesse A + valide, mais l'objet lui-même n'est pas une promesse.
Cela a été fait spécifiquement pour vous permettre d'utiliser la syntaxe:
return knex.schema.createTable('first', function(table) {
table.increments('id');
table.string('name');
})
.createTable('second', function(table) {
table.increments('id');
table.string('name');
}).then(function() {
// all done
});
qui devrait exécuter les migrations comme prévu sur la même connexion dans l'ordre.
De plus, il n'y a pas besoin de Promise.all
ici, car cela accomplirait la même chose:
exports.up = function(knex, Promise) {
return knex.schema.createTable('first', function(table) {
table.increments('id');
table.string('name');
}).then(function() {
return knex.schema.createTable('second', function(table) {
table.increments('id');
table.string('name');
});
});
};
si vous le vouliez, vous pourriez faire:
exports.up = function(knex, Promise) {
var first = knex.schema.createTable('first', function(table) {
table.increments('id');
table.string('name');
}).then(); // coerce thenable to a promise
var second = first.then(function() {
return knex.schema.createTable('second', function(table) {
table.increments('id');
table.string('name');
});
});
return Promise.all([first, second]);
};
et les choses fonctionneraient comme défini par la spécification.
Ok ça explique ça. Je ne savais pas que - désolé pour la confusion de ne pas pouvoir donner une réponse directe tout de suite @SohumB
Oui, nous avons des graphiques de dépendances plus compliqués que cela; ce n'était qu'un cas de test minimal! Merci pour l'aide.
@johanneslumpe
sohum<strong i="8">@diurnal</strong> ~ % cat test.js
var Promise = require('bluebird');
function promises() {
var first = Promise.resolve('wee');
var second = first.then(function() {
console.log('delayin');
return Promise.delay(1000);
}).then(function() {
console.log('done!');
});
return first;
}
promises().then(function() { console.log('yep, first is finished'); });
sohum<strong i="9">@diurnal</strong> ~ % node test.js
delayin
yep, first is finished
done!
Commentaire le plus utile
Donc la confusion ici est que la méthode
createTable
ne retourne pas de promesse, mais renvoie plutôt un objetSchemaBuilder
, qui est un "thenable", c'est-à-dire appeler.then
sur le object retournera une promesse A + valide, mais l'objet lui-même n'est pas une promesse.Cela a été fait spécifiquement pour vous permettre d'utiliser la syntaxe:
qui devrait exécuter les migrations comme prévu sur la même connexion dans l'ordre.
De plus, il n'y a pas besoin de
Promise.all
ici, car cela accomplirait la même chose:si vous le vouliez, vous pourriez faire:
et les choses fonctionneraient comme défini par la spécification.