Packages
arke
0.1.0
1.1.33
retired
0.6.2
0.6.1
0.6.0
0.5.0
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.4.0-bulk.1
0.4.0-bulk.0
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.1.38
0.1.37
0.1.36
0.1.35
0.1.34
0.1.33
0.1.32
0.1.31
0.1.30
0.1.29
0.1.28
0.1.27
0.1.26
0.1.25
0.1.24
0.1.23
0.1.22
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Arke low code framework Core
Current section
Files
Jump to
Current section
Files
lib/arke/system.ex
defmodule Arke.System do
defmacro __using__(_) do
quote do
# @after_compile __MODULE__
Module.register_attribute(__MODULE__, :arke, accumulate: false, persist: true)
Module.register_attribute(__MODULE__, :groups, accumulate: true, persist: true)
Module.register_attribute(__MODULE__, :parameters, accumulate: true, persist: false)
Module.put_attribute(__MODULE__, :system_arke, true)
import unquote(__MODULE__), only: [arke: 1, arke: 2, parameter: 3, parameter: 2, group: 1, group: 2]
# @before_compile unquote(__MODULE__)
def arke_from_attr(), do: Keyword.get(__MODULE__.__info__(:attributes), :arke, []) |> List.first
def groups_from_attr(), do: Keyword.get(__MODULE__.__info__(:attributes), :groups, [])
def on_validate(unit), do: {:ok, unit}
def before_validate(unit), do: {:ok, unit}
def on_create(unit), do: {:ok, unit}
def before_create(unit), do: {:ok, unit}
def on_update(unit), do: {:ok, unit}
def before_update(unit), do: {:ok, unit}
def on_delete(unit), do: {:ok, unit}
def before_delete(unit), do: {:ok, unit}
defoverridable [on_validate: 1, before_validate: 1, on_create: 1, before_create: 1, on_update: 1,
before_update: 1, on_delete: 1, before_delete: 1]
end
end
# defmacro __before_compile__(env) do
# end
#
# def compile(translations) do
#
# end
######################################################################################################################
# ARKE MACRO #########################################################################################################
######################################################################################################################
@doc """
Macro to create an arke struct with the given parameters.
Usable only via `code` and not `iex`.
## Example
arke do
parameter :custom_parameter, :string, required: true, unique: true
parameter :custom_parameter2, :string, required: true, values: ["value1", "value2"]
parameter :custom_parameter3, :integer, required: true, values: [%{label: "option 1", value: 1},%{label: "option 2", value: 2}]
parameter :custom_parameter4, :dict, required: true, default: %{"default_dict_key": "default_dict_value"}
end
## Return
%Arke.Core.'{arke_struct}'{}
"""
@spec arke(args :: list(), Macro.t) :: %{}
defmacro arke(opts \\ [], do: block) do
type = Keyword.get(opts, :type, "arke")
active = Keyword.get(opts, :active, true)
configuration = Keyword.get(opts, :configuration, %{})
base_parameters = get_base_arke_parameters(type)
quote do
type = unquote(type)
active = unquote(active)
opts = unquote(opts)
configuration = unquote(Macro.escape(configuration))
caller = unquote(__CALLER__.module)
id = Keyword.get(opts, :id, caller |> to_string |> String.split(".") |> List.last |> Macro.underscore |> String.to_atom)
label = Keyword.get(opts, :label, id |> Atom.to_string |> String.replace("_", " ") |> String.capitalize)
unquote(base_parameters)
unquote(block)
@arke %{id: id, data: %{label: label, active: active, type: type, parameters: @parameters}, metadata: %{}}
# @arke Arke.Core.Arke.new(id: id, label: label, active: active, configuration: configuration, type: type, parameters: @parameters)
end
end
defp get_base_arke_parameters("arke") do
quote do
parameter :id, :string, required: true, persistence: "table_column"
parameter :arke_id, :atom, required: false, persistence: "table_column"
parameter :metadata, :dict, required: false, persistence: "table_column"
parameter :inserted_at, :datetime, required: false, persistence: "table_column"
parameter :updated_at, :datetime, required: false, persistence: "table_column"
end
end
defp get_base_arke_parameters(_type), do: nil
# @spec __arke_info__(caller :: caller(), options :: list()) :: [id: atom() | String.t(), label: String.t(), active: boolean(), configuration: map(), type: atom()]
# defp __arke_info__(caller, options) do
#
# id = Keyword.get(options, :id, caller |> to_string |> String.split(".") |> List.last |> Macro.underscore |> String.to_atom)
# label = Keyword.get(options, :label, id |> Atom.to_string |> String.replace("_", " ") |> String.capitalize)
# [
# id: id,
# label: label,
# active: Keyword.get(options, :active, true),
# configuration: Keyword.get(options, :configuration, %{}),
# type: Keyword.get(options, :type, :arke)
# ]
# end
######################################################################################################################
# END ARKE MACRO #####################################################################################################
######################################################################################################################
######################################################################################################################
# PARAMETER MACRO ####################################################################################################
######################################################################################################################
@doc """
Macro used to define parameter in an arke.
See example above `arke/2`
"""
@spec parameter(id :: atom(), type :: atom(), opts :: list()) :: Macro.t
defmacro parameter(id, type, opts \\ []) do
# parameter_dict = Arke.System.BaseParameter.parameter_options(opts, id, type)
quote bind_quoted: [id: id, type: type, opts: opts] do
@parameters %{id: id, arke: type, metadata: opts}
# @parameters unquote(Macro.escape(parameter_dict))
end
end
######################################################################################################################
# END PARAMETER MACRO ################################################################################################
######################################################################################################################
######################################################################################################################
# GROUP MACRO ####################################################################################################
######################################################################################################################
@doc """
Macro used to define parameter in an arke.
See example above `arke/2`
"""
@spec group(id :: atom(), opts :: list()) :: Macro.t
defmacro group(id, opts \\ []) do
quote bind_quoted: [id: id, opts: opts] do
@groups %{id: id, metadata: opts}
end
end
######################################################################################################################
# END GROUP MACRO ################################################################################################
######################################################################################################################
end
defmodule Arke.System.Arke do
use Arke.System
end
defmodule Arke.System.BaseArke do
defstruct [:id , :label, :active, :type, :parameters, :metadata]
end
defmodule Arke.System.BaseParameter do
defstruct [:id , :label, :active, :configuration, :type, :parameters]
@doc """
Used in the parameter macro to create the map for every parameter which have the `values` option.
It check if the given value are the same type as the parameter type and then creates a list of map as follows:
[%{label "given label", value: given_value}, %{label "given label two ", value: given_value_two}]
Keep in mind that if the values are declared as list instead of map the label will be generated from the value itself.
... omitted code
parameter :custom_parameter2, :integer, required: true, values: [1, 2, 3]
... omitted code
The code above will results in an `{arke_struct}` with the values as follows
... omitted code
values: [%{label "1", value: 1}, %{label "2", value: 2}, %{label "3", value: 3}]
... omitted code
"""
@spec parameter_options(opts :: list(), id :: atom(), type :: atom()) :: %{type: atom(), opts: list()}
def parameter_options(opts, id, type) do
opts = opts
|> parameter_option_common(id)
|> parameter_by_type(type)
%{type: type, opts: opts}
end
defp parameter_option_common(opts, id) do
opts
|> Keyword.put(:id, id)
|> Keyword.put(:label, Keyword.get(opts, :label, id |> Atom.to_string |> String.replace("_", " ") |> String.capitalize))
|> parameter_option(:required, false)
|> parameter_option(:nullable, true)
|> parameter_option(:default, nil)
|> parameter_option(:persistence, "arke_parameter")
end
defp parameter_by_type(opts, :string) do
opts
|> parameter_option(:type, :string)
|> parameter_option(:min_length, nil)
|> parameter_option(:max_length, nil)
|> __enum_parameter__(:string)
end
defp parameter_by_type(opts, :integer) do
opts
|> parameter_option(:type, :integer)
|> __number_parameter__()
|> __enum_parameter__(:integer)
end
defp parameter_by_type(opts, :float) do
opts
|> parameter_option(:type, :float)
|> __number_parameter__()
|> __enum_parameter__(:float)
end
defp parameter_by_type(opts, type), do: opts |> parameter_option(:type, type)
defp __number_parameter__(opts) do
opts
|> parameter_option(:min, nil)
|> parameter_option(:max, nil)
end
defp parameter_option(opts, key, default) do
Keyword.put_new(opts, key, default)
end
defp __enum_parameter__(opts, type) do
case Keyword.has_key?(opts, :values) do
true -> __validate_values__(opts ,opts[:values], type)
false -> parameter_option(opts, :values, nil)
end
end
defp __validate_values__(opts, [h | _t]=values, type) when is_map(h) do
condition = cond do
type == :string -> fn l,v -> ((is_binary(l) and is_binary(v)) or (is_atom(l) and is_atom(v))) end
type == :integer -> fn l,v -> (is_binary(l) and is_integer(v)) end
type == :float -> fn l,v -> (is_binary(l) and is_number(v)) end
end
case Enum.all?(values, fn map -> Enum.map([:label, :value], fn key -> Map.has_key?(map, key)end)end) do
true ->
__create_map_values__(values,opts, type , condition)
_ -> Keyword.update(opts, :values, nil, fn _current_value -> nil end) # FARE RAISE ECCEZIONE DA GESTIRE. CHIAVI DEVONO ESSERE TUTTE UGUALI
end
end
defp __validate_values__(opts, values , type) do
condition = cond do
type == :string -> fn v-> (is_binary(v) or is_atom(v)) end
type == :integer -> fn v-> is_integer(v) end
type == :float -> fn v -> is_number(v) end
end
__values_from_list__(values, opts, condition)
end
defp __validate_values__(opts, _, _), do: Keyword.update(opts, :values, nil, fn _current_value -> nil end) # FARE RAISE ECCEZIONE DA GESTIRE
defp __create_map_values__(values, opts, type,condition) do
with true <- Enum.all?(values, fn %{label: l, value: v} -> condition.(l,v) end) do
new_values = Enum.map(values, fn k -> %{label: String.capitalize(to_string(k.label)), value: __get_map_value__(k.value, type) } end)
__create_index__(opts, new_values)
else ( _ -> parameter_option(opts, :values, nil)) # FARE RAISE ECCEZIONE DA GESTIRE. CHIAVI DEVONO ESSERE TUTTE UGUALI
end
end
defp __get_map_value__(value, :string), do: to_string(value)
defp __get_map_value__(value, _), do: value
defp __values_from_list__(values, opts, condition)do
with true <- Enum.all?(values, &(condition.(&1))) do
new_values = Enum.map(values, fn k -> %{label: String.capitalize(to_string(k)), value: k} end)
__create_index__(opts,new_values )
else ( _ -> Keyword.update(opts, :values, nil, fn _current_value -> nil end)) # FARE RAISE ECCEZIONE DA GESTIRE. CHIAVI DEVONO ESSERE TUTTE UGUALI
end
end
defp __create_index__(opts, new_values), do: Keyword.delete(opts, :values) |> Keyword.put_new(:values, new_values)
end