BurntSushi / erd

Translates a plain text description of a relational database schema to a graphical entity-relationship diagram.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

it would be nice to allow the relationships to terminate at particular fields.

windbender opened this issue · comments

Right now the relationships are table to table.
[users]
*id
name

[cats]
*id
name
owner_id

users 1--* cats
However inside a database, the relationships are expressed as a field to field. For example.

[users]
*id
name

[cats]
*id
name
owner_id

users:id 1--* cats: owner_id <----- THIS HERE IS WHAT IS DIFFERENT

It turns out that the dot language has a means of expressing the "port" to which a connecting line will connect. See page 20 of the follow doc: https://www.graphviz.org/pdf/dotguide.pdf. avoid the compass point concept and look at. the . things.

I realize this would not be backwards compatible since the

: notation is new. Perhaps there is a better technique to express this in the erd language.

Sorry no PR from at this time, I know nothing about Haskell.

I wholeheartedly support this request!

I have added a very basic support of ports on this fork:
The following erd code

[Person]
*name { port:"name" }
height
weight
`birth date`
+birth_place_id

[`Birth Place`]
*id
`birth city`
'birth state'
"birth country" { port: "birth country" }

Person *--1 `Birth Place` { tailport:"name", headport:"birth country" }

produces: ( I don't know whether the difference in height between the tables is correct behaviour
or the line should be diagonal instead of horizontal )
image

However, you need to manually declare ports ( i.e using the port option after every attribute ), and
tailport is the first element of the relation and headport is the second; in ERD the tail is the first one and the head is the second one.

To implement ports I have added a new Option constructor:

data Option = ...
+ | Port PortKind C.PortPos
            deriving (Show, Eq)
+  -- | Declaration of possible ports so as
+  -- to only add one extra constructor to Option
+  data PortKind = Tail | Head | Declaration deriving (Eq,Show)

I don't know whether adding one more constructor to Option is the right choice, or there is another way without touching Option.

Brilliant!
@bollafa , I have a solution that automatically matches the ports without having to do explicit declaration, but the solution is not complete... yet, and it required a fair amount of refactoring of the current code.

Also, doing the matching between ports and relevant fields is actually possible to be performed without explicit declaration. So, this would be a more involved work, but eventually worth it.

Give me a bit of time to review what is all that we have on this ready and not-ready.

  • Approach-1
    There the idea is to identify ports based on their naming, for example:
    Field birth_place_id to be port-ed to the field id in the related table, when it exists in the given table. This is a rule based implicit approach, that is, foreign key identifiers would need to be called explicitly with with a pre-defined ending: _id.
    One could have a look at the incomplete solution in the branch port-edge in this repository.

  • Approach-2
    As @bollafa illustrated: being explicit where each port would be directed. This approach makes the erd-configuration file explicit in its syntax, hence it comes with extending the existing symbols.

I think each of these solutions could exists simultaneously, next to each other, independently. In case of Approach-2 having the port defined shall be optional in its syntax. So, backward compatibility would be preserved.

As for Approach-1, when no field is called with the post-fix pattern _id the porting applies as default, that is porting is not applicable. The pattern could be something else, that may be up to discussion.

Could you please further explain approach-1 post-fix pattern? The way I understand it:

[`Birth Place`]
*id
`birth city`
'birth state'
"birth country"

otherEntity -- birth_place_id

otherEntity -- birth_place_birth_country

In this case there would be a relation from table otherEntity ( omitted for simplicity ) to attribute id in table birth_place. And another relation from otherEntity to attribute "birth country" in table birth_place. Is this correct?

If I got your last paragraph correctly, not declaring ports that are not used seems like a great idea! That way the tests will still pass without any changes because as they do not use ports, no port declaration will appear on the resulting dot file, so there won't be any difference.

I agree on both solutions being able to exist at the same time, and I would also like to propose the original dot syntax for ports as the post-fix pattern: (as in the original issue by @windbender )

users:id 1--* cats: owner_id <----- THIS HERE IS WHAT IS DIFFERENT

Of course, I do not know how difficult it would be to add this to the Erd parser, hence if it is indeed difficult the _id post-fix pattern seems an easier solution.

@windbender you can have a try DrawERD
image

@mmzx That sounds awesome!

I'm wondering if it would be possible to piece-meal them however for the sake of getting it deployed into the tool faster; First doing the explicit approach that @bollafa describes (since it sounds like it required less code refactoring) and then adding the implicit stuff you're doing.