Module: Statecraft::Metadata

Defined in:
lib/statecraft/metadata.rb

Overview

Normalizes transition metadata to exactly what will survive the jsonb round-trip, then deep-freezes it: what the guards checked is what the log stored. Symbols become strings (keys and values), times become ISO-8601 strings, and anything that JSON cannot represent fails instantly at the pipeline entrance instead of inside the transaction.

Class Method Summary collapse

Class Method Details

.deep_freeze(value) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/statecraft/metadata.rb', line 50

def self.deep_freeze(value)
  case value
  when Hash
    value.each { |key, nested| key.freeze && deep_freeze(nested) }
  when Array
    value.each { |element| deep_freeze(element) }
  end
  value.freeze
end

.normalize(raw_metadata) ⇒ Object



10
11
12
# File 'lib/statecraft/metadata.rb', line 10

def self.normalize()
  deep_freeze(round_trip())
end

.round_trip(value) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/statecraft/metadata.rb', line 14

def self.round_trip(value)
  case value
  when Hash
    value.to_h { |key, nested| [round_trip_key(key), round_trip(nested)] }
  when Array
    value.map { |element| round_trip(element) }
  when String then value.dup
  when Symbol then value.to_s
  when Integer, true, false, nil then value
  when Float then round_trip_float(value)
  when Time, Date, DateTime then value.iso8601
  else
    raise ArgumentError,
          "metadata value #{value.inspect} (#{value.class}) is not JSON-serializable; " \
          "metadata must round-trip through jsonb"
  end
end

.round_trip_float(value) ⇒ Object

Raises:

  • (ArgumentError)


32
33
34
35
36
37
38
# File 'lib/statecraft/metadata.rb', line 32

def self.round_trip_float(value)
  return value if value.finite?

  raise ArgumentError,
        "metadata value #{value.inspect} is not JSON-serializable; " \
        "jsonb has no NaN or Infinity"
end

.round_trip_key(key) ⇒ Object



40
41
42
43
44
45
46
47
48
# File 'lib/statecraft/metadata.rb', line 40

def self.round_trip_key(key)
  case key
  when String then key.dup
  when Symbol, Integer then key.to_s
  else
    raise ArgumentError,
          "metadata key #{key.inspect} (#{key.class}) is not a JSON object key"
  end
end