Class: Diagrams::ERDiagram

Inherits:
Base
  • Object
show all
Defined in:
lib/diagrams/er_diagram.rb

Overview

Represents an Entity Relationship Diagram (ERD).

Instance Attribute Summary collapse

Attributes inherited from Base

#checksum, #version

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#diff, from_hash, from_json, #to_h, #to_json

Constructor Details

#initialize(entities: [], relationships: [], version: 1) ⇒ ERDiagram

Initializes a new ERDiagram.

Parameters:

  • entities (Array<Element::ERDEntity>) (defaults to: [])

    Initial entities (optional).

  • relationships (Array<Element::ERDRelationship>) (defaults to: [])

    Initial relationships (optional).

  • version (String, Integer, nil) (defaults to: 1)

    User-defined version identifier.



13
14
15
16
17
18
19
# File 'lib/diagrams/er_diagram.rb', line 13

def initialize(entities: [], relationships: [], version: 1)
  super(version:)
  @entities = Array(entities).each_with_object({}) { |e, h| h[e.name] = e }
  @relationships = Array(relationships)
  validate_relationships!
  update_checksum!
end

Instance Attribute Details

#entitiesObject (readonly)

Returns the value of attribute entities.



6
7
8
# File 'lib/diagrams/er_diagram.rb', line 6

def entities
  @entities
end

#relationshipsObject (readonly)

Returns the value of attribute relationships.



6
7
8
# File 'lib/diagrams/er_diagram.rb', line 6

def relationships
  @relationships
end

Class Method Details

.from_h(data_hash, version:, checksum:) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/diagrams/er_diagram.rb', line 93

def self.from_h(data_hash, version:, checksum:)
  entities_data = data_hash[:entities] || data_hash['entities'] || []
  relationships_data = data_hash[:relationships] || data_hash['relationships'] || []

  entities = entities_data.map do |entity_h|
    entity_data = entity_h.transform_keys(&:to_sym)
    attributes_data = entity_data[:entity_attributes] || entity_data[:attributes] || [] # Accept both old and new key for now
    attributes = attributes_data.map do |attr_h|
      attr_data = attr_h.transform_keys(&:to_sym)
      # Convert keys back to symbols if they are strings
      # Convert keys back to symbols
      attr_data[:keys] = attr_data[:keys].map(&:to_sym) if attr_data[:keys].is_a?(Array)
      Elements::ERDAttribute.new(attr_data)
    end
    # Use the correct attribute name when creating the entity
    Elements::ERDEntity.new(entity_data.merge(entity_attributes: attributes))
  end

  relationships = relationships_data.map do |rel_h|
    rel_data = rel_h.transform_keys(&:to_sym)
    # Convert cardinalities back to symbols if they are strings
    rel_data[:cardinality1] = rel_data[:cardinality1].to_sym if rel_data[:cardinality1].is_a?(String)
    rel_data[:cardinality2] = rel_data[:cardinality2].to_sym if rel_data[:cardinality2].is_a?(String)
    Elements::ERDRelationship.new(rel_data)
  end

  diagram = new(entities:, relationships:, version:)

  # Optional: Verify checksum
  if checksum && diagram.checksum != checksum
    warn "Checksum mismatch for loaded ERDiagram (version: #{version}). Expected #{checksum}, got #{diagram.checksum}."
  end

  diagram
end

Instance Method Details

#add_entity(name:, attributes: []) ⇒ Elements::ERDEntity

Adds an entity to the diagram.

Parameters:

  • name (String)

    The unique name of the entity.

  • attributes (Array<Hash>) (defaults to: [])

    Array of attribute definitions (hashes like { type:, name:, keys:, comment: }).

Returns:

Raises:

  • (ArgumentError)

    if an entity with the same name already exists.



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/diagrams/er_diagram.rb', line 27

def add_entity(name:, attributes: [])
  raise ArgumentError, "Entity name '#{name}' cannot be empty" if name.nil? || name.strip.empty?
  raise ArgumentError, "Entity with name '#{name}' already exists" if @entities.key?(name)

  entity_attributes = attributes.map do |attr_hash|
    Elements::ERDAttribute.new(attr_hash.transform_keys(&:to_sym))
  end
  new_entity = Elements::ERDEntity.new(name:, entity_attributes: entity_attributes) # Use renamed attribute

  @entities[name] = new_entity
  update_checksum!
  new_entity
end

#add_relationship(entity1:, entity2:, cardinality1:, cardinality2:, identifying: false, label: nil) ⇒ Elements::ERDRelationship

Adds a relationship between two entities.

Parameters:

  • entity1 (String)

    Name of the first entity.

  • entity2 (String)

    Name of the second entity.

  • cardinality1 (Symbol)

    Cardinality of entity1 relative to entity2 (e.g., :ONE_ONLY).

  • cardinality2 (Symbol)

    Cardinality of entity2 relative to entity1 (e.g., :ZERO_OR_MORE).

  • identifying (Boolean) (defaults to: false)

    Whether the relationship is identifying (default: false).

  • label (String, nil) (defaults to: nil)

    Optional label describing the relationship action.

Returns:

Raises:

  • (ArgumentError)

    if either entity does not exist.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/diagrams/er_diagram.rb', line 51

def add_relationship(entity1:, entity2:, cardinality1:, cardinality2:, identifying: false, label: nil)
  unless @entities.key?(entity1) && @entities.key?(entity2)
    raise ArgumentError, "One or both entities ('#{entity1}', '#{entity2}') not found for relationship."
  end

  new_relationship = Elements::ERDRelationship.new(
    entity1:,
    entity2:,
    cardinality1:,
    cardinality2:,
    identifying:,
    label:
  )
  @relationships << new_relationship
  update_checksum!
  new_relationship
end

#find_entity(entity_name) ⇒ Elements::ERDEntity?

Finds an entity by its name.

Parameters:

  • entity_name (String)

    The name of the entity to find.

Returns:



73
74
75
# File 'lib/diagrams/er_diagram.rb', line 73

def find_entity(entity_name)
  @entities[entity_name]
end

#identifiable_elementsObject



86
87
88
89
90
91
# File 'lib/diagrams/er_diagram.rb', line 86

def identifiable_elements
  {
    entities: @entities.values,
    relationships: @relationships # Relationships don't have a simple unique ID, rely on object equality for diff
  }
end

#to_h_contentObject

— Base Class Implementation —



79
80
81
82
83
84
# File 'lib/diagrams/er_diagram.rb', line 79

def to_h_content
  {
    entities: @entities.values.map(&:to_h),
    relationships: @relationships.map(&:to_h)
  }
end