加载 SQL FIle 时出现 Knex 错误 - "undefined"或接近 的语法错误



我确信这是一个简单的问题,但我被卡住了,谷歌博士也帮不了我。

基本上,我试图在迁移中使用Node中的Knex加载模式SQL文件。SQL文件直接来自PGAdmin,没有数据,只有模式。

从本质上讲,im从文件系统中加载SQL文件,然后knex.raw()应用它们。我可以看到SQL加载得很好,它会吐到控制台中。

我的迁移方法看起来像

exports.up = knex => {
const schemaFilePath = path.join(__dirname, "../db/schema");
const schemaFiles = fs.readdirSync(schemaFilePath);
let sql;
schemaFiles.forEach(async file => {
sql += fs.readFileSync(path.join(schemaFilePath, file), "utf8");
});
return knex.raw(sql);
};

有几个SQL文件,从该模式目录加载,如下所示。(带有注释行等(

-- Table: public.roles
-- DROP TABLE public.roles;
CREATE TABLE public.roles
(
_id uuid NOT NULL DEFAULT uuid_generate_v4(),
"displayName" citext COLLATE pg_catalog."default",
"createdAt" timestamp with time zone NOT NULL,
"updatedAt" timestamp with time zone NOT NULL,
"deletedAt" timestamp with time zone,
"_fullTextSearch" citext COLLATE pg_catalog."default",
system boolean DEFAULT false,
....

我得到的错误是

ON public.validations USING btree
("updatedAt" ASC NULLS LAST)
TABLESPACE pg_default;
- syntax error at or near "undefined"
error: syntax error at or near "undefined"
at Connection.parseE (/xxx/node_modules/pg/lib/connection.js:604:13)

它也不是那个特定的文件,就好像我只是删除了那个文件,我仍然会在另一个文件中得到同样的错误。

在输出的日志中滚动,SQL对我来说都很好。

Iv检查了不好的字符、空格等。我不知道在哪里。

希望我只是做错了什么。

有什么想法吗?

自pg@7本应支持使用knexraw执行多个语句。所以有一个微小的变化,这实际上是可行的,但我自己从未测试过。

如果一个接一个地运行这些SQL文件,效果会更好吗?

你确定康卡特没有把他们搞砸吗?

这种情况是否总是在一定数量的SQL之后发生,也许最大查询大小有限制?

我一直使用命令行工具来保存/恢复数据库转储。

可以在knex迁移文件中执行这些工具,然后让knex迁移系统标记迁移已经使用。

我使用了这种功能来保存/恢复节点代码中的数据库状态(通常存储不同e2e测试设置之间的系统状态,以便能够从执行过程中开始运行e2e(:

async dump(dumpFileName, user, password, database, host) {
return new Promise((resolve, reject) => {
const cmd = [
`export PGPASSWORD=${password};`,
`pg_dump -a -O -x -F c`,
`-f '${dumpFileName}'`,
`-d ${database}`,
`-h ${host}`,
`-p 5432`,
`-U ${user}`
].join(' ');
shelljs.rm('-f', dumpFileName);
shelljs.exec(cmd, (code, stdout, stderr) => {
console.log(`Command ready: ${cmd}, with exit code: ${code}`);
if (code === 0) {
resolve(stdout);
} else {
reject(new Error(stderr));
}
});
});
}
async restore(dumpFileName, user, password, database, host) {
return new Promise((resolve, reject) => {
const cmd = [
`export PGPASSWORD=${password};`,
`cat '${dumpFileName}' | `,
`pg_restore -a -O -x -F c`,
`-d ${database}`,
`-h ${host}`,
`-p 5432`,
`-U ${user}`,
`--disable-triggers"`
].join(' ');
shelljs.exec(cmd, (code, stdout, stderr) => {
console.log(`Command ready: ${cmd}, with exit code: ${code}`);
if (code === 0) {
resolve(stdout);
} else {
reject(new Error(stderr));
}
});
});
}

不是一个完美的解决方案,但可能对某人有效。。。

我不想回答自己的问题,但我发现了发生了什么。感谢所有回复的人。

对于其他试图做同样事情的人来说,该代码存在一些问题。

首先,关于"未定义"的错误是由于

let sql;
sql += fs.readFileSync(path.join(schemaFilePath, file), "utf8");

这在SQL语句的一开始就生成了一个"未定义"。解决

let sql = "";

接下来,我遇到了一个坏角色的问题,这次是完全看不见的,很难找到。我只能通过将字符串的内容写回文件来找到它们,然后我在文件中看到了一堆无效字符,我想这些字符与UTF-8不兼容。

这是由于隐藏的文件被从文件系统中取出。即

schemaFiles.forEach(file => {
sql += fs.readFileSync(path.join(schemaFilePath, file), "utf8");
});

当我在Mac上时,它也加载了那些烦人的.DS_Store文件,这些文件插入了二进制垃圾,尽管这在屏幕输出中不可见,只是在将内容写回平面文件后。

我本来打算尝试psql加载它。psql给了我一个更好的错误消息。

通过只过滤.sql文件解决了这个问题

schemaFiles.forEach(file => {
if (file.substr(file.length - 4) === ".sql") {
code ....
}
})

最后,由于CONSTRAINTS和模式中不存在表,我在加载模式文件时遇到了问题,所以我使用pg_dump来获取有效的模式文件,不包括knex迁移表

pg_dump --schema-only --exclude-table=knex* > db/schema.sql

现在,迁移文件本质上是一个单行

return knex.raw(fs.readFileSync(path.join(__dirname, "../db/schema.sql"), "utf8"));

希望这能帮助其他陷入的人

相关内容

最新更新