Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate Mermaid class diagram (or expose DAG) from schema #3304

Closed
ingun37 opened this issue Jul 19, 2024 · 9 comments
Closed

Generate Mermaid class diagram (or expose DAG) from schema #3304

ingun37 opened this issue Jul 19, 2024 · 9 comments
Labels
enhancement New feature or request schema

Comments

@ingun37
Copy link

ingun37 commented Jul 19, 2024

What is the problem this feature would solve?

Developers want to visualize and document their data schema, likely in UML Class diagram. For those who define their type in the traditional way would have to draw the diagram manually, and it's a big maintenance cost.

What is the feature you are proposing to solve the problem?

A function that takes a schema and generate Mermaid Class Diagram. It will be particularly useful for developers who document their domain logic in GitHub Markdown because they supports Mermaid.

What alternatives have you considered?

writing manually

@ingun37 ingun37 added the enhancement New feature or request label Jul 19, 2024
@ingun37
Copy link
Author

ingun37 commented Jul 19, 2024

I would love to make a PR myself if you'd approve making this feature and give me some guidance.

@gcanti gcanti added the schema label Jul 19, 2024
@gcanti
Copy link
Contributor

gcanti commented Jul 19, 2024

Could you please provide an example including the schemas and the expected diagram?

@ingun37
Copy link
Author

ingun37 commented Jul 21, 2024

@gcanti Here are some rules I'm thinking

  • Annotation of properties and types follows typescript syntax
  • Omit access specifiers (public +, private -)
  • Unify the relation between entities with Association rather than using aggregation or composition for the simplicity. Because I don't think there's distinction of have-relations in Schema.
  • Optional, N-to-N relations are expressed with cardinality.
  • Discriminated types are expressed with inheritance. Maybe group them with namespace for the readability
  • For Struct, use annotation to know its name. For Class, use unique identifier
const Person = Struct({
  name: Schema.Number,
  age: Schema.String,
  religion: Schema.optional(Schema),
  degrees: Schema.Array(Degree),
}).annotations({ title: "Person" })

const Religion = Struct({
  name: Schema.String
}).annotations({ title: "Religion" })

const Bachelor = Schema.Struct({
  kind: Schema.Literal("bachelor"),
}).annotations({ title: "Bachelor" })

const Master = Schema.Struct({
  kind: Schema.Literal("master"),
  thesis: Thesis
}).annotations({ title: "Master" });

const Thesis = Schema.Struct({}).annotations({ title: "Thesis" })

const Degree = Schema.Union(Bachelor, Square).annotations({ title: "Degree" })
classDiagram
class Person {
  name: string
  age: number
  religion?: Religion
  degrees: Degree[]
}
class Religion {
 name: string
}
namespace Degrees {
class Degree {
  kind: "master" | "bachelor"
}
class Master {
  kind: "master"
  thesis: Thesis
}
class Bachelor {
  kind: "bachelor"
}
}
class Thesis
Person --> Religion
Person "1" --> "*" Degree
Degree <|-- Master
Degree <|-- Bachelor
Master --> Thesis
Loading

(I notated cardinatily but it's not rendering. I guess it's a current bug.)

@fubhy
Copy link
Member

fubhy commented Jul 21, 2024

That's a DAG. So we first need graph data structures in Effect. Deriving a mermaid representation from a DAG is trivial

@gcanti
Copy link
Contributor

gcanti commented Jul 21, 2024

@fubhy It depends on the meaning assigned to the edges. For instance, if the directed edge represents the relation "this schema uses this schema" then it's not acyclic (counterexamples: recursive schemas, mutually recursive schemas)

@fubhy
Copy link
Member

fubhy commented Jul 21, 2024

True. I was just refering to this specific example. My point is, I would like to have graph data structures in effect modules. For various types of graphs. Once we have those, rendering them with mermaid is trivial, whether it is a DAG or not. My second point was that, from an api design standpoint, I think it would be desirable to go schema -> graph -> mermaid instead of schema -> mermaid.

@ingun37
Copy link
Author

ingun37 commented Jul 21, 2024

If you could expose underlying graph data structure then I guess I could achieve the same thing. I'll appreciate that too.

@ingun37 ingun37 changed the title Automatic Mermaid class diagram generation from schema Automatic Mermaid class diagram generation (or expose DAG) from schema Jul 28, 2024
@ingun37 ingun37 changed the title Automatic Mermaid class diagram generation (or expose DAG) from schema Generate Mermaid class diagram (or expose DAG) from schema Jul 28, 2024
@ingun37
Copy link
Author

ingun37 commented Sep 11, 2024

I managed to make one using JSONSchema. Closing.

@ingun37 ingun37 closed this as completed Sep 11, 2024
@jessekelly881
Copy link
Contributor

jessekelly881 commented Oct 3, 2024

I'm pretty sure if you treat the asts as vertices and use for example {type: "union_member", index: 1}, { type:"rest_element" }, etc. as edges you could perfectly map a schema to a graph(and back) without any loss of data. It would then be pretty easy to just map and simplify the edges and vertices as needed.

const m = HashMap.make<[[AST.AST, [AST.AST, E][]]]>([] as any);

// adjacency list
HashMap.set(m, Bachelor.ast, []);
HashMap.set(m, Degree.ast, [[Bachelor.ast, { type: "union_member", index: 1 }]]);
const adjacencyList = {
  [Person.ast]: [
    [Schema.Number.ast, { type: "field", name: "name" } ], // Person -> Number
    [Schema.String.ast, { type: "field", name: "age" } ], // Person -> String
    [Religion.ast, { type: "optional_field", name: "religion" }], // Person -> Religion
    [Degree.ast, { type: "rest_element", name: "degrees" } ]  // Person -> Degree
  ],
  [Religion.ast]: [
    [Schema.String.ast, { type: "field", name: "name" } ]
  ],
  // ...
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request schema
Projects
None yet
Development

No branches or pull requests

4 participants