Preface
Automatic markdown documents generator for Prisma.
Example markdown document generated by
prisma-markdown
Until last year, I always drew ERDs by hand when developing applications.
I have been drawing ERDs by hand for nearly 20 years, but whenever there was a change in the DB while developing the application, it was always difficult for me to reflect it in the ERD, including documentation and sharing with team members.
It was possible to use automatic ERD generation tools, but these automatic ERD generation tools could not handle documentation. Also, they could not draw proper diagrams when the number of tables increased to hundreds, either.
Therefore, my 20-year development history has always been stained with the pain of drawing ERDs by hand and duplication and missync with actual application code.
To escape from this handwritten ERD hell, I've created a new library called prisma-markdown
. It can automatically generate ERD while covering documentation. Also, by utilizing the pagination concept, prisma-markdown
can draw diagrams properly even if the number of tables exceeds hundreds/thousands.
Let's see how prisma-markdown
made me happy.
Setup
At first, install NPM package.
npm i -D prisma-markdown
At next, add the generator to the schema file, and write documentation comments on models and columns with ///
symbols.
generator markdown {
provider = "prisma-markdown"
title = "Shopping Mall"
output = "./ERD.md"
}
/// Describe table.
///
/// @namespace Actors
model some_users {
/// Describe column.
id String @id @db.Uuid
}
At last, run below command, than ERD.md
file would be generated.
npx prisma generate
Comment Tags
If your database has over hundreds of models, none of automatic ERD generators can express them perfect. In that case, prisma-markdown
recommends you to separate hundreds of models to multiple paginated diagrams by using /// @namepsace <name>
comments.
When you write /// @namepsace <name>
comment on models, they would be separated to proper sections of markdown document. For reference, you can assign multiple @namepsace
s to a model, and if you do not assign any @namepsace
to a model, it would be assigned to default
tag.
Also, if you use @erd <name>
instead of @namespace <name>
, target model would be expressed only at ERD. It would not be appeared to the markdown content section. Otherwise, @describe <name>
tag will show the model only at markdown content section, not at ERD.
-
@namespace <name>
: Both ERD and markdown content -
@erd <name>
: Only ERD -
@describe <name>
: Only markdown content -
@hidden
: Neither ERD nor markdown content
/// Both description and ERD on Actors chatper.
///
/// Also, only ERD on Articles and Orders chapters.
///
/// @namespace Actors
/// @erd Articles
/// @erd Orders
model shopping_customers {}
/// Only description on Actors chapter.
///
/// @describe Actors
model shopping_customer_login_histories {}
/// Only ERD on Articles chapter.
///
/// @erd Articles
model shopping_sale_reviews {}
/// Never be shown.
///
/// @hidden
model shopping_sale_hits {}
Demonstration
To show how prisma-markdown
works, I desinged a shopping mall database, well-known to everyone. When defining a model scheme, write description comment with ///
symbol like below. After that, run npx prisma generate
command, then markdown document with ERD diagrams would be automatically generated.
Prisma Schema File
generator markdown {
provider = "prisma-markdown"
title = "Shopping Mall"
output = "./ERD.md"
}
/// Product composition information handled in the sale snapshot.
///
/// `shopping_sale_snapshot_units` is an entity that embodies the
/// "individual product" information handled in the
/// {@link shopping_sale_snapshots sale snapshot}.
///
/// For reference, the reason why `shopping_sale_snapshot_units` is separated
/// from {@link shopping_sale_snapshots} by an algebraic relationship of
/// 1: N is because there are often cases where multiple products are sold
/// in one listing. This is the case with so-called "bundled products".
///
/// - Bundle from regular product (laptop set)
/// - main body
/// - keyboard
/// - mouse
/// - Apple Care (Free A/S Voucher)
///
/// And again, `shopping_sale_snapshot_units` does not in itself refer to
/// the final {@link shopping_sale_snapshot_unit_stocks stock} that the
/// customer will purchase.
/// The {@link shopping_sale_snapshot_unit_stocks final stock} can be
/// found only after selecting all given
/// {@link shopping_sale_snapshot_unit_options options} and their
/// {@link shopping_sale_snapshot_unit_option_candidates candidate} values.
///
/// For example, even if you buy a laptop, the
/// {@link shopping_sale_snapshot_unit_stocks final stocks} are determined
/// only after selecting all the
/// {@link shopping_sale_snapshot_unit_options options} (CPU / RAM / SSD), etc.
///
/// @namespace Sales
/// @erd Carts
/// @author Samchon
model shopping_sale_snapshot_units {
//----
// COLUMNS
//----
/// @format uuid
id String @id @db.Uuid
/// Belonged snapshot's {@link shopping_sale_snapshots.id}
///
/// @format uuid
shopping_sale_snapshot_id String @db.Uuid
/// Representative name of the unit.
name String @db.VarChar
/// Whether the unit is primary or not.
///
/// Just a labeling value.
primary Boolean @db.Boolean
/// Whether the unit is required or not.
///
/// When the unit is required, the customer must select the unit. If do
/// not select, customer can't buy it.
required Boolean @db.Boolean
/// Sequence order in belonged snapshot.
sequence Int @db.Integer
//----
// RELATIONS
//----
/// Belonged snapshot.
snapshot shopping_sale_snapshots @relation(fields: [shopping_sale_snapshot_id], references: [id], onDelete: Cascade)
/// List of options.
options shopping_sale_snapshot_unit_options[]
/// List of stocks.
stocks shopping_sale_snapshot_unit_stocks[]
/// List of stocks contained in cart item
cart_item_stocks shopping_cart_item_stocks[]
}
Generated Markdown Document
shopping_sale_snapshot_units
Product composition information handled in the sale snapshot.
shopping_sale_snapshot_units
is an entity that embodies the "individual product" information handled in the sale snapshot.For reference, the reason why
shopping_sale_snapshot_units
is separated from shopping_sale_snapshots by an algebraic relationship of 1: N is because there are often cases where multiple products are sold in one listing. This is the case with so-called "bundled products".
- Bundle from regular product (laptop set)
- main body
- keyboard
- mouse
- Apple Care (Free A/S Voucher)
And again,
shopping_sale_snapshot_units
does not in itself refer to the final stock that the customer will purchase. The final stock can be found only after selecting all given options and their candidate values.For example, even if you buy a laptop, the final stocks are determined only after selecting all the options (CPU / RAM / SSD), etc.
Properties
id
:shopping_sale_snapshot_id
: Belonged snapshot's shopping_sale_snapshots.idname
: Representative name of the unit.primary
> Whether the unit is primary or not. > > Just a labeling value.required
> Whether the unit is required or not. > > When the unit is required, the customer must select the unit. If do > not select, customer can't buy it.sequence
: Sequence order in belonged snapshot.
Top comments (1)
he is korea best of best developer.