Skip to content

Commit

Permalink
Add options to transform field keys non-recursively (beam-community#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
protestContest committed Feb 12, 2024
1 parent 9bbacd1 commit bb44ebd
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 10 deletions.
2 changes: 2 additions & 0 deletions lib/jsonapi/serializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ defmodule JSONAPI.Serializer do
case Utils.String.field_transformation() do
:camelize -> Utils.String.expand_fields(fields, &Utils.String.camelize/1)
:dasherize -> Utils.String.expand_fields(fields, &Utils.String.dasherize/1)
:camelize_nonrecursive -> Utils.String.expand_fields_once(fields, &Utils.String.camelize/1)
:dasherize_nonrecursive -> Utils.String.expand_fields_once(fields, &Utils.String.dasherize/1)
_ -> fields
end
end
Expand Down
10 changes: 9 additions & 1 deletion lib/jsonapi/utils/string.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule JSONAPI.Utils.String do
String manipulation helpers.
"""

@allowed_transformations [:camelize, :dasherize, :underscore]
@allowed_transformations [:camelize, :dasherize, :underscore, :camelize_nonrecursive, :dasherize_nonrecursive]

@doc """
Replace dashes between words in `value` with underscores
Expand Down Expand Up @@ -236,6 +236,14 @@ defmodule JSONAPI.Utils.String do
value
end

def expand_fields_once(map, fun) when is_map(map) do
Enum.into(map, %{}, fn {key, value} ->
{fun.(key), expand_fields(value, &to_string/1)}
end)
end

def expand_fields_once(value, _fun), do: expand_fields(value, &to_string/1)

defp maybe_expand_fields(values, fun) when is_list(values) do
Enum.map(values, fn
string when is_binary(string) -> string
Expand Down
1 change: 0 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ defmodule JSONAPI.Mixfile do
end

# Use Phoenix compiler depending on environment.
defp compilers(:test), do: [:phoenix] ++ Mix.compilers()
defp compilers(_), do: Mix.compilers()

# Specifies which paths to compile per environment.
Expand Down
63 changes: 55 additions & 8 deletions test/jsonapi/serializer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -588,9 +588,9 @@ defmodule JSONAPI.SerializerTest do
id: 1,
text: "Hello",
inserted_at: NaiveDateTime.utc_now(),
body: "Hello world",
body: %{data: "Hello world", data_attr: "foo"},
full_description: "This_is_my_description",
author: %{id: 2, username: "jbonds", first_name: "jerry", last_name: "bonds"},
author: %{id: 2, username: "jbonds", first_name: %{data: "jerry", data_attr: "foo"}, last_name: "bonds"},
best_comments: [
%{
id: 5,
Expand All @@ -607,15 +607,17 @@ defmodule JSONAPI.SerializerTest do
included = encoded[:included]

assert attributes["full-description"] == data[:full_description]
assert attributes["body"]["data-attr"] == "foo"
assert attributes["inserted-at"] == data[:inserted_at]

assert Enum.find(included, fn i -> i[:type] == "user" && i[:id] == "2" end)[:attributes][
"last-name"
] == "bonds"
author2 = Enum.find(included, fn i -> i[:type] == "user" && i[:id] == "2" end)
assert author2 != nil
assert author2[:attributes]["first-name"]["data-attr"] == "foo"
assert author2[:attributes]["last-name"] == "bonds"

assert Enum.find(included, fn i -> i[:type] == "user" && i[:id] == "4" end)[:attributes][
"last-name"
] == "bronds"
author4 = Enum.find(included, fn i -> i[:type] == "user" && i[:id] == "4" end)
assert author4 != nil
assert author4[:attributes]["last-name"] == "bronds"

assert List.first(relationships["best-comments"][:data])[:id] == "5"

Expand All @@ -624,6 +626,51 @@ defmodule JSONAPI.SerializerTest do
end
end

describe "when configured to dasherize fields non-recursively" do
setup do
Application.put_env(:jsonapi, :field_transformation, :dasherize_nonrecursive)

on_exit(fn ->
Application.delete_env(:jsonapi, :field_transformation)
end)

{:ok, []}
end

test "serialize properly dasherizes attribute and relationship keys only" do
data = %{
id: 1,
text: "Hello",
inserted_at: NaiveDateTime.utc_now(),
body: %{data: "Some data", data_attr: "foo"},
full_description: "This_is_my_description",
author: %{id: 2, username: "jbonds", first_name: %{data: "jerry", data_attr: "foo"}, last_name: "bonds"},
best_comments: [
%{
id: 5,
text: %{data: "greatest comment ever", data_attr: "foo"},
user: %{id: 4, username: "jack", last_name: "bronds"}
}
]
}

encoded = Serializer.serialize(PostView, data, nil)

attributes = encoded[:data][:attributes]
included = encoded[:included]

assert attributes["full-description"] == data[:full_description]
assert attributes["body"]["data_attr"] == "foo"
assert attributes["inserted-at"] == data[:inserted_at]

author = Enum.find(included, &( &1[:type] == "user" && &1[:id] == "2"))
assert author != nil
assert author[:attributes]["last-name"] == "bonds"
assert author[:attributes]["first-name"]["data"] == "jerry"
assert author[:attributes]["first-name"]["data_attr"] == "foo"
end
end

test "serialize does not merge `included` if not configured" do
data = %{
id: 1,
Expand Down

0 comments on commit bb44ebd

Please sign in to comment.