datnguye / dbterd

Generate the ERD as a code from dbt artifacts
https://dbterd.datnguyen.de/
MIT License
198 stars 28 forks source link

[FEAT] Allows drawing recursive relationships #88

Closed syou6162 closed 6 months ago

syou6162 commented 6 months ago

Is your feature request related to a problem? Please describe. Currently, dbterd cannot draw parent-child relationships such as categories.

For example:

version: 2
sources:
  - name: my_dataset
    database: my_project
    tables:
      - name: Category
        freshness:
        columns:
          - name: parentCategoryId
            tests:
              - relationships:
                  to: source("my_project", "Category")
                  field: categoryId

If you include a test for these recursive relationships, dbterd will fail with the following error

% dbterd run -t mermaid 
2024-02-18 00:04:15,812 - dbterd - INFO - Run with dbterd==1.11.0b1 (main.py:54)
2024-02-18 00:04:15,812 - dbterd - INFO - Using dbt artifact dir at: /Users/yasuhisa.yoshida/my_project/target (base.py:76)
Traceback (most recent call last):
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/bin/dbterd", line 8, in <module>
    sys.exit(main())
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/main.py", line 6, in main
    cli.dbterd()
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/cli/params.py", line 75, in wrapper
    return func(*args, **kwargs)  # pragma: no cover
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/cli/params.py", line 201, in wrapper
    return func(*args, **kwargs)  # pragma: no cover
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/cli/main.py", line 66, in run
    Executor(ctx).run(**kwargs)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/adapters/base.py", line 32, in run
    self.__run_by_strategy(**kwargs)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/adapters/base.py", line 200, in __run_by_strategy
    result = operation(manifest=manifest, catalog=catalog, **kwargs)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/adapters/targets/mermaid/mermaid_test_relationship.py", line 17, in run
    return ("output.md", parse(manifest, catalog, **kwargs))
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/adapters/targets/mermaid/mermaid_test_relationship.py", line 80, in parse
    tables, relationships = test_relationship.parse(
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/adapters/algos/test_relationship.py", line 80, in parse
    relationships = base.get_relationships(manifest=manifest, **kwargs)
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/adapters/algos/base.py", line 422, in get_relationships
    refs = [
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/adapters/algos/base.py", line 425, in <listcomp>
    table_map=get_table_map(test_node=manifest.nodes[x], **kwargs),
  File "/Users/yasuhisa.yoshida/.pyenv/versions/3.10.0/lib/python3.10/site-packages/dbterd/adapters/algos/base.py", line 585, in get_table_map
    if f'("{map[1].split(".")[-1]}")'.lower() in to_model.replace("'", '"').lower():
IndexError: list index out of range

The relevant code is below.

In these cases, dbterd will fail because the depends_on.nodes in manifest.json does not contain the two elements.

  "depends_on": {
    "macros": [
      "macro.dbt.test_relationships",
    ],
    "nodes": [
      "source.my_project.my_dataset.Category"
    ]
  },

Describe the solution you'd like Allow drawing even when recursive relationships are involved. The simplest solution would be to modify the relevant code as follows.

    map = test_node.depends_on.nodes or []
    if len(map) == 1:
        return [map[0], map[0]]
    ....

Describe alternatives you've considered N/A

datnguye commented 6 months ago

Nice finding @syou6162 🚀