inukshuk / sqleton

Visualize your SQLite database schema
GNU General Public License v3.0
110 stars 12 forks source link

Add PlantUML support #15

Open Davoodeh opened 2 years ago

Davoodeh commented 2 years ago

Thanks for the fantastic tool. I would appreciate something more human readable like PlantUML.

I wrote this little script that might help with the idea. It's a hacky script and not in JS so yeah... IDK if it is any good or useful for the dev team (in case considering the idea), but I leave it here just in case somebody wants to use it.

#!/bin/sh
# Convert a SQL database to Plantuml
# $1: Database file
# $2: (Optional) Output name (exluding the extension)
# TODO convert sql to plantuml

out="${2:-$1}.plantuml"

sqleton "$1" -o "$1.plain" || exit 1
[ -f "$out" ] && echo "File '$out' already exists" && exit 1

head "$1.plain" -n-1 | tail -n+2 | awk '
BEGIN {
    INDENT = "    ";
    print "@startuml ERD\n";
}

{
    if ($1 == "node") {
        print "entity " $2 " {";
        split($0, row, "|");
        rows = split(row[2], data, ">");

        # data[1] => table tag
        # loop:
        # data[2..3] => tr and td tags
        # data[4] => field name + font tag
        # data[5] => bold tag
        # data[6] => type + bold closing
        # data[7] => font closing
        # data[8..9] => tr and td tags closing

        if (rows >= 4 + 7) process(data[4], data[6]);
        for (i=12; i <= rows - 7; i = i + 8) process(data[i], data[i + 2]);
        print "}\n";
    } else if ($1 == "edge") {
        print $2 " --> " $3;
    }
}
END {
    print "\n@enduml";
}

function remove_tags(s){
    sub(/ ?<.*/, "", s);
    sub(/^ ?/, "", s);
    return s;
}
function process(field, type) {
    field = remove_tags(field);
    type = remove_tags(type);
    printf INDENT;
    # Move the star of pks to the back
    match(field, "*");
    if (RLENGTH != -1) field = "* " substr(field, 0, length(field) - RLENGTH);
    printf field " : " type;
    if (RLENGTH != -1) printf "\n" INDENT "--";
    print "";
}
' >"$out"
rm "$1.plain"

This does the conversion below which can be rendered to something like that picture:

graph 1 10.972 11.694
node django_migrations 6.8228 7.9533 2.0833 1.4583 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>django_migrations</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">app <font ><b>varchar(255)</b></font></td></tr><tr><td align="left">name <font ><b>varchar(255)</b></font></td></tr><tr><td align="left">applied <font ><b>datetime</b></font></td></tr></table>> solid Mrecord black lightgrey
node auth_group_permissions 1.3378 3.3616 2.6667 1.2222 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>auth_group_permissions</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">group_id <font ><b>integer</b></font></td></tr><tr><td align="left">permission_id <font ><b>integer</b></font></td></tr></table>> solid Mrecord black lightgrey
node auth_user_groups 8.49 0.86986 2 1.2222 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>auth_user_groups</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">user_id <font ><b>integer</b></font></td></tr><tr><td align="left">group_id <font ><b>integer</b></font></td></tr></table>> solid Mrecord black lightgrey
node auth_user_user_permissions 5.4561 5.548 3.0556 1.2222 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>auth_user_user_permissions</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">user_id <font ><b>integer</b></font></td></tr><tr><td align="left">permission_id <font ><b>integer</b></font></td></tr></table>> solid Mrecord black lightgrey
node django_admin_log 9.5613 9.7449 2.8333 2.4028 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>django_admin_log</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">action_time <font ><b>datetime</b></font></td></tr><tr><td align="left">object_id <font ><b>text</b></font></td></tr><tr><td align="left">object_repr <font ><b>varchar(200)</b></font></td></tr><tr><td align="left">change_message <font ><b>text</b></font></td></tr><tr><td align="left">content_type_id <font ><b>integer</b></font></td></tr><tr><td align="left">user_id <font ><b>integer</b></font></td></tr><tr><td align="left">action_flag <font ><b>smallint unsigned</b></font></td></tr></table>> solid Mrecord black lightgrey
node django_content_type 5.024 11.086 2.2917 1.2222 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>django_content_type</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">app_label <font ><b>varchar(100)</b></font></td></tr><tr><td align="left">model <font ><b>varchar(100)</b></font></td></tr></table>> solid Mrecord black lightgrey
node auth_permission 2.31 7.1659 2.3472 1.4583 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>auth_permission</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">content_type_id <font ><b>integer</b></font></td></tr><tr><td align="left">codename <font ><b>varchar(100)</b></font></td></tr><tr><td align="left">name <font ><b>varchar(255)</b></font></td></tr></table>> solid Mrecord black lightgrey
node auth_group 4.6199 0.49404 2 0.98611 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>auth_group</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">name <font ><b>varchar(150)</b></font></td></tr></table>> solid Mrecord black lightgrey
node auth_user 9.7531 5.6411 2.3472 3.1111 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>auth_user</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">id* <font ><b>integer</b></font></td></tr><tr><td align="left">password <font ><b>varchar(128)</b></font></td></tr><tr><td align="left">last_login <font ><b>datetime</b></font></td></tr><tr><td align="left">is_superuser <font ><b>bool</b></font></td></tr><tr><td align="left">username <font ><b>varchar(150)</b></font></td></tr><tr><td align="left">last_name <font ><b>varchar(150)</b></font></td></tr><tr><td align="left">email <font ><b>varchar(254)</b></font></td></tr><tr><td align="left">is_staff <font ><b>bool</b></font></td></tr><tr><td align="left">is_active <font ><b>bool</b></font></td></tr><tr><td align="left">date_joined <font ><b>datetime</b></font></td></tr><tr><td align="left">first_name <font ><b>varchar(150)</b></font></td></tr></table>> solid Mrecord black lightgrey
node django_session 4.8228 3.495 2.4167 1.2222 <<table border="0" cellspacing="0.5"><tr><td align="left" height="24" valign="bottom"><font point-size="13"><b>django_session</b></font></td></tr></table>|<table border="0" cellspacing="0.5" width="134"><tr><td align="left">session_key* <font ><b>varchar(40)</b></font></td></tr><tr><td align="left">session_data <font ><b>text</b></font></td></tr><tr><td align="left">expire_date <font ><b>datetime</b></font></td></tr></table>> solid Mrecord black lightgrey
edge auth_group_permissions auth_permission 4 1.4929 3.9686 1.6558 4.6058 1.913 5.6123 2.0953 6.3256 solid black
edge auth_group_permissions auth_group 4 2.0299 2.7569 2.6029 2.2563 3.4112 1.5501 3.9717 1.0603 solid black
edge auth_user_groups auth_group 4 7.4883 0.77259 6.953 0.72061 6.2925 0.65646 5.7402 0.60283 solid black
edge auth_user_groups auth_user 4 8.65 1.4741 8.8161 2.1018 9.0835 3.1116 9.3133 3.9799 solid black
edge auth_user_user_permissions auth_permission 4 4.2801 6.1527 4.0546 6.2687 3.8175 6.3907 3.5889 6.5082 solid black
edge auth_user_user_permissions auth_user 4 6.9892 5.5812 7.4714 5.5916 7.9987 5.6031 8.4623 5.6131 solid black
edge django_admin_log django_content_type 4 8.1443 10.164 7.547 10.34 6.8576 10.544 6.279 10.715 solid black
edge django_admin_log auth_user 4 9.6173 8.5469 9.6354 8.1581 9.6559 7.7196 9.6754 7.3033 solid black
edge auth_permission django_content_type 4 2.8109 7.8895 3.3035 8.6009 4.0503 9.6796 4.5377 10.384 solid black
stop
@startuml ERD

entity django_migrations {
    * id : integer
    --
    app : varchar(255)
    name : varchar(255)
    applied : datetime
}

entity auth_group_permissions {
    * id : integer
    --
    group_id : integer
    permission_id : integer
}

entity auth_user_groups {
    * id : integer
    --
    user_id : integer
    group_id : integer
}

entity auth_user_user_permissions {
    * id : integer
    --
    user_id : integer
    permission_id : integer
}

entity django_admin_log {
    * id : integer
    --
    action_time : datetime
    object_id : text
    object_repr : varchar(200)
    change_message : text
    content_type_id : integer
    user_id : integer
    action_flag : smallint unsigned
}

entity django_content_type {
    * id : integer
    --
    app_label : varchar(100)
    model : varchar(100)
}

entity auth_permission {
    * id : integer
    --
    content_type_id : integer
    codename : varchar(100)
    name : varchar(255)
}

entity auth_group {
    * id : integer
    --
    name : varchar(150)
}

entity auth_user {
    * id : integer
    --
    password : varchar(128)
    last_login : datetime
    is_superuser : bool
    username : varchar(150)
    last_name : varchar(150)
    email : varchar(254)
    is_staff : bool
    is_active : bool
    date_joined : datetime
    first_name : varchar(150)
}

entity django_session {
    * session_key : varchar(40)
    --
    session_data : text
    expire_date : datetime
}

auth_group_permissions --> auth_permission
auth_group_permissions --> auth_group
auth_user_groups --> auth_group
auth_user_groups --> auth_user
auth_user_user_permissions --> auth_permission
auth_user_user_permissions --> auth_user
django_admin_log --> django_content_type
django_admin_log --> auth_user
auth_permission --> django_content_type

@enduml

image

inukshuk commented 2 years ago

Cool, thanks for sharing!

Asncodes-80 commented 2 years ago

That's great for all. It's high-effort, powerful and simple for user and even developer! Thanks for sharing.