UNPKG

prisma-markdown

Version:

Prisma Markdown documents generator including ERD diagrams and comment descriptions

116 lines (103 loc) 3.31 kB
import { DMMF } from "@prisma/generator-helper"; import { PrismaUtil } from "../utils/PrismaUtil"; import { FieldUtil } from "../utils/field-util"; export namespace MermaidWriter { export const write = (chapter: DMMF.Model[]) => [ "```mermaid", "erDiagram", ...chapter.map(writeTable), ...chapter .map((model) => model.fields .filter((f) => f.kind === "object") .map(writeRelationship({ group: chapter, model })), ) .flat() .filter((str) => !!str.length), "```", ].join("\n"); const writeTable = (model: DMMF.Model): string => [ `${JSON.stringify(model.dbName ?? model.name)} {`, ...model.fields .filter((f) => f.kind !== "object") .map(writeField(model)) .map((str) => ` ${str}`), "}", ].join("\n"); const writeField = (model: DMMF.Model) => (field: DMMF.Field): string => { const isFK = model.fields.some( (f) => f.kind === "object" && f.relationFromFields?.[0] === field.name, ); const targetField = FieldUtil(field, isFK); return [ targetField.data().size ? targetField.format("t(s)") : targetField.format("t"), targetField.format("n"), targetField.format("k"), targetField.format("r"), ] .filter((str) => !!str.length) .join(" "); }; const writeRelationship = (props: { group: DMMF.Model[]; model: DMMF.Model }) => (field: DMMF.Field): string => { if (!field.relationFromFields?.length) return ""; const column: string = field.relationFromFields[0]; const scalar: DMMF.Field | undefined = props.model.fields.find( (s) => column === s.dbName || column === s.name, ); if (scalar === undefined) return ""; const target: DMMF.Model | undefined = props.group.find( (t) => t.name === field.type, ); if (target === undefined) return ""; const oneToOne: boolean = scalar.isId || scalar.isUnique; const arrow: string = [ oneToOne ? "|" : "}", oneToOne && props.group.some( (m) => m.name === field.type && m.fields.some( (f) => f.relationName === field.relationName && !f.isRequired, ), ) ? "o" : isMandatoryMany({ model: props.model, field, target }) ? "|" : "o", "--", scalar.isRequired ? "|" : "o", "|", ].join(""); return [ JSON.stringify(props.model.dbName ?? props.model.name), arrow, JSON.stringify(target.dbName ?? target.name), ":", field.name, ].join(" "); }; const isMandatoryMany = (props: { target: DMMF.Model; model: DMMF.Model; field: DMMF.Field; }): boolean => { const opposite = props.target.fields.find( (f) => f.relationName === props.field.relationName && f.type === props.model.name, ); if (opposite === undefined) return false; const values: string[] = PrismaUtil.tagValues("minItems")(opposite); if (values.length === 0) return false; const numeric: number = Number(values[0]); return !isNaN(numeric) && numeric >= 1; }; }