Skip to content

mermaid_converter

mermaid_converter

OSI semantic model → Mermaid ERD converter.

Converts a list of OsiSemanticModel objects (one Domo data model) into a MermaidERDiagram using the existing crew_dcs ERD infrastructure.

OSI coverage

Datasets → MermaidEREntity nodes Entity (primary) → col_type "entity" + PK key Entity (foreign) → col_type "entity" + FK key Dimension (cat) → col_type "categorical" Dimension (time) → col_type "temporal" Metric → col_type "metric" + expression in comment Description → column comment Synonyms → column comment "syn: a, b" Relationship → MermaidERRelationship join_type INNER → identifying (solid) line join_type LEFT → non-identifying (dashed) line cardinality → crow's-foot notation join fields → relationship label "from_field → to_field"

OsiMermaidConverter dataclass

OsiMermaidConverter()

Convert a list of OsiSemanticModel objects to a MermaidERDiagram.

Each OsiSemanticModel becomes one entity. Entities, dimensions, and metrics become typed columns. Relationships become ERD relationship lines with cardinality and join-field labels.

Example

from crew_dcs.integrations.osi import OsiMermaidConverter diagram = OsiMermaidConverter().convert(osi_models, title="DomoStats") print(diagram.export_to_markdown())

convert

convert(
    models: list[OsiSemanticModel],
    title: str | None = None,
    simple: bool = False,
) -> MermaidERDiagram

Convert OSI models to a Mermaid ERD.

Parameters:

Name Type Description Default
models list[OsiSemanticModel]

OSI semantic models to render.

required
title str | None

Optional diagram title.

None
simple bool

When True, render only PK/FK entity columns using the standard string type — no dimension/metric columns, no comments. Produces a minimal diagram that renders reliably in all Mermaid environments (VSCode, GitHub, etc.). When False (default), render all columns with rich type labels and inline description comments.

False
Source code in src/crew_dcs/integrations/osi/mermaid_converter.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
def convert(
    self,
    models: list[OsiSemanticModel],
    title: str | None = None,
    simple: bool = False,
) -> MermaidERDiagram:
    """Convert OSI models to a Mermaid ERD.

    Args:
        models: OSI semantic models to render.
        title: Optional diagram title.
        simple: When True, render only PK/FK entity columns using the
            standard ``string`` type — no dimension/metric columns, no
            comments.  Produces a minimal diagram that renders reliably
            in all Mermaid environments (VSCode, GitHub, etc.).
            When False (default), render all columns with rich type
            labels and inline description comments.
    """
    diagram = MermaidERDiagram(title=title)
    name_to_entity: dict[str, MermaidEREntity] = {}

    # Pass 1 — build one entity per OSI model
    for model in models:
        entity = MermaidEREntity(id=model.source_dataset_id, name=model.name)

        for ent in model.entities:
            entity.add_column(
                MermaidERColumn(
                    name=_col_name(ent.name),
                    col_type="string",
                    key="PK" if ent.type == "primary" else "FK",
                )
            )

        if not simple:
            for dim in model.dimensions:
                entity.add_column(
                    MermaidERColumn(
                        name=_col_name(dim.name),
                        col_type="temporal"
                        if dim.type == "time"
                        else "categorical",
                        comment=_dim_comment(dim),
                    )
                )

            for metric in model.metrics:
                entity.add_column(
                    MermaidERColumn(
                        name=_col_name(metric.name),
                        col_type="metric",
                        comment=_metric_comment(metric),
                    )
                )

        diagram.add_entity(entity)
        name_to_entity[model.name] = entity

    # Pass 2 — relationships (deduplicated by entity pair via add_relationship)
    for model in models:
        for rel in model.relationships:
            from_ent = name_to_entity.get(rel.from_model)
            to_ent = name_to_entity.get(rel.to_model)
            if from_ent is None or to_ent is None:
                continue

            cardinality = _CARDINALITY_MAP.get(
                (rel.cardinality or "").lower(),
                CARDINALITY_ONE_TO_ZERO_OR_MANY,
            )
            identifying = rel.join_type.upper() in _IDENTIFYING_JOINS
            label = f"{rel.from_field} -> {rel.to_field}"

            diagram.add_relationship(
                MermaidERRelationship(
                    from_entity=from_ent,
                    to_entity=to_ent,
                    cardinality=cardinality,
                    label=label,
                    identifying=identifying,
                )
            )

    return diagram