ZahirJS commited on
Commit
1657843
·
verified ·
1 Parent(s): cf59592

Update entity_relationship_generator.py

Browse files
Files changed (1) hide show
  1. entity_relationship_generator.py +81 -157
entity_relationship_generator.py CHANGED
@@ -331,14 +331,6 @@ def generate_entity_relationship_diagram(json_input: str, output_format: str) ->
331
  {"name": "cod_depto", "type": "primary_key"},
332
  {"name": "nombre_depto", "type": "regular"}
333
  ]
334
- },
335
- {
336
- "name": "PROYECTO",
337
- "type": "strong",
338
- "attributes": [
339
- {"name": "cod_proyecto", "type": "primary_key"},
340
- {"name": "nombre_proyecto", "type": "regular"}
341
- ]
342
  }
343
  ],
344
  "relationships": [
@@ -350,15 +342,6 @@ def generate_entity_relationship_diagram(json_input: str, output_format: str) ->
350
  "EMPLEADO": "N",
351
  "DEPARTAMENTO": "1"
352
  }
353
- },
354
- {
355
- "name": "Trabaja_en",
356
- "type": "regular",
357
- "entities": ["EMPLEADO", "PROYECTO"],
358
- "cardinalities": {
359
- "EMPLEADO": "M",
360
- "PROYECTO": "N"
361
- }
362
  }
363
  ]
364
  }
@@ -375,112 +358,68 @@ def generate_entity_relationship_diagram(json_input: str, output_format: str) ->
375
  if 'entities' not in data:
376
  raise ValueError("Missing required field: entities")
377
 
378
- # Crear grafo con configuración simple y funcional
379
- dot = graphviz.Graph(comment='ER Diagram', engine='dot')
380
- dot.attr(rankdir='TB', bgcolor='white', pad='0.5', nodesep='1.0', ranksep='1.5')
381
- dot.attr('node', fontname='Arial', fontsize='10')
382
- dot.attr('edge', fontname='Arial', fontsize='9')
 
 
 
 
 
 
 
383
 
384
  entities = data.get('entities', [])
385
  relationships = data.get('relationships', [])
386
 
387
- # Crear entidades
388
  for entity in entities:
389
  entity_name = entity.get('name')
390
  entity_type = entity.get('type', 'strong')
 
391
 
392
  if not entity_name:
393
  continue
394
 
395
- if entity_type == 'weak':
396
- # Entidad débil: rectángulo con doble borde
397
- dot.node(
398
- entity_name,
399
- entity_name,
400
- shape='box',
401
- style='filled',
402
- fillcolor='#e8e8e8',
403
- color='#404040',
404
- penwidth='3'
405
- )
406
- else:
407
- # Entidad fuerte: rectángulo simple
408
- dot.node(
409
- entity_name,
410
- entity_name,
411
- shape='box',
412
- style='filled',
413
- fillcolor='#e8e8e8',
414
- color='#404040',
415
- penwidth='1'
416
- )
417
-
418
- # Crear atributos para cada entidad
419
- for entity in entities:
420
- entity_name = entity.get('name')
421
- attributes = entity.get('attributes', [])
422
-
423
- for i, attr in enumerate(attributes):
424
- attr_name = attr.get('name', '')
425
- attr_type = attr.get('type', 'regular')
426
 
427
- attr_id = f"{entity_name}_attr_{i}"
428
 
429
- if attr_type == 'primary_key':
430
- # Clave primaria: elipse con texto subrayado
431
- dot.node(
432
- attr_id,
433
- f'{attr_name}',
434
- shape='ellipse',
435
- style='filled',
436
- fillcolor='#d8d8d8',
437
- color='#404040',
438
- xlabel=f'PK: {attr_name}'
439
- )
440
- elif attr_type == 'partial_key':
441
- # Clave parcial
442
- dot.node(
443
- attr_id,
444
- attr_name,
445
- shape='ellipse',
446
- style='filled,dashed',
447
- fillcolor='#d8d8d8',
448
- color='#404040'
449
- )
450
- elif attr_type == 'multivalued':
451
- # Atributo multivaluado: doble elipse (simulado con penwidth)
452
- dot.node(
453
- attr_id,
454
- attr_name,
455
- shape='ellipse',
456
- style='filled',
457
- fillcolor='#d8d8d8',
458
- color='#404040',
459
- penwidth='3'
460
- )
461
- elif attr_type == 'derived':
462
- # Atributo derivado
463
- dot.node(
464
- attr_id,
465
- f'/{attr_name}/',
466
- shape='ellipse',
467
- style='filled,dashed',
468
- fillcolor='#d8d8d8',
469
- color='#404040'
470
- )
471
  else:
472
- # Atributo regular
473
- dot.node(
474
- attr_id,
475
- attr_name,
476
- shape='ellipse',
477
- style='filled',
478
- fillcolor='#d8d8d8',
479
- color='#404040'
480
- )
481
 
482
- # Conectar atributo con entidad
483
- dot.edge(entity_name, attr_id, color='#404040')
 
 
 
 
 
 
 
484
 
485
  # Crear relaciones
486
  for relationship in relationships:
@@ -499,70 +438,55 @@ def generate_entity_relationship_diagram(json_input: str, output_format: str) ->
499
  children = relationship.get('children', [])
500
 
501
  if parent and children:
502
- # Crear nodo ISA
503
- dot.node(
504
- rel_name,
505
- 'ISA',
506
- shape='triangle',
507
- style='filled',
508
- fillcolor='#c8c8c8',
509
- color='#404040'
510
- )
511
 
512
- # Conectar padre con ISA
513
- dot.edge(parent, rel_name, color='#404040')
514
 
515
- # Conectar ISA con hijos
516
  for child in children:
517
- dot.edge(rel_name, child, color='#404040')
518
 
519
  elif rel_type == 'identifying':
520
- # Relación identificadora: rombo con doble borde
521
- dot.node(
522
- rel_name,
523
- rel_name,
524
- shape='diamond',
525
- style='filled',
526
- fillcolor='#c8c8c8',
527
- color='#404040',
528
- penwidth='3'
529
- )
 
 
 
 
530
 
531
  # Conectar entidades
532
  for entity in entities_involved:
533
  cardinality = cardinalities.get(entity, '1')
534
- dot.edge(entity, rel_name, label=cardinality, color='#404040')
535
 
536
  else:
537
- # Relación regular: rombo simple
538
- dot.node(
539
- rel_name,
540
- rel_name,
541
- shape='diamond',
542
- style='filled',
543
- fillcolor='#c8c8c8',
544
- color='#404040'
545
- )
546
-
547
- # Crear atributos de la relación si existen
548
- for i, attr in enumerate(rel_attributes):
549
- attr_name = attr.get('name', '')
550
- attr_id = f"{rel_name}_attr_{i}"
551
 
552
- dot.node(
553
- attr_id,
554
- attr_name,
555
- shape='ellipse',
556
- style='filled',
557
- fillcolor='#d8d8d8',
558
- color='#404040'
559
- )
560
- dot.edge(rel_name, attr_id, color='#404040')
561
 
562
- # Conectar entidades con la relación
563
  for entity in entities_involved:
564
  cardinality = cardinalities.get(entity, '1')
565
- dot.edge(entity, rel_name, label=cardinality, color='#404040')
566
 
567
  # Renderizar el diagrama
568
  with NamedTemporaryFile(delete=False, suffix=f'.{output_format}') as tmp:
 
331
  {"name": "cod_depto", "type": "primary_key"},
332
  {"name": "nombre_depto", "type": "regular"}
333
  ]
 
 
 
 
 
 
 
 
334
  }
335
  ],
336
  "relationships": [
 
342
  "EMPLEADO": "N",
343
  "DEPARTAMENTO": "1"
344
  }
 
 
 
 
 
 
 
 
 
345
  }
346
  ]
347
  }
 
358
  if 'entities' not in data:
359
  raise ValueError("Missing required field: entities")
360
 
361
+ # Usar Digraph para mejor control del layout
362
+ dot = graphviz.Digraph(comment='ER Diagram', engine='dot')
363
+ dot.attr(
364
+ rankdir='TB',
365
+ bgcolor='white',
366
+ pad='0.5',
367
+ nodesep='0.5',
368
+ ranksep='1.0',
369
+ splines='ortho'
370
+ )
371
+ dot.attr('node', fontname='Arial', fontsize='10', color='#404040')
372
+ dot.attr('edge', fontname='Arial', fontsize='9', color='#404040')
373
 
374
  entities = data.get('entities', [])
375
  relationships = data.get('relationships', [])
376
 
377
+ # Crear entidades con atributos incluidos en la tabla
378
  for entity in entities:
379
  entity_name = entity.get('name')
380
  entity_type = entity.get('type', 'strong')
381
+ attributes = entity.get('attributes', [])
382
 
383
  if not entity_name:
384
  continue
385
 
386
+ # Construir tabla HTML para entidad con atributos
387
+ if attributes:
388
+ # Crear tabla con nombre de entidad y atributos
389
+ attr_rows = []
390
+ for attr in attributes:
391
+ attr_name = attr.get('name', '')
392
+ attr_type = attr.get('type', 'regular')
393
+
394
+ if attr_type == 'primary_key':
395
+ attr_rows.append(f'<TR><TD><U><B>{attr_name}</B></U></TD></TR>')
396
+ elif attr_type == 'partial_key':
397
+ attr_rows.append(f'<TR><TD><U>{attr_name}</U></TD></TR>')
398
+ elif attr_type == 'multivalued':
399
+ attr_rows.append(f'<TR><TD>{{{attr_name}}}</TD></TR>')
400
+ elif attr_type == 'derived':
401
+ attr_rows.append(f'<TR><TD>/{attr_name}/</TD></TR>')
402
+ else:
403
+ attr_rows.append(f'<TR><TD>{attr_name}</TD></TR>')
 
 
 
 
 
 
 
 
 
 
 
 
 
404
 
405
+ attr_html = ''.join(attr_rows)
406
 
407
+ if entity_type == 'weak':
408
+ # Entidad débil con doble borde
409
+ label = f'<<TABLE BORDER="3" CELLBORDER="1" CELLSPACING="0" CELLPADDING="6" BGCOLOR="#e8e8e8"><TR><TD COLSPAN="1"><B>{entity_name}</B></TD></TR><HR/>{attr_html}</TABLE>>'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  else:
411
+ # Entidad fuerte
412
+ label = f'<<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="6" BGCOLOR="#e8e8e8"><TR><TD COLSPAN="1"><B>{entity_name}</B></TD></TR><HR/>{attr_html}</TABLE>>'
 
 
 
 
 
 
 
413
 
414
+ dot.node(entity_name, label, shape='plaintext')
415
+ else:
416
+ # Entidad sin atributos
417
+ if entity_type == 'weak':
418
+ dot.node(entity_name, entity_name, shape='box', style='filled',
419
+ fillcolor='#e8e8e8', color='#404040', penwidth='3')
420
+ else:
421
+ dot.node(entity_name, entity_name, shape='box', style='filled',
422
+ fillcolor='#e8e8e8', color='#404040', penwidth='1')
423
 
424
  # Crear relaciones
425
  for relationship in relationships:
 
438
  children = relationship.get('children', [])
439
 
440
  if parent and children:
441
+ dot.node(rel_name, 'ISA', shape='triangle', style='filled',
442
+ fillcolor='#c8c8c8', color='#404040')
 
 
 
 
 
 
 
443
 
444
+ dot.edge(parent, rel_name, dir='none', color='#404040')
 
445
 
 
446
  for child in children:
447
+ dot.edge(rel_name, child, dir='none', color='#404040')
448
 
449
  elif rel_type == 'identifying':
450
+ # Relación identificadora
451
+ if rel_attributes:
452
+ # Con atributos
453
+ attr_rows = []
454
+ for attr in rel_attributes:
455
+ attr_name = attr.get('name', '')
456
+ attr_rows.append(f'<TR><TD>{attr_name}</TD></TR>')
457
+
458
+ attr_html = ''.join(attr_rows)
459
+ label = f'<<TABLE BORDER="3" CELLBORDER="0" CELLSPACING="0" CELLPADDING="4" BGCOLOR="#c8c8c8"><TR><TD><B>{rel_name}</B></TD></TR>{attr_html}</TABLE>>'
460
+ dot.node(rel_name, label, shape='plaintext')
461
+ else:
462
+ dot.node(rel_name, rel_name, shape='diamond', style='filled',
463
+ fillcolor='#c8c8c8', color='#404040', penwidth='3')
464
 
465
  # Conectar entidades
466
  for entity in entities_involved:
467
  cardinality = cardinalities.get(entity, '1')
468
+ dot.edge(entity, rel_name, label=cardinality, dir='none', color='#404040')
469
 
470
  else:
471
+ # Relación regular
472
+ if rel_attributes:
473
+ # Con atributos
474
+ attr_rows = []
475
+ for attr in rel_attributes:
476
+ attr_name = attr.get('name', '')
477
+ attr_rows.append(f'<TR><TD>{attr_name}</TD></TR>')
 
 
 
 
 
 
 
478
 
479
+ attr_html = ''.join(attr_rows)
480
+ label = f'<<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="4" BGCOLOR="#c8c8c8"><TR><TD><B>{rel_name}</B></TD></TR>{attr_html}</TABLE>>'
481
+ dot.node(rel_name, label, shape='plaintext')
482
+ else:
483
+ dot.node(rel_name, rel_name, shape='diamond', style='filled',
484
+ fillcolor='#c8c8c8', color='#404040')
 
 
 
485
 
486
+ # Conectar entidades
487
  for entity in entities_involved:
488
  cardinality = cardinalities.get(entity, '1')
489
+ dot.edge(entity, rel_name, label=cardinality, dir='none', color='#404040')
490
 
491
  # Renderizar el diagrama
492
  with NamedTemporaryFile(delete=False, suffix=f'.{output_format}') as tmp: