ZahirJS commited on
Commit
cf262b9
·
verified ·
1 Parent(s): c5a9b0f

Update entity_relationship_generator.py

Browse files
Files changed (1) hide show
  1. entity_relationship_generator.py +297 -694
entity_relationship_generator.py CHANGED
@@ -1,650 +1,3 @@
1
- # import graphviz
2
- # import json
3
- # from tempfile import NamedTemporaryFile
4
- # import os
5
-
6
- # def generate_entity_relationship_diagram(json_input: str, output_format: str) -> str:
7
- # """
8
- # Generates an Entity Relationship (ER) diagram from JSON input.
9
-
10
- # Args:
11
- # json_input (str): A JSON string describing the ER diagram structure.
12
- # It must follow the Expected JSON Format Example below.
13
-
14
- # Expected JSON Format Example:
15
- # {
16
- # "entities": [
17
- # {
18
- # "name": "User",
19
- # "type": "strong",
20
- # "attributes": [
21
- # {
22
- # "name": "user_id",
23
- # "type": "primary_key"
24
- # },
25
- # {
26
- # "name": "username",
27
- # "type": "regular"
28
- # },
29
- # {
30
- # "name": "email",
31
- # "type": "regular"
32
- # },
33
- # {
34
- # "name": "password_hash",
35
- # "type": "regular"
36
- # },
37
- # {
38
- # "name": "full_name",
39
- # "type": "composite"
40
- # },
41
- # {
42
- # "name": "phone_numbers",
43
- # "type": "multivalued"
44
- # },
45
- # {
46
- # "name": "age",
47
- # "type": "derived"
48
- # }
49
- # ]
50
- # },
51
- # {
52
- # "name": "Product",
53
- # "type": "strong",
54
- # "attributes": [
55
- # {
56
- # "name": "product_id",
57
- # "type": "primary_key"
58
- # },
59
- # {
60
- # "name": "name",
61
- # "type": "regular"
62
- # },
63
- # {
64
- # "name": "description",
65
- # "type": "regular"
66
- # },
67
- # {
68
- # "name": "price",
69
- # "type": "regular"
70
- # },
71
- # {
72
- # "name": "stock_quantity",
73
- # "type": "regular"
74
- # },
75
- # {
76
- # "name": "tags",
77
- # "type": "multivalued"
78
- # }
79
- # ]
80
- # },
81
- # {
82
- # "name": "Category",
83
- # "type": "strong",
84
- # "attributes": [
85
- # {
86
- # "name": "category_id",
87
- # "type": "primary_key"
88
- # },
89
- # {
90
- # "name": "name",
91
- # "type": "regular"
92
- # },
93
- # {
94
- # "name": "description",
95
- # "type": "regular"
96
- # }
97
- # ]
98
- # },
99
- # {
100
- # "name": "Order",
101
- # "type": "strong",
102
- # "attributes": [
103
- # {
104
- # "name": "order_id",
105
- # "type": "primary_key"
106
- # },
107
- # {
108
- # "name": "order_date",
109
- # "type": "regular"
110
- # },
111
- # {
112
- # "name": "status",
113
- # "type": "regular"
114
- # },
115
- # {
116
- # "name": "total_amount",
117
- # "type": "derived"
118
- # },
119
- # {
120
- # "name": "shipping_address",
121
- # "type": "composite"
122
- # }
123
- # ]
124
- # },
125
- # {
126
- # "name": "OrderItem",
127
- # "type": "weak",
128
- # "attributes": [
129
- # {
130
- # "name": "line_number",
131
- # "type": "partial_key"
132
- # },
133
- # {
134
- # "name": "quantity",
135
- # "type": "regular"
136
- # },
137
- # {
138
- # "name": "unit_price",
139
- # "type": "regular"
140
- # },
141
- # {
142
- # "name": "subtotal",
143
- # "type": "derived"
144
- # }
145
- # ]
146
- # },
147
- # {
148
- # "name": "Payment",
149
- # "type": "strong",
150
- # "attributes": [
151
- # {
152
- # "name": "payment_id",
153
- # "type": "primary_key"
154
- # },
155
- # {
156
- # "name": "amount",
157
- # "type": "regular"
158
- # },
159
- # {
160
- # "name": "payment_method",
161
- # "type": "regular"
162
- # },
163
- # {
164
- # "name": "payment_date",
165
- # "type": "regular"
166
- # },
167
- # {
168
- # "name": "status",
169
- # "type": "regular"
170
- # }
171
- # ]
172
- # },
173
- # {
174
- # "name": "Review",
175
- # "type": "strong",
176
- # "attributes": [
177
- # {
178
- # "name": "review_id",
179
- # "type": "primary_key"
180
- # },
181
- # {
182
- # "name": "rating",
183
- # "type": "regular"
184
- # },
185
- # {
186
- # "name": "comment",
187
- # "type": "regular"
188
- # },
189
- # {
190
- # "name": "review_date",
191
- # "type": "regular"
192
- # }
193
- # ]
194
- # },
195
- # {
196
- # "name": "Vendor",
197
- # "type": "strong",
198
- # "attributes": [
199
- # {
200
- # "name": "vendor_id",
201
- # "type": "primary_key"
202
- # },
203
- # {
204
- # "name": "company_name",
205
- # "type": "regular"
206
- # },
207
- # {
208
- # "name": "contact_person",
209
- # "type": "regular"
210
- # },
211
- # {
212
- # "name": "contact_emails",
213
- # "type": "multivalued"
214
- # },
215
- # {
216
- # "name": "business_address",
217
- # "type": "composite"
218
- # }
219
- # ]
220
- # },
221
- # {
222
- # "name": "ShoppingCart",
223
- # "type": "strong",
224
- # "attributes": [
225
- # {
226
- # "name": "cart_id",
227
- # "type": "primary_key"
228
- # },
229
- # {
230
- # "name": "created_date",
231
- # "type": "regular"
232
- # },
233
- # {
234
- # "name": "last_updated",
235
- # "type": "regular"
236
- # },
237
- # {
238
- # "name": "total_items",
239
- # "type": "derived"
240
- # }
241
- # ]
242
- # },
243
- # {
244
- # "name": "CartItem",
245
- # "type": "weak",
246
- # "attributes": [
247
- # {
248
- # "name": "item_position",
249
- # "type": "partial_key"
250
- # },
251
- # {
252
- # "name": "quantity",
253
- # "type": "regular"
254
- # },
255
- # {
256
- # "name": "added_date",
257
- # "type": "regular"
258
- # }
259
- # ]
260
- # }
261
- # ],
262
- # "relationships": [
263
- # {
264
- # "name": "PlacesOrder",
265
- # "type": "regular",
266
- # "entities": ["User", "Order"],
267
- # "cardinalities": {
268
- # "User": "1",
269
- # "Order": "M"
270
- # },
271
- # "attributes": []
272
- # },
273
- # {
274
- # "name": "Contains",
275
- # "type": "identifying",
276
- # "entities": ["Order", "OrderItem"],
277
- # "cardinalities": {
278
- # "Order": "1",
279
- # "OrderItem": "M"
280
- # },
281
- # "attributes": []
282
- # },
283
- # {
284
- # "name": "OrdersProduct",
285
- # "type": "regular",
286
- # "entities": ["OrderItem", "Product"],
287
- # "cardinalities": {
288
- # "OrderItem": "M",
289
- # "Product": "1"
290
- # },
291
- # "attributes": []
292
- # },
293
- # {
294
- # "name": "BelongsTo",
295
- # "type": "regular",
296
- # "entities": ["Product", "Category"],
297
- # "cardinalities": {
298
- # "Product": "M",
299
- # "Category": "1"
300
- # },
301
- # "attributes": []
302
- # },
303
- # {
304
- # "name": "ProcessesPayment",
305
- # "type": "regular",
306
- # "entities": ["Order", "Payment"],
307
- # "cardinalities": {
308
- # "Order": "1",
309
- # "Payment": "M"
310
- # },
311
- # "attributes": []
312
- # },
313
- # {
314
- # "name": "WritesReview",
315
- # "type": "regular",
316
- # "entities": ["User", "Review"],
317
- # "cardinalities": {
318
- # "User": "1",
319
- # "Review": "M"
320
- # },
321
- # "attributes": []
322
- # },
323
- # {
324
- # "name": "ReviewsProduct",
325
- # "type": "regular",
326
- # "entities": ["Review", "Product"],
327
- # "cardinalities": {
328
- # "Review": "M",
329
- # "Product": "1"
330
- # },
331
- # "attributes": []
332
- # },
333
- # {
334
- # "name": "Supplies",
335
- # "type": "regular",
336
- # "entities": ["Vendor", "Product"],
337
- # "cardinalities": {
338
- # "Vendor": "M",
339
- # "Product": "M"
340
- # },
341
- # "attributes": [
342
- # {
343
- # "name": "supply_price"
344
- # },
345
- # {
346
- # "name": "lead_time"
347
- # }
348
- # ]
349
- # },
350
- # {
351
- # "name": "HasCart",
352
- # "type": "regular",
353
- # "entities": ["User", "ShoppingCart"],
354
- # "cardinalities": {
355
- # "User": "1",
356
- # "ShoppingCart": "1"
357
- # },
358
- # "attributes": []
359
- # },
360
- # {
361
- # "name": "CartContains",
362
- # "type": "identifying",
363
- # "entities": ["ShoppingCart", "CartItem"],
364
- # "cardinalities": {
365
- # "ShoppingCart": "1",
366
- # "CartItem": "M"
367
- # },
368
- # "attributes": []
369
- # },
370
- # {
371
- # "name": "CartHasProduct",
372
- # "type": "regular",
373
- # "entities": ["CartItem", "Product"],
374
- # "cardinalities": {
375
- # "CartItem": "M",
376
- # "Product": "1"
377
- # },
378
- # "attributes": []
379
- # }
380
- # ]
381
- # }
382
-
383
- # Returns:
384
- # str: The filepath to the generated PNG image file.
385
- # """
386
- # try:
387
- # if not json_input.strip():
388
- # return "Error: Empty input"
389
-
390
- # data = json.loads(json_input)
391
-
392
- # if 'entities' not in data:
393
- # raise ValueError("Missing required field: entities")
394
-
395
- # dot = graphviz.Graph(comment='ER Diagram', engine='neato')
396
- # dot.attr(
397
- # bgcolor='white',
398
- # pad='1.5',
399
- # overlap='false',
400
- # splines='true',
401
- # sep='+25',
402
- # esep='+15'
403
- # )
404
- # dot.attr('node', fontname='Arial', fontsize='10', color='#404040')
405
- # dot.attr('edge', fontname='Arial', fontsize='9', color='#4a4a4a')
406
-
407
- # entity_color = '#BEBEBE'
408
- # attribute_color = '#D4D4D4'
409
- # relationship_color = '#E8E8E8'
410
- # isa_color = '#F0F0F0'
411
-
412
- # font_color = 'black'
413
-
414
- # entities = data.get('entities', [])
415
- # relationships = data.get('relationships', [])
416
-
417
- # # Process entities with new styling
418
- # for entity in entities:
419
- # entity_name = entity.get('name')
420
- # entity_type = entity.get('type', 'strong')
421
- # attributes = entity.get('attributes', [])
422
-
423
- # if not entity_name:
424
- # continue
425
-
426
- # if entity_type == 'weak':
427
- # dot.node(
428
- # entity_name,
429
- # entity_name,
430
- # shape='box',
431
- # style='filled,rounded',
432
- # fillcolor=entity_color,
433
- # fontcolor=font_color,
434
- # color='#404040',
435
- # penwidth='3',
436
- # width='1.8',
437
- # height='0.8',
438
- # fontsize='12'
439
- # )
440
- # else:
441
- # dot.node(
442
- # entity_name,
443
- # entity_name,
444
- # shape='box',
445
- # style='filled,rounded',
446
- # fillcolor=entity_color,
447
- # fontcolor=font_color,
448
- # color='#404040',
449
- # penwidth='1',
450
- # width='1.8',
451
- # height='0.8',
452
- # fontsize='12'
453
- # )
454
-
455
- # for i, attr in enumerate(attributes):
456
- # attr_name = attr.get('name', '')
457
- # attr_type = attr.get('type', 'regular')
458
-
459
- # attr_id = f"{entity_name}_attr_{i}"
460
-
461
- # if attr_type == 'primary_key':
462
- # dot.node(
463
- # attr_id,
464
- # f'{attr_name} (PK)',
465
- # shape='ellipse',
466
- # style='filled,rounded',
467
- # fillcolor=attribute_color,
468
- # fontcolor=font_color,
469
- # color='#404040',
470
- # width='1.2',
471
- # height='0.6',
472
- # fontsize='10'
473
- # )
474
- # elif attr_type == 'partial_key':
475
- # dot.node(
476
- # attr_id,
477
- # f'{attr_name} (Partial)',
478
- # shape='ellipse',
479
- # style='filled,rounded,dashed',
480
- # fillcolor=attribute_color,
481
- # fontcolor=font_color,
482
- # color='#404040',
483
- # width='1.2',
484
- # height='0.6',
485
- # fontsize='10'
486
- # )
487
- # elif attr_type == 'multivalued':
488
- # dot.node(
489
- # attr_id,
490
- # attr_name,
491
- # shape='ellipse',
492
- # style='filled,rounded',
493
- # fillcolor=attribute_color,
494
- # fontcolor=font_color,
495
- # color='#404040',
496
- # penwidth='3',
497
- # width='1.2',
498
- # height='0.6',
499
- # fontsize='10'
500
- # )
501
- # elif attr_type == 'derived':
502
- # dot.node(
503
- # attr_id,
504
- # f'/{attr_name}/',
505
- # shape='ellipse',
506
- # style='filled,rounded,dashed',
507
- # fillcolor=attribute_color,
508
- # fontcolor=font_color,
509
- # color='#404040',
510
- # width='1.2',
511
- # height='0.6',
512
- # fontsize='10'
513
- # )
514
- # elif attr_type == 'composite':
515
- # dot.node(
516
- # attr_id,
517
- # attr_name,
518
- # shape='ellipse',
519
- # style='filled,rounded',
520
- # fillcolor=attribute_color,
521
- # fontcolor=font_color,
522
- # color='#404040',
523
- # width='1.2',
524
- # height='0.6',
525
- # fontsize='10'
526
- # )
527
- # else:
528
- # dot.node(
529
- # attr_id,
530
- # attr_name,
531
- # shape='ellipse',
532
- # style='filled,rounded',
533
- # fillcolor=attribute_color,
534
- # fontcolor=font_color,
535
- # color='#404040',
536
- # width='1.2',
537
- # height='0.6',
538
- # fontsize='10'
539
- # )
540
-
541
- # dot.edge(entity_name, attr_id, color='#4a4a4a', len='1.5')
542
-
543
- # for relationship in relationships:
544
- # rel_name = relationship.get('name')
545
- # rel_type = relationship.get('type', 'regular')
546
- # entities_involved = relationship.get('entities', [])
547
- # cardinalities = relationship.get('cardinalities', {})
548
- # rel_attributes = relationship.get('attributes', [])
549
-
550
- # if not rel_name:
551
- # continue
552
-
553
- # if rel_type == 'isa':
554
- # parent = relationship.get('parent')
555
- # children = relationship.get('children', [])
556
-
557
- # if parent and children:
558
- # isa_id = f"isa_{rel_name}"
559
-
560
- # dot.node(
561
- # isa_id,
562
- # 'ISA',
563
- # shape='triangle',
564
- # style='filled,rounded',
565
- # fillcolor=isa_color,
566
- # fontcolor=font_color,
567
- # color='#404040',
568
- # penwidth='2',
569
- # width='1.0',
570
- # height='0.8',
571
- # fontsize='10'
572
- # )
573
-
574
- # dot.edge(parent, isa_id, color='#4a4a4a', len='2.0')
575
-
576
- # for child in children:
577
- # dot.edge(isa_id, child, color='#4a4a4a', len='2.0')
578
-
579
- # elif len(entities_involved) >= 2:
580
- # if rel_type == 'identifying':
581
- # dot.node(
582
- # rel_name,
583
- # rel_name,
584
- # shape='diamond',
585
- # style='filled,rounded',
586
- # fillcolor=relationship_color,
587
- # fontcolor=font_color,
588
- # color='#404040',
589
- # penwidth='3',
590
- # width='1.8',
591
- # height='1.0',
592
- # fontsize='11'
593
- # )
594
- # else:
595
- # dot.node(
596
- # rel_name,
597
- # rel_name,
598
- # shape='diamond',
599
- # style='filled,rounded',
600
- # fillcolor=relationship_color,
601
- # fontcolor=font_color,
602
- # color='#404040',
603
- # penwidth='1',
604
- # width='1.8',
605
- # height='1.0',
606
- # fontsize='11'
607
- # )
608
-
609
- # for j, attr in enumerate(rel_attributes):
610
- # attr_name = attr.get('name', '')
611
- # attr_id = f"{rel_name}_attr_{j}"
612
-
613
- # dot.node(
614
- # attr_id,
615
- # attr_name,
616
- # shape='ellipse',
617
- # style='filled,rounded',
618
- # fillcolor=attribute_color,
619
- # fontcolor=font_color,
620
- # color='#404040',
621
- # width='1.0',
622
- # height='0.5',
623
- # fontsize='9'
624
- # )
625
- # dot.edge(rel_name, attr_id, color='#4a4a4a', len='1.0')
626
-
627
- # for entity in entities_involved:
628
- # cardinality = cardinalities.get(entity, '1')
629
- # dot.edge(
630
- # entity,
631
- # rel_name,
632
- # label=f' {cardinality} ',
633
- # color='#4a4a4a',
634
- # len='2.5',
635
- # fontcolor='#4a4a4a',
636
- # fontsize='10'
637
- # )
638
-
639
- # with NamedTemporaryFile(delete=False, suffix=f'.{output_format}') as tmp:
640
- # dot.render(tmp.name, format=output_format, cleanup=True)
641
- # return f"{tmp.name}.{output_format}"
642
-
643
- # except json.JSONDecodeError:
644
- # return "Error: Invalid JSON format"
645
- # except Exception as e:
646
- # return f"Error: {str(e)}"
647
-
648
  import graphviz
649
  import json
650
  from tempfile import NamedTemporaryFile
@@ -662,156 +15,406 @@ def generate_entity_relationship_diagram(json_input: str, output_format: str) ->
662
  {
663
  "entities": [
664
  {
665
- "name": "User",
666
  "type": "strong",
667
  "attributes": [
668
  {
669
- "name": "user_id",
670
  "type": "primary_key"
671
  },
672
  {
673
- "name": "username",
674
  "type": "regular"
675
  },
676
  {
677
- "name": "email",
678
  "type": "regular"
679
  },
680
  {
681
- "name": "password_hash",
682
  "type": "regular"
683
  },
684
  {
685
- "name": "full_name",
686
- "type": "composite"
687
  },
688
  {
689
  "name": "phone_numbers",
690
  "type": "multivalued"
691
  },
692
  {
693
- "name": "age",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
694
  "type": "derived"
695
  }
696
  ]
697
  },
698
  {
699
- "name": "Product",
700
  "type": "strong",
701
  "attributes": [
702
  {
703
- "name": "product_id",
704
- "type": "primary_key"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
  },
706
  {
707
- "name": "name",
708
  "type": "regular"
709
  },
710
  {
711
- "name": "description",
712
  "type": "regular"
713
  },
714
  {
715
- "name": "price",
 
 
 
 
 
 
 
 
 
 
716
  "type": "regular"
717
  },
718
  {
719
- "name": "stock_quantity",
720
  "type": "regular"
721
  },
722
  {
723
- "name": "tags",
724
  "type": "multivalued"
725
  }
726
  ]
727
  },
728
  {
729
- "name": "Category",
730
  "type": "strong",
731
  "attributes": [
732
  {
733
- "name": "category_id",
734
- "type": "primary_key"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
735
  },
736
  {
737
- "name": "name",
738
  "type": "regular"
739
  },
740
  {
741
- "name": "description",
 
 
 
 
 
 
 
 
 
 
742
  "type": "regular"
 
 
 
 
743
  }
744
  ]
745
  },
746
  {
747
- "name": "Order",
748
  "type": "strong",
749
  "attributes": [
750
  {
751
- "name": "order_id",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752
  "type": "primary_key"
753
  },
754
  {
755
- "name": "order_date",
756
  "type": "regular"
757
  },
758
  {
759
- "name": "status",
760
  "type": "regular"
761
  },
762
  {
763
- "name": "total_amount",
764
  "type": "derived"
 
 
 
 
 
 
 
 
 
 
765
  },
766
  {
767
- "name": "shipping_address",
768
- "type": "composite"
769
  }
770
  ]
771
  },
772
  {
773
- "name": "OrderItem",
774
- "type": "weak",
775
  "attributes": [
776
  {
777
- "name": "line_number",
778
- "type": "partial_key"
779
  },
780
  {
781
- "name": "quantity",
 
 
 
 
 
 
 
 
 
 
782
  "type": "regular"
783
  },
784
  {
785
- "name": "unit_price",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  "type": "regular"
787
  },
788
  {
789
- "name": "subtotal",
790
- "type": "derived"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
791
  }
792
  ]
793
  }
794
  ],
795
  "relationships": [
796
  {
797
- "name": "PlacesOrder",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
798
  "type": "regular",
799
- "entities": ["User", "Order"],
800
  "cardinalities": {
801
- "User": "1",
802
- "Order": "M"
803
  },
804
- "attributes": []
 
 
 
 
 
 
 
 
 
 
805
  },
806
  {
807
- "name": "Contains",
808
- "type": "identifying",
809
- "entities": ["Order", "OrderItem"],
810
  "cardinalities": {
811
- "Order": "1",
812
- "OrderItem": "M"
813
  },
814
- "attributes": []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815
  }
816
  ]
817
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import graphviz
2
  import json
3
  from tempfile import NamedTemporaryFile
 
15
  {
16
  "entities": [
17
  {
18
+ "name": "Person",
19
  "type": "strong",
20
  "attributes": [
21
  {
22
+ "name": "person_id",
23
  "type": "primary_key"
24
  },
25
  {
26
+ "name": "first_name",
27
  "type": "regular"
28
  },
29
  {
30
+ "name": "last_name",
31
  "type": "regular"
32
  },
33
  {
34
+ "name": "birth_date",
35
  "type": "regular"
36
  },
37
  {
38
+ "name": "age",
39
+ "type": "derived"
40
  },
41
  {
42
  "name": "phone_numbers",
43
  "type": "multivalued"
44
  },
45
  {
46
+ "name": "full_address",
47
+ "type": "composite"
48
+ }
49
+ ]
50
+ },
51
+ {
52
+ "name": "Student",
53
+ "type": "strong",
54
+ "attributes": [
55
+ {
56
+ "name": "student_number",
57
+ "type": "regular"
58
+ },
59
+ {
60
+ "name": "enrollment_date",
61
+ "type": "regular"
62
+ },
63
+ {
64
+ "name": "gpa",
65
  "type": "derived"
66
  }
67
  ]
68
  },
69
  {
70
+ "name": "UndergraduateStudent",
71
  "type": "strong",
72
  "attributes": [
73
  {
74
+ "name": "major",
75
+ "type": "regular"
76
+ },
77
+ {
78
+ "name": "expected_graduation",
79
+ "type": "regular"
80
+ },
81
+ {
82
+ "name": "credits_completed",
83
+ "type": "regular"
84
+ }
85
+ ]
86
+ },
87
+ {
88
+ "name": "GraduateStudent",
89
+ "type": "strong",
90
+ "attributes": [
91
+ {
92
+ "name": "thesis_topic",
93
+ "type": "regular"
94
+ },
95
+ {
96
+ "name": "advisor_id",
97
+ "type": "regular"
98
+ },
99
+ {
100
+ "name": "degree_type",
101
+ "type": "regular"
102
+ }
103
+ ]
104
+ },
105
+ {
106
+ "name": "Faculty",
107
+ "type": "strong",
108
+ "attributes": [
109
+ {
110
+ "name": "employee_number",
111
+ "type": "regular"
112
  },
113
  {
114
+ "name": "hire_date",
115
  "type": "regular"
116
  },
117
  {
118
+ "name": "office_number",
119
  "type": "regular"
120
  },
121
  {
122
+ "name": "years_of_service",
123
+ "type": "derived"
124
+ }
125
+ ]
126
+ },
127
+ {
128
+ "name": "Professor",
129
+ "type": "strong",
130
+ "attributes": [
131
+ {
132
+ "name": "rank",
133
  "type": "regular"
134
  },
135
  {
136
+ "name": "tenure_status",
137
  "type": "regular"
138
  },
139
  {
140
+ "name": "research_areas",
141
  "type": "multivalued"
142
  }
143
  ]
144
  },
145
  {
146
+ "name": "Lecturer",
147
  "type": "strong",
148
  "attributes": [
149
  {
150
+ "name": "contract_type",
151
+ "type": "regular"
152
+ },
153
+ {
154
+ "name": "courses_per_semester",
155
+ "type": "regular"
156
+ }
157
+ ]
158
+ },
159
+ {
160
+ "name": "Staff",
161
+ "type": "strong",
162
+ "attributes": [
163
+ {
164
+ "name": "position_title",
165
+ "type": "regular"
166
  },
167
  {
168
+ "name": "department_assigned",
169
  "type": "regular"
170
  },
171
  {
172
+ "name": "salary_grade",
173
+ "type": "regular"
174
+ }
175
+ ]
176
+ },
177
+ {
178
+ "name": "AdministrativeStaff",
179
+ "type": "strong",
180
+ "attributes": [
181
+ {
182
+ "name": "access_level",
183
  "type": "regular"
184
+ },
185
+ {
186
+ "name": "responsibilities",
187
+ "type": "multivalued"
188
  }
189
  ]
190
  },
191
  {
192
+ "name": "TechnicalStaff",
193
  "type": "strong",
194
  "attributes": [
195
  {
196
+ "name": "certifications",
197
+ "type": "multivalued"
198
+ },
199
+ {
200
+ "name": "equipment_assigned",
201
+ "type": "multivalued"
202
+ }
203
+ ]
204
+ },
205
+ {
206
+ "name": "Vehicle",
207
+ "type": "strong",
208
+ "attributes": [
209
+ {
210
+ "name": "vehicle_id",
211
  "type": "primary_key"
212
  },
213
  {
214
+ "name": "license_plate",
215
  "type": "regular"
216
  },
217
  {
218
+ "name": "year",
219
  "type": "regular"
220
  },
221
  {
222
+ "name": "current_value",
223
  "type": "derived"
224
+ }
225
+ ]
226
+ },
227
+ {
228
+ "name": "Car",
229
+ "type": "strong",
230
+ "attributes": [
231
+ {
232
+ "name": "doors",
233
+ "type": "regular"
234
  },
235
  {
236
+ "name": "fuel_type",
237
+ "type": "regular"
238
  }
239
  ]
240
  },
241
  {
242
+ "name": "Bus",
243
+ "type": "strong",
244
  "attributes": [
245
  {
246
+ "name": "capacity",
247
+ "type": "regular"
248
  },
249
  {
250
+ "name": "route_assigned",
251
+ "type": "regular"
252
+ }
253
+ ]
254
+ },
255
+ {
256
+ "name": "MaintenanceVehicle",
257
+ "type": "strong",
258
+ "attributes": [
259
+ {
260
+ "name": "equipment_type",
261
  "type": "regular"
262
  },
263
  {
264
+ "name": "specialized_tools",
265
+ "type": "multivalued"
266
+ }
267
+ ]
268
+ },
269
+ {
270
+ "name": "Course",
271
+ "type": "strong",
272
+ "attributes": [
273
+ {
274
+ "name": "course_id",
275
+ "type": "primary_key"
276
+ },
277
+ {
278
+ "name": "course_name",
279
  "type": "regular"
280
  },
281
  {
282
+ "name": "credits",
283
+ "type": "regular"
284
+ }
285
+ ]
286
+ },
287
+ {
288
+ "name": "Department",
289
+ "type": "strong",
290
+ "attributes": [
291
+ {
292
+ "name": "dept_id",
293
+ "type": "primary_key"
294
+ },
295
+ {
296
+ "name": "dept_name",
297
+ "type": "regular"
298
+ },
299
+ {
300
+ "name": "budget",
301
+ "type": "regular"
302
  }
303
  ]
304
  }
305
  ],
306
  "relationships": [
307
  {
308
+ "name": "PersonISA",
309
+ "type": "isa",
310
+ "parent": "Person",
311
+ "children": ["Student", "Faculty", "Staff"]
312
+ },
313
+ {
314
+ "name": "StudentISA",
315
+ "type": "isa",
316
+ "parent": "Student",
317
+ "children": ["UndergraduateStudent", "GraduateStudent"]
318
+ },
319
+ {
320
+ "name": "FacultyISA",
321
+ "type": "isa",
322
+ "parent": "Faculty",
323
+ "children": ["Professor", "Lecturer"]
324
+ },
325
+ {
326
+ "name": "StaffISA",
327
+ "type": "isa",
328
+ "parent": "Staff",
329
+ "children": ["AdministrativeStaff", "TechnicalStaff"]
330
+ },
331
+ {
332
+ "name": "VehicleISA",
333
+ "type": "isa",
334
+ "parent": "Vehicle",
335
+ "children": ["Car", "Bus", "MaintenanceVehicle"]
336
+ },
337
+ {
338
+ "name": "Enrolls",
339
  "type": "regular",
340
+ "entities": ["Student", "Course"],
341
  "cardinalities": {
342
+ "Student": "M",
343
+ "Course": "M"
344
  },
345
+ "attributes": [
346
+ {
347
+ "name": "semester"
348
+ },
349
+ {
350
+ "name": "year"
351
+ },
352
+ {
353
+ "name": "grade"
354
+ }
355
+ ]
356
  },
357
  {
358
+ "name": "Teaches",
359
+ "type": "regular",
360
+ "entities": ["Faculty", "Course"],
361
  "cardinalities": {
362
+ "Faculty": "M",
363
+ "Course": "M"
364
  },
365
+ "attributes": [
366
+ {
367
+ "name": "semester"
368
+ },
369
+ {
370
+ "name": "classroom"
371
+ }
372
+ ]
373
+ },
374
+ {
375
+ "name": "WorksIn",
376
+ "type": "regular",
377
+ "entities": ["Faculty", "Department"],
378
+ "cardinalities": {
379
+ "Faculty": "M",
380
+ "Department": "1"
381
+ },
382
+ "attributes": [
383
+ {
384
+ "name": "start_date"
385
+ }
386
+ ]
387
+ },
388
+ {
389
+ "name": "Manages",
390
+ "type": "regular",
391
+ "entities": ["Staff", "Department"],
392
+ "cardinalities": {
393
+ "Staff": "M",
394
+ "Department": "M"
395
+ },
396
+ "attributes": [
397
+ {
398
+ "name": "role"
399
+ }
400
+ ]
401
+ },
402
+ {
403
+ "name": "Uses",
404
+ "type": "regular",
405
+ "entities": ["Staff", "Vehicle"],
406
+ "cardinalities": {
407
+ "Staff": "M",
408
+ "Vehicle": "M"
409
+ },
410
+ "attributes": [
411
+ {
412
+ "name": "usage_date"
413
+ },
414
+ {
415
+ "name": "purpose"
416
+ }
417
+ ]
418
  }
419
  ]
420
  }