Skip to main content

Convert compiled Microsoft Dynamics 365 Business Central AL packages (.app) into DBML schemas.

Project description

AL-to-DBML

PyPI version Python versions CI License: MIT Ruff

al2dbml is a small Python CLI that converts a compiled Microsoft Dynamics 365 Business Central AL package (.app) into a DBML schema you can paste straight into dbdiagram.io or dbdocs.io. The pipeline reads SymbolReference.json from the .app archive (tolerating AL's 40-byte header), normalises tables, extensions, enums, and TableRelations, and emits one valid DBML document with Table, Ref, Enum, and TableGroup sections.

Release history and per-version notes live in CHANGELOG.md.

Install

Python 3.10+ is required. The runtime depends only on click and pydbml.

Recommended: uv tool install

uv installs CLI tools into isolated environments and puts the entry point on your PATH, so al2dbml is available globally without touching your system Python.

uv tool install al2dbml

If you don't already have uv:

# Fedora / RHEL / CentOS
sudo dnf install uv

# macOS (Homebrew)
brew install uv

# Anywhere (standalone installer)
curl -LsSf https://astral.sh/uv/install.sh | sh

Upgrade later with uv tool upgrade al2dbml, uninstall with uv tool uninstall al2dbml.

Alternative: pipx

pipx install al2dbml

Alternative: plain pip

Works inside an activated virtualenv. On modern distros that mark system Python as externally-managed (PEP 668), prefer uv tool or pipx instead.

pip install al2dbml

Verify

al2dbml --version
al2dbml --help

Quickstart

al2dbml MyApp.app -o schema.dbml

Drop schema.dbml into https://dbdiagram.io. Without -o, the DBML is streamed to stdout so you can pipe it elsewhere.

al2dbml MyApp.app | less

Grouping

By default tables are bucketed into TableGroups by the last segment of their AL namespace (so Microsoft.Finance.GeneralLedger -> group GeneralLedger). Tables that have no namespace tag fall back to the first whitespace-separated word in their name (so Sales Header + Sales Line -> group Sales). Buckets smaller than two tables are dropped so single-table groups don't clutter the diagram.

Override the source with --group-by:

al2dbml MyApp.app --group-by namespace   # default
al2dbml MyApp.app --group-by word        # legacy first-word grouping
al2dbml MyApp.app --group-by none        # no auto groups (only explicit --group rules apply)
# Auto grouping (default)
al2dbml MyApp.app -o schema.dbml

# Explicit rules; the value is NAME=PATTERN[,PATTERN...] and -g is repeatable
al2dbml MyApp.app -g "Documents=Sales*,Purch*" -g "Master=Customer,Vendor,Item"

# Disable grouping entirely
al2dbml MyApp.app --no-groups

# Keep singleton groups too
al2dbml MyApp.app --min-group-size 1

Rich field descriptions (aldoc overlay)

By default, column notes are built from the AL Caption property in SymbolReference.json — which is usually just the field name itself. Real BC field documentation (the "Specifies the customer number..." sentences you see on Microsoft Learn) lives in the AL ToolTip property and /// <summary> XML doc comments, neither of which the compiled .app package preserves.

To get those rich descriptions into your diagram, run aldoc (Microsoft's official AL documentation generator, bundled with the AL Language VS Code extension) once to produce a YAML reference tree, then point al2dbml at it with -d/--docs:

# Step 1: generate docs from your .app (slow, but only once per release)
aldoc generate MyApp.app -o ./myapp-docs/

# Step 2: render the DBML with descriptions overlaid (fast)
al2dbml MyApp.app --docs ./myapp-docs/ -o schema.dbml

The result:

  • Each table block gets a Note { ... } body sourced from the AL /// <summary> of the table — e.g. "Stores document-level information for sales quotes, orders, invoices, credit memos, blanket orders, and return orders."
  • Each column note leads with the AL ToolTip text — e.g. "Specifies the customer number to whom the goods or services are sold."
  • Existing condition / **References** sections still follow, separated by <br><br>

Coverage is uneven: active-document tables (Sales Header, Customer, Item, etc.) are richly documented in real BC; history and buffer tables often have nothing. Where aldoc has no entry, the original Caption-based note (or no note) is used.

TableExtensions

Extensions are merged into their target tables by default. Use --no-merge-extensions to emit them as separate <Target> (Extension) tables instead.

Public Python API

from al2dbml import Diagram, generate, GroupingConfig

# One-shot helper
dbml = generate("MyApp.app", output_path="schema.dbml")

# Or step-by-step for custom grouping
diagram = Diagram.from_app(
    "MyApp.app",
    grouping=GroupingConfig(rules={"Documents": ["Sales*", "Purch*"]}),
)
print(diagram.dbml())

Limitations

  • FlowFields are treated as regular fields — the underlying CalcFormula is not interpreted.
  • Obsolete fields are emitted alongside active ones; no filtering by ObsoleteState.
  • Multi-field primary keys are represented as multiple [pk] flags rather than a composite index, matching DBML's single-PK convention.
  • Multi-column secondary keys are not yet emitted as DBML indexes; only single-column secondary keys are surfaced (as [unique] on the column).
  • Cross-package references (table relations that point to a table outside the current .app) are preserved as notes on the source column, since the target table is not present in the diagram.
  • IF (...) ... ELSE IF (...) ... ELSE ... conditional TableRelation expressions are parsed into one DBML Ref per resolved branch, with each branch's condition recorded in the source column's note. Branches whose target table is missing from the current .app degrade to notes only.
  • Render time scales quadratically with the table count inside the underlying pydbml library. Small/medium packages (up to a few hundred tables) finish in under a second. Microsoft's full Base Application (~1,500 tables) currently takes several minutes to render, even though parsing itself is fast. A custom DBML emitter is on the roadmap to remove this cliff.

Development

python -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest -q
.venv/bin/ruff check .

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

al2dbml-0.8.3.tar.gz (49.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

al2dbml-0.8.3-py3-none-any.whl (36.6 kB view details)

Uploaded Python 3

File details

Details for the file al2dbml-0.8.3.tar.gz.

File metadata

  • Download URL: al2dbml-0.8.3.tar.gz
  • Upload date:
  • Size: 49.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for al2dbml-0.8.3.tar.gz
Algorithm Hash digest
SHA256 195a19c1140c3ee0514d0abaf75bbdd69416d26828d2f8ef3264de62e0b12b51
MD5 1a4c50c01c3ca68a5f3eb6bdc3a8cc35
BLAKE2b-256 2582c456875979cb964edd26478d1498ac8011df0500a3ca106ff2731dcc8521

See more details on using hashes here.

Provenance

The following attestation bundles were made for al2dbml-0.8.3.tar.gz:

Publisher: publish.yml on mykola-kharchenko/al2dbml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file al2dbml-0.8.3-py3-none-any.whl.

File metadata

  • Download URL: al2dbml-0.8.3-py3-none-any.whl
  • Upload date:
  • Size: 36.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for al2dbml-0.8.3-py3-none-any.whl
Algorithm Hash digest
SHA256 f4a01f5d2f82b56892ccfaf85bef6f83e23f82484a491f5be096594e25250931
MD5 64b8118d9c4e586978920c16f01484c0
BLAKE2b-256 62df894652f05d629e94ce86dff0aebee89a5b7c9a0be76f7621abe35d2a3da9

See more details on using hashes here.

Provenance

The following attestation bundles were made for al2dbml-0.8.3-py3-none-any.whl:

Publisher: publish.yml on mykola-kharchenko/al2dbml

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page