DEV Community

Cover image for I made ERD and documents genertor of Prisma ORM
Jeongho Nam
Jeongho Nam

Posted on • Updated on

I made ERD and documents genertor of Prisma ORM

Preface

Automatic markdown documents generator for Prisma.

prisma-markdown-example

Example markdown document generated by prisma-markdown

When developing a backend system, I draw ERD (Entity Relationship Diagram) first. And then, write a document describing the ERD to educate companions. After those designings and documentations, I start developing the backend server with ORM programming.

By the way, as the pre-designed ERD can't be perfect as I'm not a god, schema structures of database often being changed during the development. Those changes sometimes come from change of requirements, and sometimes come from my mistake that omitting principle concepts. Anyway, in that case, I have to re-draw the ERD, and re-write the document. It's so annoying and hard to managing.

To avoid such a duplicated job, I'd tried to find a proper tool that can generate ERD and describing documents automatically from the schema file. However, none of them could satisfy me. There had not been any tool which can generate both ERD and document at the same time. Even in the ERD case, none of them working properly when hundreds of tables come, either.

Therefore, I made it by myself. If you're a prisma user and need to write document decribing the database design, let's automate it. From now on, I'll show you how to install and build the documents from the prisma schema file. Let's enjoy the new world.

Setup

At first, install NPM package.

npm i -D prisma-markdown
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

At last, run below command, than ERD.md file would be generated.

npx prisma generate
Enter fullscreen mode Exit fullscreen mode

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 @namepsaces 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 {}
Enter fullscreen mode Exit fullscreen mode

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[]
}
Enter fullscreen mode Exit fullscreen mode

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.id
  • name: 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 (4)

Collapse
 
gktim profile image
gkTim

Nice, good work!

Collapse
 
hungtrinh profile image
Hưng Trịnh

Thanks for your share

Collapse
 
wefactory profile image
wefactory

i love this

Collapse
 
sirajulm profile image
Sirajul Muneer

Nice one ❤️