Knex: Versprechen verhalten sich bei Migrationen nicht wie erwartet

Erstellt am 16. Juni 2014  ·  10Kommentare  ·  Quelle: knex/knex

(Dies kann ein Duplikat von # 312 sein.)

Eine Migrationsdatei wie folgt:

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) {

};

gibt folgende Ausgabe:

{ __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)
question

Hilfreichster Kommentar

Die Verwirrung hier ist also, dass die createTable -Methode kein Versprechen zurückgibt, sondern ein SchemaBuilder -Objekt zurückgibt, das ein "thenable" ist, dh .then auf dem aufruft Das Objekt gibt ein gültiges A + Versprechen zurück, aber das Objekt selbst ist kein Versprechen.

Dies wurde speziell durchgeführt, um Ihnen die Verwendung der Syntax zu ermöglichen:

  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
  });

Dadurch sollten die Migrationen wie erwartet nacheinander auf derselben Verbindung ausgeführt werden.

Außerdem sind hier keine Promise.all erforderlich, da dies dasselbe bewirken würde:

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');
    });
  });
};

Wenn Sie möchten, können Sie Folgendes tun:

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]);
};

und die Dinge würden wie in der Spezifikation definiert funktionieren.

Alle 10 Kommentare

Ich denke nicht, dass Sie Promise.all([first, second]); , da Sie bereits second mit first verkettet haben. Könnten Sie bitte versuchen, nur return first ? Da sich Ihr zweites createTable in einem then befindet, das mit first verkettet ist, müssen Sie es nicht zu Promise.all hinzufügen, da es ausgeführt wird sowieso, während first aufgelöst wird.

Die Versprechensspezifikation besagt, dass ein einmal erfülltes Versprechen nie wieder erfüllt werden sollte und alle zukünftigen Aufrufe von then das zwischengespeicherte Ergebnis zurückgeben sollten. Wenn first und second beide erfüllt sind, sollte Promise.all([first, second]) ~ ein No-Op sein.

return first hat das gleiche Verhalten - dh es wird versucht, die Tabellen first , first und second erstellen, was sogar noch falscher ist, als es sollte Seien Sie niemals ein Code, der tatsächlich etwas innerhalb der Funktion auswertet, die in diesem Szenario an first.then wurde.

Ähm ok das klingt komisch. Wenn Sie Promise.all dies die Leistung geringfügig steigern;)

Aber ja, das scheint falsch zu sein. Ich werde dies vorerst als Fehler markieren und warten, bis

Haha, mir ist die Leistung eines Ticks bei meinen Migrationen nicht besonders wichtig: p

Entschuldigung, ich habe oben eine falsche Aussage gemacht - return first sollte immer noch die zweite Tabelle erstellen. Es ist nur so, dass das Ergebnis des Aufrufs von .then für das Ergebnis der Funktion nicht darauf wartet. Was, w / e - es sollte definitiv immer noch nicht first , first , second tun!

Ich bin mir nicht sicher, ob ich das vollständig verstehe: Warum sollte der zweite Tisch nicht auf die Erstellung des ersten warten? Da Sie das erste Versprechen mit then verketten, werden sie effektiv in Serie ausgeführt. Das sollte kein Problem sein.

Die Erstellung der zweiten Tabelle wird zwar durchgeführt, das Ergebnis der Funktion exports.up jedoch nicht. Das heißt, wenn Sie exports.up().then anrufen, ist es dasselbe wie first.then und nicht second.then - weil es _is_ first.then !

Ah, ich habe dich dort missverstanden - ja, da hast du recht!

Die Verwirrung hier ist also, dass die createTable -Methode kein Versprechen zurückgibt, sondern ein SchemaBuilder -Objekt zurückgibt, das ein "thenable" ist, dh .then auf dem aufruft Das Objekt gibt ein gültiges A + Versprechen zurück, aber das Objekt selbst ist kein Versprechen.

Dies wurde speziell durchgeführt, um Ihnen die Verwendung der Syntax zu ermöglichen:

  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
  });

Dadurch sollten die Migrationen wie erwartet nacheinander auf derselben Verbindung ausgeführt werden.

Außerdem sind hier keine Promise.all erforderlich, da dies dasselbe bewirken würde:

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');
    });
  });
};

Wenn Sie möchten, können Sie Folgendes tun:

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]);
};

und die Dinge würden wie in der Spezifikation definiert funktionieren.

Ok, das erklärt das. Wusste das nicht - Entschuldigung für die Verwirrung, dass ich nicht sofort eine klare Antwort geben konnte

Ja, wir haben kompliziertere Abhängigkeitsgraphen als diese; Dies war nur ein minimaler Testfall! Danke für die Hilfe.

@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!
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

lanceschi picture lanceschi  ·  3Kommentare

nklhrstv picture nklhrstv  ·  3Kommentare

npow picture npow  ·  3Kommentare

hyperh picture hyperh  ·  3Kommentare

aj0strow picture aj0strow  ·  3Kommentare