I made ERD and documents genertor of Prisma ORM
Tags: prisma, typescript, opensource, database
Published: 2023-09-15 05:54:04

## Preface
Automatic markdown documents generator for Prisma.

  - [Github Repository](https://github.com/samchon/prisma-markdown)
  - [Generated Markdown Example](https://github.com/samchon/prisma-markdown/blob/master/ERD.md)
  - [Target Prisma Schema File](https://github.com/samchon/prisma-markdown/blob/master/schema.prisma)


[![prisma-markdown-example](https://github.com/samchon/prisma-markdown/assets/13158709/80ca9c8e-4c96-4deb-a8cb-674e9845ebf6)](https://github.com/samchon/prisma-markdown/blob/master/ERD.md)

> [Example markdown document](https://github.com/samchon/prisma-markdown/blob/master/ERD.md) generated by [`prisma-markdown`](https://github.com/samchon/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](https://www.prisma.io) 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](https://www.prisma.io) schema file. Let's enjoy the new world.




## Setup
At first, install NPM package.

```bash
npm i -D prisma-markdown
```

At next, add the generator to the schema file, and write documentation comments on models and columns with `///` symbols.

```prisma
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`](https://github.com/samchon/prisma-markdown/blob/master/ERD.md) file would be generated.

```bash
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

```prisma
/// 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

  - [Generated Markdown Example](https://github.com/samchon/prisma-markdown/blob/master/ERD.md)
  - [Target Prisma Schema File](https://github.com/samchon/prisma-markdown/blob/master/schema.prisma)

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
```prisma
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](#shopping_sale_snapshots).
> 
> For reference, the reason why `shopping_sale_snapshot_units` is separated from [shopping_sale_snapshots](#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](#shopping_sale_snapshot_unit_stocks) that the customer will purchase. The [final stock](#shopping_sale_snapshot_unit_stocks) can be found only after selecting all given [options](#shopping_sale_snapshot_unit_options) and their [candidate](#shopping_sale_snapshot_unit_option_candidates) values.
> 
> For example, even if you buy a laptop, the [final stocks](#shopping_sale_snapshot_unit_stocks) are determined only after selecting all the [options](#shopping_sale_snapshot_unit_options) (CPU / RAM / SSD), etc.
> 
> **Properties**
>   - `id`: 
>   - `shopping_sale_snapshot_id`: Belonged snapshot's [shopping_sale_snapshots.id](#shopping_sale_snapshots)
>   - `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.