feat(growth): load csv indicators into ets tables
All checks were successful
continuous-integration/drone/pr Build is passing
All checks were successful
continuous-integration/drone/pr Build is passing
This commit is contained in:
parent
902a22c947
commit
52c1d0c028
145
lib/growth/indicators/load.ex
Normal file
145
lib/growth/indicators/load.ex
Normal file
@ -0,0 +1,145 @@
|
||||
defmodule Growth.Indicators.Load do
|
||||
@moduledoc """
|
||||
Load local indicators csv files into ets.
|
||||
|
||||
For each measurement an ets table is created, so the system has the following tables:
|
||||
|
||||
* `:arm_circumference_for_age`
|
||||
* `:bmi_for_age`
|
||||
* `:head_circumference_for_age`
|
||||
* `:height_for_age`
|
||||
* `:subscapular_skinfold_for_age`
|
||||
* `:telemetry_handler_table`
|
||||
* `:triceps_skinfold_for_age`
|
||||
* `:weight_for_age`
|
||||
* `:weight_for_height`
|
||||
|
||||
The rows in the csv files are converted to two tuple, representing the a key and value, with the following format:
|
||||
|
||||
* **key**: `{gender, unit, t-value}`
|
||||
* **value**: map with the keys:
|
||||
* l
|
||||
* m
|
||||
* s
|
||||
* sd3neg
|
||||
* sd2neg
|
||||
* sd1neg
|
||||
* sd0
|
||||
* sd1
|
||||
* sd2
|
||||
* sd3
|
||||
* source
|
||||
* category
|
||||
|
||||
"""
|
||||
|
||||
@spec all :: [[boolean()]]
|
||||
@doc """
|
||||
Load indicators csv files into their own ets tables.
|
||||
"""
|
||||
def all do
|
||||
"priv/growth/indicators/*.csv"
|
||||
|> Path.wildcard()
|
||||
|> Enum.map(&create_ets/1)
|
||||
|> Enum.map(&Task.async(__MODULE__, :load_measure, [&1]))
|
||||
|> Task.await_many()
|
||||
end
|
||||
|
||||
@spec create_ets(String.t()) :: {:atom, String.t()}
|
||||
@doc """
|
||||
Create a public ets table for the csv filename, using the file name as the table name.
|
||||
|
||||
Returns a tuple with table name as an atom and the filename.
|
||||
"""
|
||||
def create_ets(filename) do
|
||||
measure = filename |> Path.basename() |> Path.rootname() |> String.to_atom()
|
||||
|
||||
try do
|
||||
:ets.new(measure, [:set, :public, :named_table])
|
||||
rescue
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
|
||||
{measure, filename}
|
||||
end
|
||||
|
||||
@spec load_measure({:atom, String.t()}) :: [boolean()]
|
||||
@doc """
|
||||
Read, convert, and load a measure/filename into the proper ets table.
|
||||
"""
|
||||
def load_measure({measure, filename}) do
|
||||
filename
|
||||
|> read()
|
||||
|> convert()
|
||||
|> load(measure)
|
||||
end
|
||||
|
||||
@spec read(String.t()) :: Enumerable.t()
|
||||
@doc false
|
||||
def read(filename) do
|
||||
filename
|
||||
|> File.stream!()
|
||||
|> IndicatorParser.parse_stream()
|
||||
end
|
||||
|
||||
@spec convert(Enumerable.t()) :: Enumerable.t()
|
||||
@doc false
|
||||
def convert(data) do
|
||||
Stream.map(data, fn [
|
||||
source,
|
||||
category,
|
||||
gender,
|
||||
unit,
|
||||
t,
|
||||
l,
|
||||
m,
|
||||
s,
|
||||
sd3neg,
|
||||
sd2neg,
|
||||
sd1neg,
|
||||
sd0,
|
||||
sd1,
|
||||
sd2,
|
||||
sd3
|
||||
] ->
|
||||
converted_t =
|
||||
if unit in ~w(day week month) do
|
||||
as_integer(t)
|
||||
else
|
||||
as_float(t)
|
||||
end
|
||||
|
||||
key = {gender, unit, converted_t}
|
||||
|
||||
value = %{
|
||||
l: as_float(l),
|
||||
m: as_float(m),
|
||||
s: as_float(s),
|
||||
sd3neg: as_float(sd3neg),
|
||||
sd2neg: as_float(sd2neg),
|
||||
sd1neg: as_float(sd1neg),
|
||||
sd0: as_float(sd0),
|
||||
sd1: as_float(sd1),
|
||||
sd2: as_float(sd2),
|
||||
sd3: as_float(sd3),
|
||||
source: source,
|
||||
category: category
|
||||
}
|
||||
|
||||
{key, value}
|
||||
end)
|
||||
end
|
||||
|
||||
@spec load(Enumerable.t(), atom()) :: [boolean()]
|
||||
@doc false
|
||||
def load(data, ets_table) do
|
||||
Enum.map(data, fn {key, value} ->
|
||||
:ets.insert_new(ets_table, {key, value})
|
||||
end)
|
||||
end
|
||||
|
||||
defp as_integer(value), do: value |> Integer.parse() |> elem(0)
|
||||
|
||||
defp as_float(value), do: value |> Float.parse() |> elem(0)
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user