refactor: reduce complexity

This commit is contained in:
carla 2026-01-15 17:00:17 +01:00
parent 67072f0c52
commit 6dc398fa5a
3 changed files with 92 additions and 78 deletions

View file

@ -97,17 +97,33 @@ defmodule Mv.Membership.Import.HeaderMapper do
}
# Build reverse map: normalized_variant -> canonical_field
# This is computed at runtime on first access and cached
# Cached on first access for performance
defp normalized_to_canonical do
cached = Process.get({__MODULE__, :normalized_to_canonical})
if cached do
cached
else
map = build_normalized_to_canonical_map()
Process.put({__MODULE__, :normalized_to_canonical}, map)
map
end
end
# Builds the normalized variant -> canonical field map
defp build_normalized_to_canonical_map do
@member_field_variants_raw
|> Enum.flat_map(fn {canonical, variants} ->
Enum.map(variants, fn variant ->
{normalize_header(variant), canonical}
end)
end)
|> Enum.flat_map(&map_variants_to_normalized/1)
|> Map.new()
end
# Maps a canonical field and its variants to normalized tuples
defp map_variants_to_normalized({canonical, variants}) do
Enum.map(variants, fn variant ->
{normalize_header(variant), canonical}
end)
end
@doc """
Normalizes a CSV header string for comparison.
@ -208,9 +224,10 @@ defmodule Mv.Membership.Import.HeaderMapper do
|> String.replace(<<0x2212::utf8>>, "-")
end
# Normalizes punctuation: parentheses, slashes become spaces
# Normalizes punctuation: parentheses, slashes, underscores become spaces
defp normalize_punctuation(str) do
str
|> String.replace("_", " ")
|> String.replace(~r/[()\[\]{}]/, " ")
|> String.replace(~r/[\/\\]/, " ")
end
@ -228,18 +245,18 @@ defmodule Mv.Membership.Import.HeaderMapper do
result =
headers
|> Enum.with_index()
|> Enum.reduce_while({%{}, [], %{}}, fn {header, index}, {acc_map, acc_unknown, acc_seen} ->
|> Enum.reduce_while({%{}, []}, fn {header, index}, {acc_map, acc_unknown} ->
normalized = normalize_header(header)
case process_member_header(header, index, normalized, acc_map, acc_seen) do
case process_member_header(header, index, normalized, acc_map, %{}) do
{:error, reason} ->
{:halt, {:error, reason}}
{:ok, new_map, new_seen} ->
{:cont, {new_map, acc_unknown, new_seen}}
{:ok, new_map, _} ->
{:cont, {new_map, acc_unknown}}
{:unknown} ->
{:cont, {acc_map, [index | acc_unknown], acc_seen}}
{:cont, {acc_map, [index | acc_unknown]}}
end
end)
@ -247,7 +264,7 @@ defmodule Mv.Membership.Import.HeaderMapper do
{:error, reason} ->
{:error, reason}
{member_map, unknown_indices, _normalized_seen} ->
{member_map, unknown_indices} ->
validate_required_fields(member_map, unknown_indices)
end
end
@ -258,17 +275,17 @@ defmodule Mv.Membership.Import.HeaderMapper do
{:ok, acc_map, acc_seen}
end
defp process_member_header(_header, index, normalized, acc_map, acc_seen) do
if Map.has_key?(normalized_to_canonical(), normalized) do
canonical = normalized_to_canonical()[normalized]
defp process_member_header(_header, index, normalized, acc_map, _acc_seen) do
case Map.get(normalized_to_canonical(), normalized) do
nil ->
{:unknown}
if Map.has_key?(acc_map, canonical) do
{:error, "duplicate header for #{canonical} (normalized: #{normalized})"}
else
{:ok, Map.put(acc_map, canonical, index), Map.put(acc_seen, normalized, canonical)}
end
else
{:unknown}
canonical ->
if Map.has_key?(acc_map, canonical) do
{:error, "duplicate header for #{canonical} (normalized: #{normalized})"}
else
{:ok, Map.put(acc_map, canonical, index), %{}}
end
end
end
@ -295,7 +312,7 @@ defmodule Mv.Membership.Import.HeaderMapper do
result =
unknown_indices
|> Enum.reduce_while({%{}, [], %{}}, fn index, {acc_map, acc_unknown, acc_seen} ->
|> Enum.reduce_while({%{}, []}, fn index, {acc_map, acc_unknown} ->
header = Enum.at(headers, index)
normalized = normalize_header(header)
@ -305,16 +322,16 @@ defmodule Mv.Membership.Import.HeaderMapper do
normalized,
custom_field_lookup,
acc_map,
acc_seen
%{}
) do
{:error, reason} ->
{:halt, {:error, reason}}
{:ok, new_map, new_seen} ->
{:cont, {new_map, acc_unknown, new_seen}}
{:ok, new_map, _} ->
{:cont, {new_map, acc_unknown}}
{:unknown} ->
{:cont, {acc_map, [index | acc_unknown], acc_seen}}
{:cont, {acc_map, [index | acc_unknown]}}
end
end)
@ -322,7 +339,7 @@ defmodule Mv.Membership.Import.HeaderMapper do
{:error, reason} ->
{:error, reason}
{custom_map, remaining_unknown, _normalized_seen} ->
{custom_map, remaining_unknown} ->
{:ok, custom_map, Enum.reverse(remaining_unknown)}
end
end
@ -350,10 +367,10 @@ defmodule Mv.Membership.Import.HeaderMapper do
normalized,
_custom_field_lookup,
acc_map,
acc_seen
_acc_seen
)
when normalized == "" do
{:ok, acc_map, acc_seen}
{:ok, acc_map, %{}}
end
defp process_custom_field_header(
@ -362,7 +379,7 @@ defmodule Mv.Membership.Import.HeaderMapper do
normalized,
custom_field_lookup,
acc_map,
acc_seen
_acc_seen
) do
if Map.has_key?(custom_field_lookup, normalized) do
custom_field_id = custom_field_lookup[normalized]
@ -370,8 +387,7 @@ defmodule Mv.Membership.Import.HeaderMapper do
if Map.has_key?(acc_map, custom_field_id) do
{:error, "duplicate custom field header (normalized: #{normalized})"}
else
{:ok, Map.put(acc_map, custom_field_id, index),
Map.put(acc_seen, normalized, custom_field_id)}
{:ok, Map.put(acc_map, custom_field_id, index), %{}}
end
else
{:unknown}