fuelen / ecto_erd

A mix task for generating Entity Relationship Diagram from Ecto schemas available in your project.
Apache License 2.0
216 stars 15 forks source link

Support for PlantUML ERD format #6

Closed nivertech closed 2 years ago

nivertech commented 2 years ago

PlantUML is not the best ERD diagramming tool [1], but it's the best Diagrams-as-Code tool overall, and also used in C4-PlantUML [2,3] Software Documentation methodology.

[1] https://plantuml.com/ie-diagram [2] https://github.com/plantuml-stdlib/C4-PlantUML [3] https://engineering.linecorp.com/en/blog/diagramming-software-architecture-using-c4-model-and-c4-plantuml/

fuelen commented 2 years ago

Hi @nivertech Thank you for the suggestion. I'll try to add support for this format soon.

fuelen commented 2 years ago

@nivertech Here is a result of my first prototype. It looks a bit weird. Are there any recommendations how to make it better?

image ![зображення](https://user-images.githubusercontent.com/588762/134582889-8b1a200e-083e-4cc6-8857-102e28a30792.png)
code ```plantuml @startuml left to right direction ' hide the spot hide circle hide methods ' avoid problems with angled crows feet skinparam linetype ortho entity "Hexpm.Accounts.AuditLog" { id : integer -- user_agent : varchar action : varchar params : jsonb user_id : integer organization_id : integer inserted_at : timestamp } entity "Hexpm.Accounts.Email" { id : integer -- email : varchar verified : boolean primary : boolean public : boolean gravatar : boolean verification_key : varchar verification_expiry : timestamp user_id : integer inserted_at : timestamp updated_at : timestamp } entity "Hexpm.Accounts.Key" { id : integer -- name : varchar secret_first : varchar secret_second : varchar public : boolean revoke_at : timestamp revoked_at : timestamp inserted_at : timestamp updated_at : timestamp last_use : jsonb user_id : integer organization_id : integer permissions : jsonb } entity "Hexpm.Accounts.Key.Use" { id : uuid -- used_at : timestamp user_agent : varchar ip : varchar } entity "Hexpm.Accounts.KeyPermission" { id : uuid -- domain : varchar resource : varchar } entity "Hexpm.Accounts.Organization" { id : integer -- name : varchar billing_active : boolean inserted_at : timestamp updated_at : timestamp } entity "Hexpm.Accounts.OrganizationUser" { id : integer -- role : varchar organization_id : integer user_id : integer inserted_at : timestamp updated_at : timestamp } entity "Hexpm.Accounts.PasswordReset" { id : integer -- key : varchar primary_email : varchar user_id : integer inserted_at : timestamp } entity "Hexpm.Accounts.RecoveryCode" { id : uuid -- code : varchar used_at : timestamp } entity "Hexpm.Accounts.Session" { id : integer -- token : bytea data : jsonb inserted_at : timestamp updated_at : timestamp } entity "Hexpm.Accounts.TFA" { secret : varchar tfa_enabled : boolean app_enabled : boolean recovery_codes : jsonb } entity "Hexpm.Accounts.User" { id : integer -- username : varchar full_name : varchar password : varchar service : boolean deactivated_at : timestamp role : varchar inserted_at : timestamp updated_at : timestamp handles : jsonb tfa : jsonb organization_id : integer } entity "Hexpm.Accounts.UserHandles" { id : uuid -- twitter : varchar github : varchar elixirforum : varchar freenode : varchar slack : varchar } entity "Hexpm.BlockAddress.Entry" { id : integer -- ip : varchar comment : varchar } entity "Hexpm.Repository.Download" { id : integer -- release_id : integer downloads : integer day : date } entity "Hexpm.Repository.Install" { id : integer -- hex : varchar elixirs : array } entity "Hexpm.Repository.Package" { id : integer -- name : varchar docs_updated_at : timestamp inserted_at : timestamp updated_at : timestamp repository_id : integer meta : jsonb } entity "Hexpm.Repository.PackageDependant" { id : integer -- package_id : integer name : varchar repo : varchar } entity "Hexpm.Repository.PackageDownload" { package_id : integer view : varchar downloads : integer } entity "Hexpm.Repository.PackageMetadata" { id : uuid -- description : varchar licenses : array links : jsonb maintainers : array extra : jsonb } entity "Hexpm.Repository.PackageOwner" { id : integer -- level : varchar package_id : integer user_id : integer inserted_at : timestamp updated_at : timestamp } entity "Hexpm.Repository.PackageReport" { id : integer -- state : varchar description : varchar author_id : integer package_id : integer inserted_at : timestamp updated_at : timestamp } entity "Hexpm.Repository.PackageReportComment" { id : integer -- text : varchar inserted_at : timestamp updated_at : timestamp package_report_id : integer author_id : integer } entity "Hexpm.Repository.PackageReportRelease" { id : integer -- release_id : integer package_report_id : integer inserted_at : timestamp updated_at : timestamp } entity "Hexpm.Repository.Release" { id : integer -- version : varchar inner_checksum : bytea outer_checksum : bytea has_docs : boolean inserted_at : timestamp updated_at : timestamp package_id : integer publisher_id : integer meta : jsonb retirement : jsonb } entity "Hexpm.Repository.ReleaseDownload" { release_id : integer downloads : integer } entity "Hexpm.Repository.ReleaseMetadata" { id : uuid -- app : varchar build_tools : array elixir : varchar } entity "Hexpm.Repository.ReleaseRetirement" { id : uuid -- reason : varchar message : varchar } entity "Hexpm.Repository.Repository" { id : integer -- name : varchar public : boolean inserted_at : timestamp updated_at : timestamp organization_id : integer } entity "Hexpm.Repository.Requirement" { id : integer -- app : varchar requirement : varchar optional : boolean release_id : integer dependency_id : integer } entity "Hexpm.ShortURLs.ShortURL" { id : integer -- url : varchar short_code : varchar inserted_at : timestamp } entity "Ecto.Migration.SchemaMigration" { version : integer inserted_at : timestamp } "Hexpm.Repository.Package" ||-o| "Hexpm.Repository.PackageMetadata" "Hexpm.Accounts.User" ||-|{ "Hexpm.Accounts.Email" "Hexpm.Repository.Package" ||-|{ "Hexpm.Repository.PackageOwner" "Hexpm.Accounts.Organization" ||-|{ "Hexpm.Accounts.AuditLog" "Hexpm.Accounts.User" ||-o| "Hexpm.Accounts.TFA" "Hexpm.Accounts.User" ||-|{ "Hexpm.Repository.PackageReportComment" "Hexpm.Accounts.Organization" ||-|{ "Hexpm.Accounts.Key" "Hexpm.Accounts.Organization" ||-|{ "Hexpm.Accounts.OrganizationUser" "Hexpm.Accounts.User" ||-|{ "Hexpm.Accounts.OrganizationUser" "Hexpm.Accounts.Organization" ||-o| "Hexpm.Repository.Repository" "Hexpm.Accounts.User" ||-|{ "Hexpm.Repository.PackageReport" "Hexpm.Repository.Package" ||-|{ "Hexpm.Repository.PackageReport" "Hexpm.Repository.Release" ||-|{ "Hexpm.Repository.Download" "Hexpm.Repository.Package" ||-|{ "Hexpm.Repository.Release" "Hexpm.Accounts.User" ||-|{ "Hexpm.Accounts.Key" "Hexpm.Accounts.Key" ||-|{ "Hexpm.Accounts.KeyPermission" "Hexpm.Accounts.Organization" ||-o| "Hexpm.Accounts.User" "Hexpm.Repository.PackageReport" ||-|{ "Hexpm.Repository.PackageReportComment" "Hexpm.Accounts.TFA" ||-|{ "Hexpm.Accounts.RecoveryCode" "Hexpm.Accounts.User" ||-|{ "Hexpm.Accounts.PasswordReset" "Hexpm.Repository.Release" ||-o| "Hexpm.Repository.ReleaseDownload" "Hexpm.Repository.Release" ||-|{ "Hexpm.Repository.Requirement" "Hexpm.Repository.Release" ||-|{ "Hexpm.Repository.PackageReportRelease" "Hexpm.Accounts.User" ||-o| "Hexpm.Accounts.UserHandles" "Hexpm.Repository.Package" ||-|{ "Hexpm.Repository.Requirement" "Hexpm.Repository.Release" ||-o| "Hexpm.Repository.ReleaseMetadata" "Hexpm.Repository.Release" ||-o| "Hexpm.Repository.ReleaseRetirement" "Hexpm.Repository.PackageReport" ||-|{ "Hexpm.Repository.PackageReportRelease" "Hexpm.Accounts.User" ||-|{ "Hexpm.Repository.Release" "Hexpm.Accounts.Key" ||-o| "Hexpm.Accounts.Key.Use" "Hexpm.Repository.Repository" ||-|{ "Hexpm.Repository.Package" "Hexpm.Repository.Package" ||-|{ "Hexpm.Repository.PackageDownload" "Hexpm.Accounts.User" ||-|{ "Hexpm.Repository.PackageOwner" "Hexpm.Accounts.User" ||-|{ "Hexpm.Accounts.AuditLog" "Hexpm.Repository.Package" ||-|{ "Hexpm.Repository.PackageDependant" @enduml ```
nivertech commented 2 years ago

@fuelen Hexpm is a large example. ERD is an extension of Class Diagrams [1]. There is some limited layout support [2]

[1] https://plantuml.com/class-diagram [2] https://plantuml.com/class-diagram#c08f8d9927fcb626

Maybe you can use namespaces or packages to group entities together:

http://alphadoc.plantuml.com/doc/dokuwiki/en/class-diagram#lpfxhwn73pnmk362kj9v

fuelen commented 2 years ago

@nivertech thanks for the links. I found, that usage of ||--o| and ||--|{ instead of ||-o| and ||-|{ makes everything nice :slightly_smiling_face:

fuelen commented 2 years ago

@nivertech published version v0.4.0 with PlantUML support.

nivertech commented 2 years ago

@fuelen tested it yesterday - works fine. Thanks!