Top Level Namespace

Defined in:

Macro Summary

Macro Detail

macro caridina_use_json_discriminator(mapping, fallback = nil) #

JSON::Serializable::use_json_discriminator on steroids.

It supports looking at many fields to discriminate the type, and case use nested fields. If no known discriminator value is found, it use the fallback type if any or raise an error.

Many types can be given for a discriminator, using an array. In this case the first one deserializing without error is returned.

The mapping should be order by priority, in case many discriminator values are found, higher priority last.

For example:

struct Event
  include JSON::Serializable

  caridina_use_json_discriminator(
    {
      ["type", "name"] => {"A": EventA, "B": EventB},
      "event_type"     => {"A": EventA, "C": EventC, "AC": [EventA, EventC]},
    }
  )

  struct Type
    include JSON::Serializable

    getter name : String
  end

  getter type : Type
  getter event_type : String
end

Event.from_json(%(
  {
    "type": {"name": "A"},
    ...
  }
)) # => EventA(…)

Event.from_json(%(
  {
    "event_type": "C",
    ...
  }
)) # => EventC(…)

Event.from_json(%(
  {
    "event_type": "AC",
    ...
  }
)) # => EventA, or if it fails to deserialize it to EventA then EventC

You MUST use an array when using a nested field as a discriminator field. There is no limit on the level of nesting.

If many discriminator fields match, the last one with a known value will be used.

Event.from(%(
  {
    "type": {"name": "unknown"},
    "event_type": "C"
  }
)) # => EventC(…)

Event.from(%(
  {
    "type": {"name": "A"},
    "event_type": "unknown"
  }
)) # => EventA(…)

# "event_type" is read first, but in the mapping ["type", "name"] came last so
# it has priority.
Event.from(%(
  {
    "event_type": "C",
    "type": {"name": "A"}
  }
)) # => EventA(…)