【Drizzle】queryに__typeを埋め込んで型強力にする
こんにちは、フリーランスエンジニアの太田雅昭です
以前、DrizzleのViewで__typeを埋め込んで、型を強化する話を書きました。
今回は、Viewを使わずqueryでやってしまおうというお話です。
tableを用意する
下記のテーブルを用います。
export const usersTable = pgTable('users', {
id: text().notNull(),
handle: text().unique(),
email: text(),
}
ユーティリティ関数を用意する
下記のようなユーティリティ関数を作ります。
export function mkType<T extends string>(type: T) {
return { __type: sql<T>`${sql.raw(`'${type}'`)}`.as('__type') }
}
これは、フィールドに__typeとして固定値を入れるためのものです。詳細は前回の記事を参照ください。
queryを作る
queryを作ります。
import { SQL } from "drizzle-orm";
// queryで受け取る引数
export type CustomQueryParams = {
where?: SQL<unknown>
orderBy?: SQL<unknown>
limit?: number
offset?: number
}
// 自身参照用
export const userAsSelfQuery = (params?: CustomQueryParams) => db()
.query
.usersTable
.findOne({
extras: { ...mkType('user_self') },
with: {
posts: true,
},
...params,
});
// 公開用
export const usersAsPublicQuery = (params?: CustomQueryParams) => db()
.query
.usersTable
.findMany({
extras: { ...mkType('users_public') },
columns: { email: false, }, // 機密情報を除く
with: {
posts: true,
},
...params,
});
型を作ります。type指定しているため、クライアントから読み込んでも安全です。
// type指定でimportすることで、サーバークライアント間のエラーを防ぐ
import type {userAsSelfQuery, usersAsPublicQuery} from 'queries';
export type UserAsSelf = Awaited<ReturnType<typeof userAsSelfQuery>>
export type UserAsPublic = Awaited<ReturnType<typeof usersAsPublicQuery>>[number]
使ってみる
下記のようにして使います。
function showMe(me: UserAsSelf) {
console.log(me);
}
function showAsPublic(user: UserAsPublic){
console.log(user);
}
async function test() {
const me = await userAsSelfQuery();
const usersPublic = await usersAsPublic();
showMe(me);
showMe(usersPublic[0]); // 型エラーになる
showPublic(me); // 型エラーになる
showPublic(usersPublic[0]);
}
__typeに固定値が入っているため、予期しないところでの使用時に型エラーが出るようになります。