Last active
August 6, 2018 17:48
-
-
Save mustafaturan/eb7ed26f0e4b6a4d223d15bcb4f23ae2 to your computer and use it in GitHub Desktop.
Wrapper for the fastest Elixir JSON encode/decode library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule JSON do | |
@moduledoc false | |
@encode_opts [:use_nil] | |
@decode_opts [:return_maps, :use_nil] | |
alias :jiffy, as: Jiffy | |
@doc """ | |
Encode and return tuple | |
""" | |
@spec encode(any) :: {:ok, Strint.t()} | {:error, tuple()} | |
def encode(nil) do | |
{:ok, nil} | |
end | |
def encode(payload) do | |
{:ok, Jiffy.encode(payload, @encode_opts)} | |
catch | |
{:error, reason} -> {:error, reason} | |
end | |
@doc """ | |
Encode and return encoded json | |
""" | |
@spec encode!(any) :: Strint.t() | {:error, tuple()} | |
def encode!(payload) do | |
case encode(payload) do | |
{:ok, json} -> json | |
{:error, reason} -> {:error, reason} | |
end | |
end | |
@doc """ | |
Decode and return tuple | |
""" | |
@spec decode(String.t() | nil) :: {:ok, Map.t() | list()} | {:error, tuple()} | |
def decode(payload) do | |
{:ok, Jiffy.decode("#{payload}", @decode_opts)} | |
catch | |
{:error, reason} -> {:error, reason} | |
end | |
@doc """ | |
Decode and return decoded data | |
""" | |
@spec decode!(String.t() | nil) :: Map.t() | list() | {:error, tuple()} | |
def decode!(payload) do | |
case decode(payload) do | |
{:ok, data} -> data | |
{:error, reason} -> {:error, reason} | |
end | |
end | |
@doc """ | |
Convert map string keys to atom keys | |
This function is an optional to atomize map keys instead of having | |
string keys. | |
Warning: By default, the maximum number of atoms is 1,048,576. | |
This function should be used responsibly. Personally, | |
I recommend to use this function if you only can validate | |
the JSON schemas. | |
""" | |
@spec atomize_keys(any()) :: any() | |
# Walk through the map | |
def atomize_keys(map = %{}) do | |
map | |
|> Enum.map(fn {k, v} -> {to_atom(k), atomize_keys(v)} end) | |
|> Enum.into(%{}) | |
end | |
# Walk through the list | |
def atomize_keys([head | rest]) do | |
[atomize_keys(head) | atomize_keys(rest)] | |
end | |
# Other data types | |
def atomize_keys(other) do | |
other | |
end | |
defp to_atom(key) when is_atom(key) do | |
key | |
end | |
defp to_atom(key) when is_binary(key) do | |
String.to_atom(key) | |
end | |
defp to_atom(key) do | |
key | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
encode! & decode! should return data or raise; there is no point in having those calls if callers still need to patter match on the returned values