-
-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
inline SQL scripts for bundlers #345
Conversation
build script compiles sql files into strings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent start; here's some suggested changes 🙌
scripts/buildSqlModule.js
Outdated
const sqlModule = sqlFiles.reduce((acc, file) => { | ||
const sql = fs.readFileSync(path.join(sqlDir, file), "utf8"); | ||
const varName = "sql_" + file.replace(".sql", "").replace(/-/g, "_"); | ||
return acc + `export const ${varName} = \`${sql}\`;\n`; | ||
}, ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The escaping of the SQL wasn't safe in general, let's protect against future migrations. If you can think of any UTF-8 encoded string sql
for which sql !== eval(escape(sql))
please let me know.
const sqlModule = sqlFiles.reduce((acc, file) => { | |
const sql = fs.readFileSync(path.join(sqlDir, file), "utf8"); | |
const varName = "sql_" + file.replace(".sql", "").replace(/-/g, "_"); | |
return acc + `export const ${varName} = \`${sql}\`;\n`; | |
}, ""); | |
/** | |
* Turns `str` into a String.raw expression, safely escaping backticks and | |
* placeholder strings. | |
*/ | |
function escape(str) { | |
return ( | |
"String.raw`" + | |
str | |
.replace(/`/g, '` + "`" + String.raw`') | |
.replace(/\$\{/g, "$$` + String.raw`{") + | |
"`" | |
); | |
} | |
const sqlModule = | |
"/* This file is auto-generated by `npm run build:sql`; DO NOT EDIT */\n" + | |
"// prettier-ignore\n" + | |
"const migrations = {\n" + | |
sqlFiles | |
.map((file) => { | |
const sql = fs.readFileSync(path.join(sqlDir, file), "utf8"); | |
return ` ${JSON.stringify(file)}: ${escape(sql)},`; | |
}) | |
.join("\n") + "\n};\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I am misunderstanding, I believe this may break out, but isn't an SQL escape. I can do a bit of fuzzing
}; console.log('Hacked!'); //
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice try, but that looks safe enough to me:
$ node
Welcome to Node.js v18.17.1.
Type ".help" for more information.
> function escape(str) {
... return (
... "String.raw`" +
... str
... .replace(/`/g, '` + "`" + String.raw`')
... .replace(/\$\{/g, "$$` + String.raw`{") +
... "`"
... );
... }
undefined
> sql = "}; console.log('Hacked!'); //"
"}; console.log('Hacked!'); //"
> sql === eval(escape(sql))
true
> sql = "`}; console.log('Hacked!'); //`"
"`}; console.log('Hacked!'); //`"
> sql === eval(escape(sql))
true
Co-authored-by: Benjie <benjie@jemjie.com>
Co-authored-by: Benjie <benjie@jemjie.com>
When you get a chance, please regenerate the generated file (and remove the old version). Cheers! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks almost perfect. One last tiny change and regenerate and then we're good I think!
Co-authored-by: Benjie <benjie@jemjie.com>
Thanks, changed! |
Please regenerate the generated file 🙏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great to me!
Released as |
@benjie thank you for the PRR and quick release/tag! |
Description
Removing
fs
dependency and inlining SQL files into a TS file at build time beforetsc
is run allows this to be run in serverless environments. For example, this nextjs config in vercel worked:Fixes #143
Performance impact
Front loaded at build time
Security impact
None
Checklist
yarn lint:fix
passes.yarn test
passes. - current e2e tests workRELEASE_NOTES.md
file (if one exists).