Tuesday, January 1, 2019

TIL - Elixir Jason.Encoder - handling optional fields

At some point along my learning road I had a location struct with the following fields:

@derive Jason.Encoder
defstruct latitude: -999, longitude: -999, speed: -1.0, altitude: -1.0, bearing: -1.0

I added one more field:

defstruct latitude: -999, longitude: -999, speed: -1.0, altitude: -1.0, bearing: -1.0, timestamp: 0.0

And my tests for encoding the struct values after reading these older location records from a file started to fail.

Turns out this @derive part is generating the code similar to this:

defimpl Jason.Encoder, for: [Location] do
def encode(%{altitude: _, bearing: _, latitude: _, longitude: _, speed: _, timestamp: _} = value, opts) do
Jason.Encode.map(Map.take(value, [:altitude, :bearing, :latitude, :longitude, :speed, :timestamp]), opts)
end
end

ref: https://hexdocs.pm/jason/Jason.Encoder.html#content

So older records can't be matched by this automatically generated definition. 

Considering that as a part of "support older data with a fallback value for the new field" exercise and based on Jason.Encoder documentation:

1. I removed the @derive Jason.Encoder line to avoid the automatic protocol implementation generation.
2. Provided own implementation that supports the old data stored:

require Jason

defimpl Jason.Encoder, for: [Location] do
# Matches the default implementation of @derive Jason.Encoder
def encode(%{altitude: _, bearing: _, latitude: _, longitude: _, speed: _, timestamp: _} = value, opts) do
Jason.Encode.map(Map.take(value, [:altitude, :bearing, :latitude, :longitude, :speed, :timestamp]), opts)
end
# Support for older data
def encode(%{altitude: _, bearing: _, latitude: _, longitude: _, speed: _} = value, opts) do
Jason.Encode.map(Map.take(value, [:altitude, :bearing, :latitude, :longitude, :speed]), opts)
end
end

This it for my Today I Learnt.

References:
https://github.com/michalmuskala/jason

And as this post started with adding a timestamp field, here you can read on timestamps in Elixir. From the Jason.Encoder author:
https://michal.muskala.eu/2017/02/02/unix-timestamps-in-elixir-1-4.html

No comments: