knexからkyselyへの移行中。
knexはtoStringでSQLが取得できたけれど、kyselyではどうすれば良いのか。
一応、マニュアルには以下の通り書いてある。
const compiledQuery = db
.selectFrom('person')
.select('first_name')
.where('id', '=', id)
.compile()
console.log(compiledQuery) // { sql: 'select "first_name" from "person" where "id" = $1', parameters: [1], query: { ... } }
compileしたqueryを実行することもできる。
const compiledQuery = db
.selectFrom('person')
.select('first_name')
.where('id', '=', id)
.compile()
const results = await db.executeQuery(compiledQuery)
こうすることで、まずcompileしたSQLをlog用のDBにinsertしておいて、そのあとに実行するということができるようになる。
ところが、.compile()
はプレースホルダーがMySQLなら?
,postgresであれば$
として表示される。実際にinsertやupdateした値をそのままログに残したい場合もあるだろう。そういうときは以下のような関数をつくって、?をparametersと入れ替えてあげればよい。
export const toRawSql = (
sql: string,
parameters: readonly unknown[],
): string => {
let sqlWithValues = sql;
parameters.forEach((param) => {
sqlWithValues = sqlWithValues.replace("?", param as any);
});
return sqlWithValues;
};
何も考えずに書いたヘルパ関数。
reduceとか使うならこんな感じか
export const toRawSql = (
sql: string,
parameters: readonly unknown[],
): string => {
return parameters.reduce((currentSql, param) => {
return currentSql.replace("?", param as any);
}, sql);
};
reduceのほうはテスト書いてないから自信ないけどたぶん動くはず。
knexは最近アップデートが滞っている。Databaseを切り替えるような運用だとパスワードが消えるという本当にどうしようもないバグがずっと残ったままで、issueで何回かアップデートをお願いしたがどうもダメっぽいので本格的にkyselyへ移行しようと考えている。
kyselyはいまだにver0台だが、productionで使用している企業もあるようなので、もうちょっと社内ツールなどでテストしてから本番環境でも使っていきたい所存。sqlcは昨日まで頑張っていたがいろいろ困りどころがあって折れました。