From bb44ebd30a1deebee6f459b51f8c5ff33cfff233 Mon Sep 17 00:00:00 2001 From: Zack Michener Date: Mon, 12 Feb 2024 10:52:59 -0800 Subject: [PATCH] Add options to transform field keys non-recursively (#132) --- lib/jsonapi/serializer.ex | 2 + lib/jsonapi/utils/string.ex | 10 ++++- mix.exs | 1 - test/jsonapi/serializer_test.exs | 63 ++++++++++++++++++++++++++++---- 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/lib/jsonapi/serializer.ex b/lib/jsonapi/serializer.ex index 3c744a7f..5417b09a 100644 --- a/lib/jsonapi/serializer.ex +++ b/lib/jsonapi/serializer.ex @@ -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 diff --git a/lib/jsonapi/utils/string.ex b/lib/jsonapi/utils/string.ex index 0be48824..25b9fa2d 100644 --- a/lib/jsonapi/utils/string.ex +++ b/lib/jsonapi/utils/string.ex @@ -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 @@ -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 diff --git a/mix.exs b/mix.exs index 6a9f36df..d97e5374 100644 --- a/mix.exs +++ b/mix.exs @@ -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. diff --git a/test/jsonapi/serializer_test.exs b/test/jsonapi/serializer_test.exs index ba6a986f..a228a32d 100644 --- a/test/jsonapi/serializer_test.exs +++ b/test/jsonapi/serializer_test.exs @@ -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, @@ -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" @@ -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,