Skip to content

Commit 0ea6d2b

Browse files
committed
Initial and probably final commit.
1 parent 1e4f688 commit 0ea6d2b

File tree

4 files changed

+232
-1
lines changed

4 files changed

+232
-1
lines changed

LICENSE

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This code is public domain. You can copy, modify, distribute and perform the work,
2+
even for commercial purposes, all without asking permission.

README.md

+97-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,98 @@
11
# plantuml2mysql
2-
Simple generator of SQL DDL for MySQL dialect from PlantUML class diagram
2+
3+
I liked `plantuml` tool for UML diagrams but use it
4+
also for visualizing structure of relational database.
5+
This script loads plantuml class diagram and generates
6+
DDL for MySQL SQL dialect. You may define primary keys
7+
with `#` prefix in field name (it mean protected field
8+
in PlantUML) and define index fields with `+` prefix.
9+
10+
Field type noted after field name as is. Also you may
11+
use comments after `--`.
12+
13+
For example class definition:
14+
15+
@startuml
16+
17+
class dummy {
18+
Sample table.
19+
==
20+
#id int(10)
21+
field1 int(10)
22+
field2 varchar(128)
23+
}
24+
25+
@enduml
26+
27+
will be converted to SQL:
28+
29+
CREATE TABLE IF NOT EXISTS Dummy (
30+
id INT(10),
31+
field1 INT(10),
32+
field2 VARCHAR(128),
33+
PRIMARY KEY (id));
34+
35+
Text between class name and `==` is table description.
36+
The description of the table is mandatory.
37+
I was too lazy to check for absence of descriptions but
38+
I not lazy to write them in each table of my databases.
39+
40+
See below result of more complicated sample from [database.plu](database.plu):
41+
42+
[database.png](database.png)
43+
44+
```./plantuml2mysql.py database.plu sampledb```
45+
46+
```sql
47+
CREATE DATABASE sampledb CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;
48+
USE sampledb;
49+
50+
CREATE TABLE IF NOT EXISTS user (
51+
id SERIAL,
52+
login VARCHAR(16),
53+
mail VARCHAR(64),
54+
docsRef INT(10) COMMENT 'referenced docs for a user',
55+
created INT(11),
56+
sesid INT(11),
57+
PRIMARY KEY (id),
58+
INDEX (login),
59+
INDEX (mail)
60+
);
61+
62+
CREATE TABLE IF NOT EXISTS session (
63+
id SERIAL,
64+
uid INT(10) UNSIGNED,
65+
remoteip INT(10) UNSIGNED,
66+
useragent VARCHAR(255),
67+
data LONGTEXT COMMENT 'serialized session data',
68+
lastseen INT(11),
69+
PRIMARY KEY (id),
70+
INDEX (uid),
71+
INDEX (lastseen)
72+
);
73+
74+
CREATE TABLE IF NOT EXISTS docs (
75+
id INT(10),
76+
fid INT(10) COMMENT 'link to a file',
77+
aunthorid INT(10),
78+
created INT(11),
79+
PRIMARY KEY (id, fid),
80+
INDEX (aunthorid),
81+
INDEX (created)
82+
);
83+
84+
CREATE TABLE IF NOT EXISTS files (
85+
id SERIAL,
86+
docId INT(10),
87+
title VARCHAR(255),
88+
path VARCHAR(255),
89+
hash INT(32) UNSIGNED,
90+
PRIMARY KEY (id),
91+
INDEX (docId)
92+
);
93+
```
94+
95+
I just not need yet more features and satisfied with this code as is
96+
but I'll merge your patches if you create something completely different.
97+
98+

database.plu

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
UML legend:
2+
3+
table = class
4+
#pkey
5+
+index
6+
7+
@startuml
8+
class user <<(U,olive)>> {
9+
Users table example.
10+
==
11+
#id
12+
+login : varchar(16)
13+
+mail : varchar(64)
14+
docsRef : int(10) -- referenced docs for a user
15+
created : int(11)
16+
sesid : int(11)
17+
}
18+
19+
user "1" -- "0..*" docs
20+
21+
class session <<(U,olive)>> {
22+
Sessions table example.
23+
==
24+
#id
25+
+uid : int(10) unsigned
26+
remoteip : int(10) unsigned
27+
useragent : varchar(255)
28+
data : longtext -- serialized session data
29+
+lastseen : int(11)
30+
}
31+
32+
session "0..*" -- "1" user
33+
34+
class docs <<(F,brown)>> {
35+
Documents storage example.
36+
==
37+
#id : int(10)
38+
#fid : int(10) -- link to a file
39+
+aunthorid : int(10)
40+
+created : int(11)
41+
}
42+
43+
class files <<(F,brown)>> {
44+
File storage example.
45+
==
46+
#id
47+
+docId : int(10)
48+
title : varchar(255)
49+
path : varchar(255)
50+
hash : int(32) unsigned
51+
}
52+
53+
files "1" -- "1..*" docs
54+
55+
@enduml

plantuml2mysql.py

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/env python3
2+
#-*-coding:utf-8-*-
3+
# Usage: ./plantuml2mysql <dbsource.plu> <dbname>
4+
# Author: Alexander I.Grafov <[email protected]>
5+
# The code is public domain.
6+
7+
CHARSET="utf8_unicode_ci"
8+
9+
import sys
10+
11+
def main():
12+
print("CREATE DATABASE %s CHARACTER SET = utf8 COLLATE = %s;" % (sys.argv[2], CHARSET))
13+
print("USE %s;\n" % sys.argv[2])
14+
uml = False; table = False; field = False
15+
pk = False; idx = False
16+
primary = []; index = ""
17+
with open(sys.argv[1]) as src:
18+
data = src.readlines()
19+
for l in data:
20+
l = l.strip()
21+
if not l:
22+
continue
23+
if l == "@startuml":
24+
uml = True
25+
continue
26+
if not uml:
27+
continue
28+
if l == "--":
29+
continue
30+
comment = ""
31+
i = l.split()
32+
fname = i[0]
33+
if field and ("--" in l):
34+
i, comment = l.split("--", 2)
35+
i = i.split()
36+
pk = False; idx = False
37+
if fname[0] in ("+", "#"):
38+
if fname[0] == "#":
39+
pk = True
40+
else:
41+
idx = True
42+
fname = fname[1:]
43+
if l == "@enduml":
44+
uml = False
45+
continue
46+
if not uml:
47+
continue
48+
if l.startswith("class"):
49+
table = True; field = False
50+
primary = []; index = ""
51+
print("CREATE TABLE IF NOT EXISTS", i[1], "(")
52+
continue
53+
if table and not field and l == "==":
54+
field = True
55+
continue
56+
if field and l == "}":
57+
table = False; field = False
58+
print(" PRIMARY KEY (%s)" % ", ".join(primary), end="")
59+
if index:
60+
print(",\n%s" % index[:-2],)
61+
index = ""
62+
print(");\n")
63+
continue
64+
if field and l == "#id":
65+
print(" %-16s SERIAL," % "id")
66+
if field and l != "#id":
67+
print(" %-16s %s" % (fname, " ".join(i[2:]).upper()), end="")
68+
if comment:
69+
print(" COMMENT '%s'" % comment.strip(), end="")
70+
print(",")
71+
if field and pk:
72+
primary.append(fname)
73+
if field and idx:
74+
index += " INDEX (%s),\n" % fname
75+
76+
77+
if __name__ == "__main__":
78+
main()

0 commit comments

Comments
 (0)