Elixir - JasonHelpers - Как я могу отправить список ключевых слов на json_map? - PullRequest
0 голосов
/ 06 ноября 2019

У меня есть структура данных, которую я хочу преобразовать в json и сохранить порядок ключей.

Например: %{ x: 1, a: 5} следует преобразовать в "{\"x\": 1, \"a\": 5}"

Яд делает это безлюбая проблема. Но когда я обновляюсь до Jason, он меняется на "{\"a\": 5, \"x\": 1}".

Поэтому я использую JasonHelpers json_map, чтобы сохранить порядок следующим образом:

Jason.Helpers.json_map([x: 1, a: 5])

Создает фрагмент с правильным порядком.

Однако, когда я использую переменную для этого:

list = [x: 1, a: 5]
Jason.Helpers.json_map(list)

У меня появляется ошибка:

** (Protocol.UndefinedError) protocol Enumerable not implemented for {:list, [line: 15], nil} of type Tuple.
....

ВОПРОС: Как я могупередать предварительно вычисленный список в Jason.Helpers.json_map?

Расчет сложный, поэтому я не хочу повторять код только для использования json_map, но использую функцию, которая возвращает список.

Ответы [ 2 ]

3 голосов
/ 07 ноября 2019

json_map/1 - это макрос из своих документов:

Кодирует карту JSON из ключевого слова времени компиляции.

Itпредназначен для компиляции JSON во время компиляции, поэтому он не работает с переменной времени выполнения.

Поддержка кодирования списков ключевых слов была добавлена ​​в библиотеку Jason год назад ,но, похоже, его еще не подтолкнули к гексагоне. Мне удалось заставить его работать, вытащив последний код из github:

defp deps do
  [{:jason, git: "https://github.com/michalmuskala/jason.git"}]
end

Затем, создав структуру, которая реализует Jason.Encoder (адаптировано из это решение автором Jason):

defmodule OrderedObject do
  defstruct [:value]

  def new(value), do: %__MODULE__{value: value}

  defimpl Jason.Encoder do
    def encode(%{value: value}, opts) do
      Jason.Encode.keyword(value, opts)
    end
  end
end

Теперь мы можем кодировать объекты с помощью упорядоченных ключей:

iex(1)> Jason.encode!(OrderedObject.new([x: 1, a: 5]))
"{\"x\":1,\"a\":5}"
1 голос
/ 07 ноября 2019

Я не знаю, является ли это частью общедоступного API или просто деталью реализации, но, похоже, у вас есть некоторый контроль над порядком при реализации протокола Jason.Encoder для структуры.

Давайтескажем, вы определили Ordered struct:

defmodule Ordered do
  @derive {Jason.Encoder, only: [:a, :x]}
  defstruct [:a, :x]
end

Если вы закодируете структуру, ключ "a" будет перед ключом "x":

iex> Jason.encode!(%Ordered{a: 5, x: 1})
"{\"a\":5,\"x\":1}"

Давайтепереупорядочить ключи, которые мы передаем опции :only:

defmodule Ordered do
  @derive {Jason.Encoder, only: [:x, :a]}
  defstruct [:a, :x]
end

Если мы сейчас закодируем структуру, ключ "x" будет перед ключом "a":

iex> Jason.encode!(%Ordered{a: 5, x: 1})
"{\"x\":1,\"a\":5}"
...