Class: Dbwatcher::Services::DiagramData::Dataset

Inherits:
Object
  • Object
show all
Defined in:
lib/dbwatcher/services/diagram_data/dataset.rb

Overview

Complete dataset for diagram generation

This class serves as a container for all diagram data including entities and relationships, with validation and management capabilities.

Examples:

dataset = Dataset.new
dataset.add_entity(Entity.new(id: "users", name: "User", type: "table"))
dataset.add_entity(Entity.new(id: "orders", name: "Order", type: "table"))
dataset.add_relationship(Relationship.new(
  source_id: "users", target_id: "orders", type: "has_many"
))
dataset.valid? # => true
dataset.to_h   # => complete dataset hash

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(metadata: {}) ⇒ Dataset

Initialize empty dataset

Parameters:

  • metadata (Hash) (defaults to: {})

    optional dataset-level metadata



26
27
28
29
30
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 26

def initialize(metadata: {})
  @entities = {}
  @relationships = []
  @metadata = .is_a?(Hash) ?  : {}
end

Instance Attribute Details

#entitiesObject (readonly)

Returns the value of attribute entities.



21
22
23
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 21

def entities
  @entities
end

#metadataObject (readonly)

Returns the value of attribute metadata.



21
22
23
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 21

def 
  @metadata
end

#relationshipsObject (readonly)

Returns the value of attribute relationships.



21
22
23
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 21

def relationships
  @relationships
end

Class Method Details

.from_h(hash) ⇒ Dataset

Create dataset from hash

Parameters:

  • hash (Hash)

    dataset data

Returns:

  • (Dataset)

    new dataset instance



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 235

def self.from_h(hash)
  dataset = new(metadata: hash[:metadata] || hash["metadata"] || {})

  # Load entities
  entities_data = hash[:entities] || hash["entities"] || {}
  entities_data.each_value do |entity_data|
    entity = Entity.from_h(entity_data)
    dataset.add_entity(entity)
  end

  # Load relationships
  relationships_data = hash[:relationships] || hash["relationships"] || []
  relationships_data.each do |relationship_data|
    relationship = Relationship.from_h(relationship_data)
    dataset.add_relationship(relationship)
  end

  dataset
end

.from_json(json) ⇒ Dataset

Create dataset from JSON

Parameters:

  • json (String)

    JSON string

Returns:

  • (Dataset)

    new dataset instance



259
260
261
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 259

def self.from_json(json)
  from_h(JSON.parse(json))
end

Instance Method Details

#add_entity(entity) ⇒ Entity

Add entity to dataset

Parameters:

  • entity (Entity)

    entity to add

Returns:

  • (Entity)

    the added entity

Raises:

  • (ArgumentError)

    if entity is invalid



37
38
39
40
41
42
43
44
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 37

def add_entity(entity)
  raise ArgumentError, "Entity must be an Entity instance" unless entity.is_a?(Entity)

  raise ArgumentError, "Entity is invalid: #{entity.validation_errors.join(", ")}" unless entity.valid?

  @entities[entity.id] = entity
  entity
end

#add_relationship(relationship) ⇒ Relationship

Add relationship to dataset

Parameters:

Returns:

Raises:

  • (ArgumentError)

    if relationship is invalid



51
52
53
54
55
56
57
58
59
60
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 51

def add_relationship(relationship)
  raise ArgumentError, "Relationship must be a Relationship instance" unless relationship.is_a?(Relationship)

  unless relationship.valid?
    raise ArgumentError, "Relationship is invalid: #{relationship.validation_errors.join(", ")}"
  end

  @relationships << relationship
  relationship
end

#clearself

Clear all data from dataset

Returns:

  • (self)

    for method chaining



205
206
207
208
209
210
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 205

def clear
  @entities.clear
  @relationships.clear
  @metadata.clear
  self
end

#connected_entitiesArray<Entity>

Get entities with at least one relationship

Returns:

  • (Array<Entity>)

    connected entities



190
191
192
193
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 190

def connected_entities
  connected_ids = (@relationships.map(&:source_id) + @relationships.map(&:target_id)).uniq
  @entities.values.select { |entity| connected_ids.include?(entity.id) }
end

#empty?Boolean

Check if dataset is empty

Returns:

  • (Boolean)

    true if no entities or relationships



198
199
200
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 198

def empty?
  @entities.empty? && @relationships.empty?
end

#entity?(id) ⇒ Boolean

Check if entity exists

Parameters:

  • id (String)

    entity ID

Returns:

  • (Boolean)

    true if entity exists



74
75
76
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 74

def entity?(id)
  @entities.key?(id.to_s)
end

#get_entity(id) ⇒ Entity?

Get entity by ID

Parameters:

  • id (String)

    entity ID

Returns:

  • (Entity, nil)

    entity or nil if not found



66
67
68
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 66

def get_entity(id)
  @entities[id.to_s]
end

#inspectString

Detailed string representation

Returns:

  • (String)

    detailed string representation



273
274
275
276
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 273

def inspect
  "#{self.class.name}(entities: #{@entities.size}, relationships: #{@relationships.size}, " \
    "metadata: #{@metadata.inspect})"
end

#isolated_entitiesArray<Entity>

Get entities with no relationships

Returns:

  • (Array<Entity>)

    isolated entities



182
183
184
185
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 182

def isolated_entities
  connected_ids = (@relationships.map(&:source_id) + @relationships.map(&:target_id)).uniq
  @entities.values.reject { |entity| connected_ids.include?(entity.id) }
end

#relationships_for(entity_id, direction: :all) ⇒ Array<Relationship>

Get relationships for an entity

Parameters:

  • entity_id (String)

    entity ID

  • direction (Symbol) (defaults to: :all)

    :outgoing, :incoming, or :all

Returns:



110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 110

def relationships_for(entity_id, direction: :all)
  id = entity_id.to_s

  case direction
  when :outgoing
    @relationships.select { |rel| rel.source_id == id }
  when :incoming
    @relationships.select { |rel| rel.target_id == id }
  when :all
    @relationships.select { |rel| rel.source_id == id || rel.target_id == id }
  else
    raise ArgumentError, "Direction must be :outgoing, :incoming, or :all"
  end
end

#remove_entity(id) ⇒ Entity?

Remove entity by ID

Parameters:

  • id (String)

    entity ID

Returns:

  • (Entity, nil)

    removed entity or nil if not found



82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 82

def remove_entity(id)
  entity = @entities.delete(id.to_s)

  # Remove relationships involving this entity
  if entity
    @relationships.reject! do |rel|
      rel.source_id == id.to_s || rel.target_id == id.to_s
    end
  end

  entity
end

#remove_relationship(relationship) ⇒ Boolean

Remove relationship

rubocop:disable Naming/PredicateMethod

Parameters:

Returns:

  • (Boolean)

    true if relationship was removed



100
101
102
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 100

def remove_relationship(relationship)
  !@relationships.delete(relationship).nil?
end

#statsHash

Get dataset statistics

Returns:

  • (Hash)

    statistics about the dataset



168
169
170
171
172
173
174
175
176
177
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 168

def stats
  {
    entity_count: @entities.size,
    relationship_count: @relationships.size,
    entity_types: @entities.values.map(&:type).uniq.sort,
    relationship_types: @relationships.map(&:type).uniq.sort,
    isolated_entities: isolated_entities.map(&:id),
    connected_entities: connected_entities.map(&:id)
  }
end

#to_hHash

Serialize dataset to hash

Returns:

  • (Hash)

    serialized dataset



215
216
217
218
219
220
221
222
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 215

def to_h
  {
    entities: @entities.transform_values(&:to_h),
    relationships: @relationships.map(&:to_h),
    metadata: @metadata,
    stats: stats
  }
end

#to_json(*args) ⇒ String

Serialize dataset to JSON

Returns:

  • (String)

    JSON representation



227
228
229
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 227

def to_json(*args)
  to_h.to_json(*args)
end

#to_sString

String representation of dataset

Returns:

  • (String)

    string representation



266
267
268
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 266

def to_s
  "#{self.class.name}(entities: #{@entities.size}, relationships: #{@relationships.size})"
end

#valid?Boolean

Check if dataset is valid

Returns:

  • (Boolean)

    true if dataset is valid



128
129
130
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 128

def valid?
  validation_errors.empty?
end

#validation_errorsArray<String>

Get validation errors

Returns:

  • (Array<String>)

    array of validation error messages



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/dbwatcher/services/diagram_data/dataset.rb', line 135

def validation_errors
  errors = []

  # Validate all entities
  @entities.each do |id, entity|
    errors << "Entity #{id} is invalid: #{entity.validation_errors.join(", ")}" unless entity.valid?
  end

  # Validate all relationships
  @relationships.each_with_index do |relationship, index|
    unless relationship.valid?
      errors << "Relationship #{index} is invalid: #{relationship.validation_errors.join(", ")}"
    end

    # Check that referenced entities exist
    unless entity?(relationship.source_id)
      errors << "Relationship #{index} references non-existent source entity: #{relationship.source_id}"
    end

    unless entity?(relationship.target_id)
      errors << "Relationship #{index} references non-existent target entity: #{relationship.target_id}"
    end
  end

  # Validate metadata
  errors << "Metadata must be a Hash" unless @metadata.is_a?(Hash)

  errors
end