Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map key validity/order in Elixir 1.14 #170

Open
tfwright opened this issue Jul 24, 2023 · 4 comments · May be fixed by #195
Open

Map key validity/order in Elixir 1.14 #170

tfwright opened this issue Jul 24, 2023 · 4 comments · May be fixed by #195

Comments

@tfwright
Copy link

I have been using Jason to encode Elixir maps into Jason in docs generated at compile time. That had been working fine until upgrading to Elixir 1.14 when suddenly docs kept changing after compilation do to differently ordered Jason keys.

I quickly realized that, in retrospect, it was a mistake to rely on maps for this since their order is explicitly not guaranteed. After some digging I saw that Jason.Helpers provides json_map/1 to transform an ordered keyword list into a json object, so I assume that would be the right tool for this problem.

However, when I started converting the docs I ran into a compilation error for a API response that includes a / (see livemd below). Is there something about the JSON spec I'm not aware of that would explain this behavior?

Jason json_map

Mix.install([
  {:jason, "~> 1.4"}
])

Section

require Jason.Helpers
Jason.Helpers.json_map("my/key": "test")
@michalmuskala
Copy link
Owner

michalmuskala commented Jul 25, 2023

This is a limitation of the current architecture of json_map macro that pre-computes some information at compile-time - it should be possible to fix it.

In the meantime, you should be able to use the runtime variant of an ordered map - the Jason.OrderedObject, e.g.

Jason.OrderedObject.new("my/key": "test")

it also allows for using string keys:

Jason.OrderedObject.new([{"my/key", "test"}])

and the keys can be dynamic:

Jason.OrderedObject.new([{my_key, "test"}])

PS. the key order jumbling comes likely from upgrading to Erlang 26, rather than Elixir 1.14

@kevinlang
Copy link

Running into a similar issue where I have a mix task that generates some JSON data that I commit to the repository. My diffs are noisy due to key order changing. It would be nice to be able to provide an option to pretty_print like sort_keys: true or something.

In the meantime, I just shell out to jq to sort the JSON.

@michalmuskala
Copy link
Owner

An option to sort the keys for pretty printing would definitely work, perhaps even one for the base encoding and using maps iterators. I would welcome a PR with such a change

@venkatd
Copy link

venkatd commented Sep 3, 2024

Hi @michalmuskala what is involved in allowing a custom sort function for maps to be passed into the encode function?

We would be willing to sponsor someone to implement this :)

@gilbertbw gilbertbw linked a pull request Nov 8, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants