8000 TD-7106 Add df_content and data_structures to implementation cache by Lorenzo-SF · Pull Request #154 · Bluetab/td-cache · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

TD-7106 Add df_content and data_structures to implementation cache #154

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## [7.0.1] 2025-01-13
## [Unreleased]

### Added

- [TD-7106] Issues with customisation and sorting in implementations tables

## [7.0.1] 2025-01-13

### Changed

Expand Down
85 changes: 84 additions & 1 deletion lib/td_cache/implementation_cache.ex
|> MapHelpers.parse_fields(@props)
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ defmodule TdCache.ImplementationCache do
{:minimum, :float},
{:result_type, :string},
{:updated_at, :datetime},
{:status, :string}
{:status, :string},
{:df_content, :map},
{:data_structures, :list}
]

@rule_props [
Expand Down Expand Up @@ -172,6 +174,8 @@ defmodule TdCache.ImplementationCache do

implementation
|> decode_df_content()
|> decode_data_structures()
|> put_optional(:execution_result_info, execution_result_info)
|> put_optional(:rule, rule)
|> put_optional(:concepts_links, concepts)
Expand Down Expand Up @@ -269,6 +273,8 @@ defmodule TdCache.ImplementationCache do
implementation_props =
implementation
|> Map.take(props_keys)
|> encode_df_content()
|> encode_data_structures()

result_props_keys = Enum.map(@result_props, fn {key, _} -> key end)

Expand Down Expand Up @@ -307,4 +313,81 @@ defmodule TdCache.ImplementationCache do
_ -> ["SADD", "implementation:deleted_ids", implementation_ref]
end
end

defp encode_df_content(%{df_content: content} = props) when is_map(content) do
%{props | df_content: Jason.encode!(content)}
end

defp encode_df_content(props), do: props

defp decode_df_content(%{df_content: content} = implementation) when is_binary(content) do
case Jason.decode(content) do
{:ok, decoded} -> %{implementation | df_content: decoded}
_ -> implementation
end
end

defp decode_df_content(implementation), do: implementation

defp encode_data_structures(%{data_structures: data_structures} = props) do
encoded_data_structures =
data_structures
|> Enum.map(fn %{
data_structure: %{current_version: current_version, domains: domains} = ds,
type: link_type
} ->
cv =
Map.new()
|> Map.put(:name, Map.get(current_version, :name))
|> Map.put(:path, Map.get(current_version, :path))

data_structure =
Map.new()
|> Map.put(:id, Map.get(ds, :id))
|> Map.put(:external_id, Map.get(ds, :external_id))
|> Map.put(:domains, domains)
|> Map.put(:current_version, cv)

%{data_structure: data_structure, type: link_type}
end)
|> Jason.encode!()

Map.put(props, :data_structures, encoded_data_structures)
end

defp encode_data_structures(props), do: props

defp decode_data_structures(%{data_structures: data_structures} = implementation) do
implementation
|> Map.delete(:data_structures)
|> Map.put("data_structures", data_structures)
|> decode_data_structures()
end

defp decode_data_structures(%{"data_structures" => data_structures} = implementation) do
case Jason.decode(data_structures) do
{:ok, decoded_data_structures} ->
decoded_data_structures =
decoded_data_structures
|> Enum.map(fn %{
"type" => link_type,
"data_structure" =>
%{"domains" => domains} =
data_structure
} ->
ds = %{data_structure | "domains" => domains}

%{"type" => String.to_atom(link_type), "data_structure" => ds}
end)

implementation
|> Map.delete("data_structures")
|> Map.put(:data_structures, MapHelpers.atomize_keys(decoded_data_structures))

_ ->
[]
end
end

defp decode_data_structures(implementation), do: implementation
end
54 changes: 54 additions & 0 deletions lib/td_cache/utils/map_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,58 @@ defmodule TdCache.Utils.MapHelpers do
def parse_string(:string, value) when is_atom(value), do: Atom.to_string(value)
# def parse_string(:datetime, value) when is_binary(value), do: DateTime.from_iso8601(value)
def parse_string(_, value), do: value

def atomize_keys(nil), do: nil

# Structs don't do enumerable and anyway the keys are already
# atoms
def atomize_keys(%{__struct__: _} = struct) do
struct
end

def atomize_keys(%{} = map) do
map
|> Enum.into(%{}, fn {k, v} -> {to_atom_key(k), atomize_keys(v)} end)
end

# Walk the list and atomize the keys of
# of any map members
def atomize_keys([head | rest]) do
[atomize_keys(head) | atomize_keys(rest)]
end

def atomize_keys(not_a_map) do
not_a_map
end

@doc """
Convert map atom keys to strings
"""
def stringify_keys(nil), do: nil

def stringify_keys(%{} = map) do
Enum.into(map, %{}, fn {k, v} -> {to_string_key(k), stringify_keys(v)} end)
end

# Walk the list and stringify the keys of
# of any map members
def stringify_keys([head | rest]) do
[stringify_keys(head) | stringify_keys(rest)]
end

def stringify_keys(not_a_map) do
not_a_map
end

defp to_atom_key(key) when is_binary(key) do
String.to_atom(key)
end

defp to_atom_key(key), do: key

defp to_string_key(key) when is_atom(key) do
Atom.to_string(key)
end

defp to_string_key(key), do: Atom.to_string(key)
end
82 changes: 74 additions & 8 deletions test/td_cache/implementation_cache_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,85 @@ defmodule TdCache.ImplementationCacheTest do
alias TdCache.Redix

setup do
implementation = build(:implementation)
dfcontent = %{
"Impact" => %{"origin" => "user", "value" => "High"},
"Quality Principles" => %{"origin" => "user", "value" => "Completeness"}
}

domains = [
%{
id: 111,
name: "domain_name_111",
external_id: "domain_external_id_111"
},
%{
id: 222,
name: "domain_name_222",
external_id: "domain_external_id_222"
},
%{
id: 333,
name: "domain_name_333",
external_id: "domain_external_id_333"
}
]

data_structures = [
%{
data_structure: %{
id: 111,
external_id: "data_tructure_111",
domains: domains,
current_version: %{
path: ["this", "is", "a", "path"],
name: "data_structure_name_111"
}
},
type: :dataset
},
%{
data_structure: %{
id: 222,
external_id: "data_tructure_222",
domains: domains,
current_version: %{
path: ["this", "is", "a", "path"],
name: "data_structure_name_222"
}
},
type: :population
},
%{
data_structure: %{
id: 333,
external_id: "data_tructure_333",
domains: domains,
current_version: %{
path: ["this", "is", "a", "path"],
name: "data_structure_name_333"
}
},
type: :validation
}
]

implementation =
build(:implementation, df_content: dfcontent, data_structures: data_structures)

on_exit(fn ->
ImplementationCache.delete(implementation.id)
Redix.command(["SREM", "implementation:deleted_ids", implementation.id])
Redix.command(["DEL", "relation_impl_id_to_impl_ref"])
end)

{:ok, implementation: implementation}
{:ok, implementation: implementation, dfcontent: dfcontent}
end

describe "ImplementationCache" do
test "writes an implementation entry in redis and reads it back", %{
implementation: implementation
} do
assert {:ok, [10, 0, 1, 0]} = ImplementationCache.put(implementation)
assert {:ok, [12, 0, 1, 0]} = ImplementationCache.put(implementation)

{:ok, impl} = ImplementationCache.get(implementation.id)

Expand All @@ -38,7 +101,9 @@ defmodule TdCache.ImplementationCacheTest do
:goal,
:minimum,
:rule_id,
:status
:status,
:df_content,
:data_structures
])

refute Map.has_key?(impl, :execution_result_info)
Expand Down Expand Up @@ -85,12 +150,13 @@ defmodule TdCache.ImplementationCacheTest do
end

test "writes implementations entries in redis and list implementations keys", %{
implementation: %{id: impl_id} = implementation
implementation: %{id: impl_id} = implementation,
dfcontent: dfcontent
} do
%{id: impl2_id} = impl2 = build(:implementation)
%{id: impl2_id} = impl2 = build(:implementation, df_content: dfcontent)
%{id: impl3_id} = impl3 = build(:implementation)
assert {:ok, [10, 0, 1, 0]} = ImplementationCache.put(implementation)
assert {:ok, [10, 0, 1, 0]} = ImplementationCache.put(impl2)
assert {:ok, [12, 0, 1, 0]} = ImplementationCache.put(implementation)
assert {:ok, [11, 0, 1, 0]} = ImplementationCache.put(impl2)
assert {:ok, [10, 0, 1, 0]} = ImplementationCache.put(impl3)

assert [
Expand Down
Loading
0