Knex 加载 SQL 文件时出错 - "undefined" 处或附近的语法错误
Knex error loading SQL FIle - syntax error at or near "undefined"
我确定这是一个简单的问题,但我卡住了,Google 博士没有帮助。
基本上,我正在尝试使用 Node.js 中的 Knex 在迁移中加载架构 SQL 文件。
SQL 文件直接来自 PGAdmin,没有数据,只有模式。
本质上,我正在从文件系统加载 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 我觉得一切正常。
我检查了坏字符、空格等。我不知道在哪里。
希望我只是在这里做错了什么。
有什么想法吗?
从 pg@7 开始,应该支持使用 knex raw 执行多个语句。所以有一个细微的变化,这实际上可以工作,但我自己从未测试过。
如果你 运行 那些 SQL 个文件一个一个地处理,效果会更好吗?
你确定 concat 没有把它们搞砸吗?
一定数量的 SQL 之后是否总是发生这种情况,也许最大查询大小有限制?
我一直使用命令行工具来 save/restore 数据库转储。
人们可能会在 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));
}
});
});
}
不是完美的解决方案,但可能对某些人有用...
不想回答我自己的问题,但我知道发生了什么。感谢所有回复的人。
对于其他尝试做同样事情的人来说,该代码存在一些问题。
首先,关于 "undefined" 的错误是由于
let sql;
sql += fs.readFileSync(path.join(schemaFilePath, file), "utf8");
这会在 SQL 语句的开头生成一个 "undefined"。由
解决
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"));
希望这对遇到困难的其他人有所帮助
我确定这是一个简单的问题,但我卡住了,Google 博士没有帮助。
基本上,我正在尝试使用 Node.js 中的 Knex 在迁移中加载架构 SQL 文件。 SQL 文件直接来自 PGAdmin,没有数据,只有模式。
本质上,我正在从文件系统加载 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 我觉得一切正常。
我检查了坏字符、空格等。我不知道在哪里。
希望我只是在这里做错了什么。
有什么想法吗?
从 pg@7 开始,应该支持使用 knex raw 执行多个语句。所以有一个细微的变化,这实际上可以工作,但我自己从未测试过。
如果你 运行 那些 SQL 个文件一个一个地处理,效果会更好吗?
你确定 concat 没有把它们搞砸吗?
一定数量的 SQL 之后是否总是发生这种情况,也许最大查询大小有限制?
我一直使用命令行工具来 save/restore 数据库转储。
人们可能会在 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));
}
});
});
}
不是完美的解决方案,但可能对某些人有用...
不想回答我自己的问题,但我知道发生了什么。感谢所有回复的人。
对于其他尝试做同样事情的人来说,该代码存在一些问题。
首先,关于 "undefined" 的错误是由于
let sql;
sql += fs.readFileSync(path.join(schemaFilePath, file), "utf8");
这会在 SQL 语句的开头生成一个 "undefined"。由
解决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"));
希望这对遇到困难的其他人有所帮助