Module: LcpRuby::Metadata::ModelHashMerger

Defined in:
lib/lcp_ruby/metadata/model_hash_merger.rb

Overview

Merges a parent (abstract) model hash into a child model hash. Operates on raw hashes before ModelDefinition.from_hash is called.

Constant Summary collapse

NAMED_ARRAY_KEYS =

Named-array keys: arrays of hashes where each item has a “name” key. Child items with the same name override parent items; child-only items are appended.

Set.new(%w[fields associations scopes events]).freeze
HASH_KEYS =

Hash keys: merged by key, child wins on collision.

Set.new(%w[virtual_columns display_templates]).freeze
ADDITIVE_ARRAY_KEYS =

Additive array keys: concatenated, no override by name.

Set.new(%w[validations indexes]).freeze
IDENTITY_KEYS =

Identity keys: never inherited, always child’s own.

Set.new(%w[name table_name label label_plural slug_field]).freeze
STRIP_KEYS =

Keys stripped from the merged result.

Set.new(%w[abstract inherits]).freeze

Class Method Summary collapse

Class Method Details

.merge(parent_hash, child_hash) ⇒ Object

All other keys (positioning, data_source, etc.) fall through to the default branch: child wins if present, otherwise inherited from parent.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/lcp_ruby/metadata/model_hash_merger.rb', line 27

def self.merge(parent_hash, child_hash)
  result = {}

  # Start with parent as base, skip identity/strip keys
  parent_hash.each do |key, value|
    next if IDENTITY_KEYS.include?(key) || STRIP_KEYS.include?(key)
    result[key] = value.deep_dup
  end

  # Apply child values
  child_hash.each do |key, value|
    next if STRIP_KEYS.include?(key)

    if IDENTITY_KEYS.include?(key)
      result[key] = value
    elsif NAMED_ARRAY_KEYS.include?(key)
      result[key] = merge_named_arrays(result[key], value)
    elsif HASH_KEYS.include?(key)
      result[key] = (result[key] || {}).merge(child_hash[key] || {})
    elsif ADDITIVE_ARRAY_KEYS.include?(key)
      result[key] = concat_arrays(result[key], value)
    elsif key == "options"
      result[key] = (result[key] || {}).deep_merge(value || {})
    else
      # Scalar keys and any unknown keys: child wins
      result[key] = value.deep_dup
    end
  end

  # Clean up empty collections
  result.delete_if { |k, v| (v.is_a?(Array) && v.empty?) || (v.is_a?(Hash) && v.empty?) }

  result
end