Module: Engram::ReservedMetadata
- Defined in:
- lib/engram/reserved_metadata.rb
Overview
Collision-preserving operations for schemas sharing Engram's metadata namespace.
Constant Summary collapse
- KEY =
"_engram"
Class Method Summary collapse
- .attach(metadata, schema_key, value, namespace_description: "metadata") ⇒ Object
- .merge(left, right, path = []) ⇒ Object
- .merge_value(left, right, path) ⇒ Object
- .normalize(value, path = []) ⇒ Object
Class Method Details
.attach(metadata, schema_key, value, namespace_description: "metadata") ⇒ Object
10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/engram/reserved_metadata.rb', line 10 def attach(, schema_key, value, namespace_description: "metadata") = ( || {}).dup reserved_values = [.delete(KEY), .delete(:_engram)].compact unless reserved_values.all? { |reserved| reserved.is_a?(Hash) } raise Engram::Error, "metadata key #{KEY.inspect} is reserved for Engram #{namespace_description}" end reserved = reserved_values.reduce({}) do |merged, reserved_value| siblings = reserved_value.reject { |key, _nested| key.to_s == schema_key } merge(merged, normalize(siblings)) end .merge(KEY => reserved.merge(schema_key => normalize(value))) end |
.merge(left, right, path = []) ⇒ Object
39 40 41 42 43 |
# File 'lib/engram/reserved_metadata.rb', line 39 def merge(left, right, path = []) right.each_with_object(left.dup) do |(key, value), merged| merged[key] = merged.key?(key) ? merge_value(merged[key], value, path + [key]) : value end end |
.merge_value(left, right, path) ⇒ Object
45 46 47 48 49 50 |
# File 'lib/engram/reserved_metadata.rb', line 45 def merge_value(left, right, path) return merge(left, right, path) if left.is_a?(Hash) && right.is_a?(Hash) return left if left == right raise Engram::Error, "conflicting reserved metadata at #{path.join(".")}" end |
.normalize(value, path = []) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/engram/reserved_metadata.rb', line 24 def normalize(value, path = []) return value.map { |nested| normalize(nested, path) } if value.is_a?(Array) return value unless value.is_a?(Hash) value.each_with_object({}) do |(key, nested), normalized| string_key = key.to_s normalized_value = normalize(nested, path + [string_key]) normalized[string_key] = if normalized.key?(string_key) merge_value(normalized[string_key], normalized_value, path + [string_key]) else normalized_value end end end |