knex.raw(...) 在迁移中似乎不起作用

knex.raw(...) in migrations seems not to work

我将 knex 与 MySql 一起使用。这是我的迁移文件:

const { onUpdateTrigger } = require('../../../../knexfile')
const { onInsertTrigger } = require('../../../../knexfile')

exports.up = function (knex, Promise) {

    return knex.schema.createTable('users', (table) => {

        console.info("------> Creating table");
        table.increments('id').unsigned().primary();
        table.string('username').unique().notNullable();
        table.string('password').notNullable();
        table.timestamp('modified').notNullable();
        table.timestamp('created').notNullable().defaultTo(knex.raw('NOW()'));
    }).then(function () {

        console.info("------> Creating trigger");
        knex.raw(onUpdateTrigger('users'));
        knex.raw(onInsertTrigger('users'));
    });
};

exports.down = function (knex, Promise) {
    return knex.schema.dropTable('users');
};

knexfile.js如下:

...

development: {
    client: 'mysql',
    connection: {
        host: 'localhost',
        user: 'pbrause',
        password: '********',
        database: 'mydb',
        charset: 'utf8',
        multipleStatements : true
    },
    debug: true,
    migrations: {
        directory: __dirname + '/src/server/db/migrations'
    },
    seeds: {
        directory: __dirname + '/src/server/db/seeds'
    }
},

...

onInsertTrigger: function(table) {
    `DELIMITER $$
     CREATE TRIGGER \`mydatabase\`.\`${table}_BEFORE_INSERT\`
            BEFORE INSERT ON \`${table}\`
            FOR EACH ROW
     BEGIN
         SET new.modified = NOW();
     END$$
     DELIMITER ;`
},

onUpdateTrigger: function(table) {
    `DELIMITER $$
     CREATE TRIGGER \`mydatabase\`.\`${table}_BEFORE_UPDATE\`
            BEFORE UPDATE ON \`${table}\`
            FOR EACH ROW
     BEGIN
         SET new.modified = NOW();
     END$$
     DELIMITER ;`
}
...

我尝试了两种变体 - 一种是 SQL 代码位于 knex.raw(...) 语句内,另一种是您在上面看到的方式。在这两种情况下,都没有创建触发器,并且 knex 调试输出告诉我这些 'raw' 语句没有执行。 table 在这两种情况下均已正确创建。

知道为什么这不起作用吗?

首先你调用 knex.raw() 到时间并行,而不等待它们的执行完成:

}).then(function () {

    console.info("------> Creating trigger");
    knex.raw(onUpdateTrigger('users'));
    knex.raw(onInsertTrigger('users'));
});

从那时起应该使用 knex.schema.raw 或 return 承诺:

}).then(function () {
    console.info("------> Creating on update trigger");
    return knex.raw(onUpdateTrigger('users'));
}).then(function () {
    console.info("------> Creating on insert trigger");
    return knex.raw(onInsertTrigger('users'));
});

return knex.schema.createTable('users', (table) => {
    console.info("------> Creating table");
    table.increments('id').unsigned().primary();
    table.string('username').unique().notNullable();
    table.string('password').notNullable();
    table.timestamp('modified').notNullable();
    table.timestamp('created').notNullable().defaultTo(knex.raw('NOW()'));
})
.raw(onUpdateTrigger('users'))
.raw(onInsertTrigger('users'));

另一个问题可能是 knex.raw()(实际上数据库驱动程序通常不允许这样做)默认情况下不支持将多个 SQL 语句作为单个查询发送到数据库。

如果您正在使用 mysql,您可以通过为驱动程序 (https://github.com/mysqljs/mysql#connection-options) 设置 multipleStatements : true 配置选项来启用对它的支持。

编辑(为什么那些 knex 原始查询不是 运行 的真正答案):

以上所有内容都是正确的,如果您按照我建议的方式更改代码,它就会解决您的问题。

那些 knex.raw() 查询不是 运行 的原因是因为您只是构建查询,但从未执行它们(它们不是 return 从 promise 中编辑的,这将自动触发查询,您也不会为那些将查询显式发送到数据库的查询调用 .then()

// queries like this are only built, but never sent to server
knex.raw(onUpdateTrigger('users'));
knex.raw(onInsertTrigger('users'));

// one more the correct way to do it so that queries will be executed too
return knex.raw(onUpdateTrigger('users'))
  .then(() => knex.raw(onInsertTrigger('users')));