📜
Prisma SchemaからGraphQL SDLを生成する
背景
Prismaを使っていて、GraphQLはSDL Firstな形で実装している。
SDLは完全にPrismaの定義と一致している必然性はないけど、だいたいいっしょの定義をちくちく書いていかないといけなくて不毛でめんどくさい。
とりあえずのベースとなるSDLを出力して省力化を図る。
実装
Prisma本体でパースした結果を得られる getDMMF
という関数がある。
import {getDMMF} from '@prisma/internals';
今回のケースではこれで十分できそうだけど、得られる情報が一部限定されているので、他のケースも含めて以下の非公式のパーサーを利用させてもらっている。
純粋にパースされた結果をTypeScriptでNarrowingしながら使いやすようになっていて便利。
以下実装
import {readFileSync} from 'fs';
import {join} from 'path';
import {parsePrismaSchema} from '@loancrate/prisma-schema-parser';
const SCHEMA_PATH = join(__dirname, 'prisma', 'schema.prisma');
const main = () => {
const s = readFileSync(SCHEMA_PATH, {encoding: 'utf-8'});
const ast = parsePrismaSchema(s);
const lines = ast.declarations.flatMap(d => {
if (d.kind === 'model') {
return [
`type ${d.name.value} {`,
...d.members
.map(m => {
if (m.kind === 'field') {
const gqlType = (() => {
switch (m.type.kind) {
case 'typeId': {
return m.type.name.value + '!';
}
case 'required': {
if (m.type.type.kind === 'typeId') {
return m.type.type.name.value + '!';
} else {
return undefined;
}
}
case 'optional': {
if (m.type.type.kind === 'typeId') {
return m.type.type.name.value;
} else {
return undefined;
}
}
default:
return undefined;
}
})();
if (gqlType) {
return ` ${m.name.value}: ${gqlType}`;
} else {
return '';
}
}
return '';
})
.filter(s => !!s),
`}`,
'', // 空白行
];
} else if (d.kind === 'enum') {
return [
`enum ${d.name.value} {`,
...d.members
.map(m => {
if (m.kind === 'enumValue') {
return ` ${m.name.value}`;
}
return '';
})
.filter(s => !!s),
`}`,
'', // 空白行
];
}
return [];
});
console.log(lines.join('\n'));
};
main();
Discussion