Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lib/ash_typescript/rpc/pipeline.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,14 @@ defmodule AshTypescript.Rpc.Pipeline do
when is_map(filtered_record) do
metadata_map = Map.get(original_record, :__metadata__, %{})
extracted_metadata = extract_metadata_fields(metadata_map, show_metadata, rpc_action)
Map.merge(filtered_record, extracted_metadata)
formatter = Rpc.output_field_formatter()

formatted_metadata =
Enum.into(extracted_metadata, %{}, fn {key, value} ->
{key, format_field_names(value, formatter)}
end)

Map.merge(filtered_record, formatted_metadata)
end

defp do_add_read_metadata(filtered_record, _original_record, _show_metadata, _rpc_action) do
Expand Down
32 changes: 32 additions & 0 deletions test/ash_typescript/rpc/rpc_metadata_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,38 @@ defmodule AshTypescript.Rpc.MetadataTest do
end
end

describe "READ actions - typed map metadata nested key formatting" do
test "typed map metadata values have camelCase nested keys" do
task = create_task("Test Task")

params = %{
"action" => "read_tasks_with_typed_map_metadata",
"fields" => ["id", "title"],
"metadataFields" => ["auditEntries", "completionInfo"]
}

conn = %Plug.Conn{}
result = Rpc.run_action(:ash_typescript, conn, params)

assert result["success"] == true
tasks = result["data"]
task_result = Enum.find(tasks, &(&1["id"] == task.id))

# Nested keys in {:array, :map} metadata should be camelCase
first_entry = List.first(task_result["auditEntries"])
assert first_entry["fieldName"] == "title"
assert first_entry["oldValue"] == "Old Title"
refute Map.has_key?(first_entry, "field_name")
refute Map.has_key?(first_entry, "old_value")

# Nested keys in :map metadata should be camelCase
assert task_result["completionInfo"]["completedAt"] == "2025-01-15T10:30:00Z"
assert task_result["completionInfo"]["completedBy"] == "user_123"
refute Map.has_key?(task_result["completionInfo"], "completed_at")
refute Map.has_key?(task_result["completionInfo"], "completed_by")
end
end

# Helper function to create tasks
defp create_task(title) do
Task
Expand Down
3 changes: 3 additions & 0 deletions test/support/domain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ defmodule AshTypescript.Test.Domain do
rpc_action :destroy_task_metadata_empty, :destroy, show_metadata: []
rpc_action :destroy_task_metadata_one, :destroy, show_metadata: [:some_string]
rpc_action :destroy_task_metadata_two, :destroy, show_metadata: [:some_string, :some_number]

rpc_action :read_tasks_with_typed_map_metadata, :read_with_typed_map_metadata,
show_metadata: nil
end

resource AshTypescript.Test.PostComment
Expand Down
39 changes: 39 additions & 0 deletions test/support/resources/task.ex
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,45 @@ defmodule AshTypescript.Test.Task do
end
end

read :read_with_typed_map_metadata do
metadata :audit_entries, {:array, :map},
constraints: [
items: [
fields: [
field_name: [type: :string],
old_value: [type: :string]
]
]
]

metadata :completion_info, :map,
constraints: [
fields: [
completed_at: [type: :string],
completed_by: [type: :string]
]
]

prepare fn query, _context ->
Ash.Query.after_action(query, fn _query, results ->
results_with_metadata =
Enum.map(results, fn record ->
record
|> Ash.Resource.put_metadata(:audit_entries, [
%{field_name: "title", old_value: "Old Title"},
%{field_name: "completed", old_value: "false"}
])
|> Ash.Resource.put_metadata(:completion_info, %{
completed_at: "2025-01-15T10:30:00Z",
completed_by: "user_123"
})
end)

{:ok, results_with_metadata}
end)
end
end

read :read_with_invalid_metadata_names do
metadata :meta_1, :string, allow_nil?: false, default: "metadata_value"
metadata :is_valid?, :boolean, allow_nil?: false, default: true
Expand Down
Loading