feat: Add metadata about polymorphic fields
This commit is contained in:
parent
4fc2b745e4
commit
dee77ae424
6 changed files with 118 additions and 2 deletions
|
@ -35,6 +35,14 @@ defmodule <%= @namespace %>.<%= @version %>.<%= class_name(@resource_name) %> do
|
|||
<% end %>
|
||||
end
|
||||
|
||||
<%= for {name, choices} <- @choices do %>
|
||||
def choices(<%= inspect(name) %>) do
|
||||
[<%= Enum.map_join(choices, ", ", &":#{&1}") %>]
|
||||
end
|
||||
<% end %>
|
||||
|
||||
def choices(_), do: nil
|
||||
|
||||
def version_namespace, do: <%= @namespace %>.<%= @version %>
|
||||
def version, do: "<%= @version %>"
|
||||
|
||||
|
|
|
@ -18,11 +18,21 @@ defmodule Kindling.Schema do
|
|||
@spec schema_map(version_string()) :: map()
|
||||
def schema_map(version) do
|
||||
filename = Path.join(Version.version_dir(version), "fhir.schema.json")
|
||||
choices = get_choice_data(version)
|
||||
|
||||
filename
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|> build_backlinks()
|
||||
|> add_choice_data(choices)
|
||||
end
|
||||
|
||||
def get_choice_data(version) do
|
||||
filename = Path.join(Version.version_dir(version), "choice-elements.json")
|
||||
|
||||
filename
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
end
|
||||
|
||||
def all_resources(schema) do
|
||||
|
@ -57,6 +67,57 @@ defmodule Kindling.Schema do
|
|||
Map.put(schema, "definitions", defs)
|
||||
end
|
||||
|
||||
def add_choice_data(schema, %{"elements" => choices}) do
|
||||
Enum.reduce(choices, schema, &apply_choice/2)
|
||||
end
|
||||
|
||||
defp apply_choice({path, types_list}, schema) do
|
||||
[type_name | rest] = String.split(path, ".")
|
||||
|
||||
{type_name, field_name} = follow_refs(schema, type_name, rest)
|
||||
field_name = String.replace(field_name, "[x]", "")
|
||||
type = schema["definitions"][type_name]
|
||||
|
||||
types_list =
|
||||
case types_list do
|
||||
["*"] ->
|
||||
type["properties"]
|
||||
|> Map.keys()
|
||||
|> Enum.filter(&String.starts_with?(&1, field_name))
|
||||
|> Enum.map(&String.replace(&1, field_name, ""))
|
||||
|
||||
other ->
|
||||
other
|
||||
end
|
||||
|
||||
field_names =
|
||||
Enum.map(types_list, fn type ->
|
||||
"#{field_name}_#{Recase.to_snake(type)}"
|
||||
end)
|
||||
|
||||
existing_choices = Map.get(type, "__choices", %{})
|
||||
new_choices = Map.put(existing_choices, field_name, field_names)
|
||||
|
||||
put_in(schema, ["definitions", type_name, "__choices"], new_choices)
|
||||
end
|
||||
|
||||
defp follow_refs(_schema, type_name, [field_name]), do: {type_name, field_name}
|
||||
|
||||
defp follow_refs(schema, type_name, [hd | rest]) do
|
||||
ref =
|
||||
case schema["definitions"][type_name]["properties"][hd] do
|
||||
%{"items" => %{"$ref" => ref}} ->
|
||||
ref
|
||||
|
||||
%{"$ref" => ref} ->
|
||||
ref
|
||||
end
|
||||
|
||||
"#/definitions/" <> next_type = ref
|
||||
|
||||
follow_refs(schema, next_type, rest)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Given a schema map in the style returned by `&schema_map/1`, and a root resource name (e.g.
|
||||
`"Encounter"`), return a `MapSet` of resources that are referenced (recursively) from the
|
||||
|
|
|
@ -29,7 +29,6 @@ defmodule Kindling.SchemaDownloader do
|
|||
:ok
|
||||
|
||||
other ->
|
||||
dbg(other)
|
||||
other
|
||||
end
|
||||
end
|
||||
|
@ -53,4 +52,42 @@ defmodule Kindling.SchemaDownloader do
|
|||
raise "Could not download and unzip the FHIR schema for version #{version}."
|
||||
end
|
||||
end
|
||||
|
||||
def download_choices(version) do
|
||||
{:ok, _} = Application.ensure_all_started(:req)
|
||||
version_alias = Map.get(@version_aliases, version, version)
|
||||
|
||||
version_dir = "#{Mix.Project.build_path(Mix.Project.config())}/fhir/#{version}"
|
||||
filename = "#{version_dir}/choice-elements.json"
|
||||
File.mkdir_p!(version_dir)
|
||||
|
||||
Req.Request.new(
|
||||
method: :get,
|
||||
url: "http://www.hl7.org/fhir/#{version_alias}/choice-elements.json"
|
||||
)
|
||||
|> Req.Request.prepend_response_steps(handle_utf16: &handle_utf16/1)
|
||||
|> Req.Request.append_response_steps(decompress_body: &Req.Steps.decompress_body/1)
|
||||
|> Req.get!()
|
||||
|> then(&File.write!(filename, &1.body))
|
||||
end
|
||||
|
||||
def handle_utf16({request, %{body: "\uFEFF" <> body} = response}) do
|
||||
{request, %{response | body: body}}
|
||||
end
|
||||
|
||||
def ensure_choices!(version) do
|
||||
version_dir = "#{Mix.Project.build_path(Mix.Project.config())}/fhir/#{version}"
|
||||
filename = "#{version_dir}/choice-elements.json"
|
||||
|
||||
cond do
|
||||
File.exists?(filename) ->
|
||||
:ok
|
||||
|
||||
download_choices(version) == :ok ->
|
||||
:ok
|
||||
|
||||
true ->
|
||||
raise "Could not download choice element data for version #{version}."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,6 +39,14 @@ defmodule <%= @namespace %>.<%= @version %>.<%= class_name(@resource_name) %> do
|
|||
<% end %>
|
||||
end
|
||||
|
||||
<%= for {name, choices} <- @choices do %>
|
||||
def choices(<%= inspect(name) %>) do
|
||||
[<%= Enum.map_join(choices, ", ", &":#{&1}") %>]
|
||||
end
|
||||
<% end %>
|
||||
|
||||
def choices(_), do: nil
|
||||
|
||||
def version_namespace, do: <%= @namespace %>.<%= @version %>
|
||||
def version, do: "<%= @version %>"
|
||||
def path, do: "/<%= @resource_name %>"
|
||||
|
|
|
@ -21,7 +21,8 @@ defmodule Kindling.Templates do
|
|||
properties: Resource.grouped_properties(resource, roots),
|
||||
all_fields: Resource.all_fields(resource),
|
||||
required_fields: Resource.required_fields(resource),
|
||||
backlinks: Enum.filter(resource["__backlinks"], &(&1 in roots))
|
||||
backlinks: Enum.filter(resource["__backlinks"], &(&1 in roots)),
|
||||
choices: resource["__choices"] || %{}
|
||||
}
|
||||
|
||||
if resource_name in roots do
|
||||
|
|
|
@ -15,6 +15,7 @@ defmodule Mix.Tasks.Kindling.GenerateSchemas do
|
|||
[namespace, version] = args
|
||||
|
||||
Kindling.SchemaDownloader.ensure_version!(version)
|
||||
Kindling.SchemaDownloader.ensure_choices!(version)
|
||||
|
||||
schema = Kindling.Schema.schema_map(version)
|
||||
roots = Kindling.Config.root_resources()
|
||||
|
|
Loading…
Reference in a new issue