📘
PrismaでTruncateするスクリプト(Postgresql)
結論
パターン1(できるだけPrismaの特徴を生かす)
import { Prisma, PrismaClient } from "@prisma/client";
type CurrentSchemaResult = {
current_schema: string;
};
const prisma = new PrismaClient();
const getSchemaName = async (prisma: PrismaClient) => {
const result: CurrentSchemaResult[] = await prisma.$queryRaw`
SELECT current_schema()`;
return result[0]?.current_schema ?? "public";
};
export async function truncate(prisma: PrismaClient) {
const schemaName = await getSchemaName(prisma);
console.log(`schemaName: ${schemaName}`);
for (const modelName of Object.values(Prisma.ModelName)) {
console.log(`modelName: ${modelName}`);
await prisma.$queryRaw`
TRUNCATE "${Prisma.raw(schemaName)}"."${Prisma.raw(modelName)}" CASCADE`;
}
}
truncate(prisma)
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
パターン2(Postgresqlのテーブル状況に合わせる)
import { Prisma, PrismaClient } from "@prisma/client";
type InformationSchemaTablesResult = {
table_name: string;
};
type CurrentSchemaResult = {
current_schema: string;
};
const prisma = new PrismaClient();
const getSchemaName = async (prisma: PrismaClient) => {
const result: CurrentSchemaResult[] = await prisma.$queryRaw`
SELECT current_schema()`;
return result[0]?.current_schema ?? "public";
};
const getTableNames = async (schemaName: string, prisma: PrismaClient) => {
const result: InformationSchemaTablesResult[] = await prisma.$queryRaw`
SELECT table_name
FROM information_schema.tables
WHERE table_type='BASE TABLE'
AND table_schema=${schemaName};`;
return result.map((e) => e.table_name);
};
export async function truncate(prisma: PrismaClient) {
const schemaName = await getSchemaName(prisma);
console.log(`schemaName: ${schemaName}`);
for (const modelName of await getTableNames(schemaName, prisma)) {
console.log(`modelName: ${modelName}`);
await prisma.$queryRaw`
TRUNCATE "${Prisma.raw(schemaName)}"."${Prisma.raw(modelName)}" CASCADE`;
}
}
truncate(prisma)
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
概要
Truncateをnpm scriptに組み込みたかった。
検索したところ下記に行き着いた。
が、MySQL用のようで私の環境だとうまく動かないところがあった。
参考に改変させていただきました。
ミソ
パターン共通
- スキーマ名はSQLで直接取得。(.envなどから取れればそれでも良さそう)
- スキーマ名、モデル名のqueryRaw内での展開はPrisma.rawでエスケープしてあげる。(無いと"$1.$2"に解釈されてエラーに)
パターン1
- Prisma.ModelNameからモデル名をテーブル名として拝借。
- Many-to-ManyのリレーションはModelNameに出てこないので、レコードが消え残る可能性はある。
パターン2
- information_schema.tablesからテーブル名を直接取得。全テーブル情報が取れる。
- 同じスキーマ上に違うアプリのテーブルが混在すると全Truncateされるので注意(通常はありえないと思うけど)
- シングルクォーテーション・ダブルクォーテーションは、この形がMust。
- ほぼSQLだよりなので、Prismaらしさはあまり無い。
環境
- Prisma 4.15.0
- Postgresql 14.8
Discussion