Knex: Janji tidak berlaku seperti yang diharapkan dalam migrasi

Dibuat pada 16 Jun 2014  ·  10Komentar  ·  Sumber: knex/knex

(Ini mungkin duplikat dari # 312)

File migrasi seperti ini:

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

};

memberikan hasil sebagai berikut:

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

Komentar yang paling membantu

Jadi kebingungan di sini adalah bahwa metode createTable tidak mengembalikan sebuah janji, melainkan mengembalikan objek SchemaBuilder , yang merupakan "thenable", yaitu memanggil .then pada objek akan mengembalikan janji A + yang valid, tetapi objek itu sendiri bukan janji.

Ini dilakukan secara khusus untuk memungkinkan Anda menggunakan sintaks:

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

yang harus menjalankan migrasi seperti yang diharapkan pada koneksi yang sama secara berurutan.

Juga, tidak perlu Promise.all sini, karena ini akan menghasilkan hal yang sama:

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

meskipun jika Anda mau, Anda dapat melakukan:

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

dan semuanya akan bekerja seperti yang ditentukan oleh spesifikasi.

Semua 10 komentar

Saya tidak berpikir Anda harus mengembalikan Promise.all([first, second]); , karena Anda telah merantai second menjadi first . Bisakah Anda mencoba hanya return first ? Karena createTable ada di dalam then yang dirantai dari first , tidak perlu menambahkannya ke Promise.all , karena akan dieksekusi bagaimanapun sementara first sedang diselesaikan.

Spesifikasi promise mengatakan bahwa setelah promise terpenuhi, ia tidak akan pernah terpenuhi lagi, dan semua pemanggilan then akan mengembalikan hasil yang disimpan dalam cache. Jika first dan second keduanya terpenuhi, maka Promise.all([first, second]) harus ~ tanpa operasi.

return first memiliki perilaku yang sama - yaitu, mencoba membuat tabel first , first , dan second , yang _bahkan lebih salah_, sebagaimana mestinya tidak pernah ada kode yang benar-benar mengevaluasi apa pun di dalam fungsi yang diteruskan ke first.then dalam skenario itu.

Uhm ok kedengarannya aneh. Tidak menggunakan Promise.all dapat memberikan sedikit dorongan dalam kinerja;)

Tapi ya, ini sepertinya salah. Saya akan menandai ini sebagai bug untuk saat ini dan menunggu sampai @tgriesser ikut serta . Terima kasih telah melaporkan!

Haha, saya tidak terlalu peduli dengan kinerja satu tick dalam migrasi saya: p

Maaf, saya membuat pernyataan yang salah di atas - return first harus tetap membuat tabel kedua, hanya saja hasil pemanggilan .then pada hasil fungsi tidak akan menunggu. Yang mana, w / e - seharusnya tetap tidak menghasilkan first , first , second !

Tidak yakin saya sepenuhnya mengerti: Mengapa tabel ke-2 tidak menunggu untuk pembuatan yang pertama? Karena Anda memutuskan janji pertama menggunakan then janji tersebut akan dijalankan secara seri. Itu seharusnya tidak menjadi masalah.

Pembuatan tabel kedua akan, ya, tetapi hasil dari fungsi exports.up tidak. Yaitu, jika Anda memanggil exports.up().then , itu sama dengan memanggil first.then dan bukan second.then - karena _is_ first.then !

Ah, salah paham di sana - ya, Anda benar tentang itu!

Jadi kebingungan di sini adalah bahwa metode createTable tidak mengembalikan sebuah janji, melainkan mengembalikan objek SchemaBuilder , yang merupakan "thenable", yaitu memanggil .then pada objek akan mengembalikan janji A + yang valid, tetapi objek itu sendiri bukan janji.

Ini dilakukan secara khusus untuk memungkinkan Anda menggunakan sintaks:

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

yang harus menjalankan migrasi seperti yang diharapkan pada koneksi yang sama secara berurutan.

Juga, tidak perlu Promise.all sini, karena ini akan menghasilkan hal yang sama:

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

meskipun jika Anda mau, Anda dapat melakukan:

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

dan semuanya akan bekerja seperti yang ditentukan oleh spesifikasi.

Ok itu menjelaskan itu. Tidak tahu itu - maaf atas kebingungannya karena tidak bisa langsung memberikan jawaban langsung @SohumB

Ya, kami memiliki grafik ketergantungan yang lebih rumit dari itu; ini hanya kasus uji minimal! Terima kasih untuk bantuannya.

@bayu_joo

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!
Apakah halaman ini membantu?
0 / 5 - 0 peringkat