# Copyright 2023 Arkemis S.r.l. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. defmodule Arke.Core.Parameter do @moduledoc """ Module to manage the defaults parameter In order to create a new one simply use the .new(opts) ## Types - `string` - `integer` - `float` - `boolean` - `dict` - `date` - `time` - `datetime` ## Values There are two possible ways to declare the values for a parameter: - list => by giving a list of values \n values: ["value 1", "value 2", ...."value n"] - list of map => by giving a list of map. Each map **must** contain `label` and `value`. \n values: [%{label:"value 1", value: 1},... %{label: "value 999", value: 999}] The result will always be a list of map containing `label` and `value`. Keep in mind that if the values are provided using a list the `label` will be autogenerated. Remember also that all the values provided must be the same type as the [ParameterType](#module-types) and only `string`, `integer` and `float` support the `values` declaration ## Get list of attributes definable in opts during creation: iex> Arke.Core.Parameter.'ParameterType'.get_parameters() """ alias Arke.Boundary.ParameterManager @type parameter_struct() :: Parameter.Boolean.t() | Parameter.String.t() | Parameter.Dict.t() | Parameter.Integer.t() | Parameter.Float.t() @doc """ Macro defining a shared struct of parameter used across Arkes """ use Arke.System.Group group id: "parameter" do end def on_unit_create(_arke, %{id: id, metadata: %{project: project}} = unit) do ParameterManager.create(unit) {:ok, unit} end def on_unit_update(_, %{id: id, metadata: %{project: project}} = unit) do ParameterManager.update(id, project, unit) {:ok, unit} end def on_unit_delete(_, %{id: id, metadata: %{project: project}} = unit) do ParameterManager.remove(unit) {:ok, unit} end end defmodule Arke.Core.Parameter.String do @moduledoc """ Module that define the struct of a String by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.String ## Element added - `min_length` => :atom => define the min_length the string could have. It will check during creation - `max_length` => :atom => define the max_length the string could have. It will check during creation - `values` => [list] || [%{label: string, value: any}, ...] => use this to create a parameter with only certain values assignable. (Values must be the same type as the parameter we want to create) - `multiple` => boolean => relevant only if values are set. It makes possible to assign more than a values defined in values - `unique` => boolean => check if there is an existing record in the database with the same value before creating one - `default` => String => default value ## Example iex> params = [id: :string_test, min_length: 1, values: ["value1", "value2"], multiple: true] ...> Arke.Core.Parameter.new(%{type: :string, opts: params}) ## Return %Arke.Core.Parameter.String{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "string" do end def before_load(data, _persistence_fn) do args = Arke.System.BaseParameter.check_enum(:string, Map.to_list(data)) {:ok, Enum.into(args, %{})} end end defmodule Arke.Core.Parameter.Integer do @moduledoc """ Module that define the struct of a Integer by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.Integer ## Element added - `min` => :atom => define the mix value the parammeter could have - `max` => :atom => define the max the parammeter could have - `values` => [list] || [%{label: string, value: any}, ...] => use this to create a parameter with only certain values assignable. (Values must be the same type as the parameter we want to create) - `multiple` => boolean => relevant only if values are set. It makes possible to assign more than a values defined in values - `default` => Integer => default value ## Example iex> params = [id: :integer_test, min: 3, max: 7.5, values: [%{label: "option 1", value: 1}, %{label: "option 2", value: 2}]] ...> Arke.Core.Parameter.new(%{type: :integer, opts: params}) ## Return %Arke.Core.Parameter.Float{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "integer" do end def before_load(data, _persistence_fn) do args = Arke.System.BaseParameter.check_enum(:integer, Map.to_list(data)) {:ok, Enum.into(args, %{})} end end defmodule Arke.Core.Parameter.Float do @moduledoc """ Module that define the struct of a Float by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.Float ## Element added - `min` => :atom => define the mix value the parammeter could have - `max` => :atom => define the max the parammeter could have - `values` => [list] || [%{label: string, value: any}, ...] => use this to create a parameter with only certain values assignable. (Values must be the same type as the parameter we want to create) - `multiple` => boolean => relevant only if values are set. It makes possible to assign more than a values defined in values - `default` => Float => default value ## Example iex> params = [id: :float_test, min: 3, max: 7.5] ...> Arke.Core.Parameter.new(%{type: :float, opts: params}) ## Return %Arke.Core.Parameter.Float{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "float" do end def before_load(data, _persistence_fn) do args = Arke.System.BaseParameter.check_enum(:float, Map.to_list(data)) {:ok, Enum.into(args, %{})} end end defmodule Arke.Core.Parameter.Boolean do @moduledoc """ Module that define the struct of a Boolean by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.Boolean ## Element added - `default` => Boolean => default value ## Example iex> params = [id: :boolean_test, default: false] ...> Arke.Core.Parameter.Boolean(%{type: :boolean, opts: params}) ## Return %Arke.Core.Parameter.Boolean{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "boolean" do end end defmodule Arke.Core.Parameter.Dict do @moduledoc """ Module that define the struct of a Dict by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.Dict ## Element added - `default` => Dict => default value ## Example iex> params = [id: :dict_test, default: %{default_key: default_value}] ...> Arke.Core.Parameter.Dict(%{type: :dict, opts: params}) ## Return %Arke.Core.Parameter.Dict{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "dict" do end end defmodule Arke.Core.Parameter.List do @moduledoc """ Module that define the struct of a Dict by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.Dict ## Element added - `default` => Dict => default value ## Example iex> params = [id: :dict_test, default: %{default_key: default_value}] ...> Arke.Core.Parameter.Dict(%{type: :dict, opts: params}) ## Return %Arke.Core.Parameter.Dict{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "list" do end end defmodule Arke.Core.Parameter.Date do @moduledoc """ Module that define the struct of a Date by extending the Arke.Core.Parameter.base_parameters(). ## Accepted values Date accepts the following format as values: - string => "YYYY-MM-DD" (separator must be - hyphen) - sigil => ~D[YYYY-MM-DD] (separator must be - hyphen) - struct => %Date{} {arke_struct} = Parameter.Date ## Element added - `default` => [values](#module-accepted-values) => default value ## Example iex> params = [id: :date_test, default: "1999-09-03"] ...> Arke.Core.Parameter.new(%{type: :date, opts: params}) ## Return %Arke.Core.Parameter.Date{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "date" do end end defmodule Arke.Core.Parameter.Time do @moduledoc """ Module that define the struct of a Time by extending the Arke.Core.Parameter.base_parameters(). ## Accepted values Date accepts the following format as values: - string => "HH:MM:SS" (separator must be - hyphen) - sigil => ~T[HH:MM:SS] (separator must be - hyphen) - struct => %Time{} {arke_struct} = Parameter.Date ## Element added - `default` => [values](#module-accepted-values) => default value ## Example iex> params = [id: :time_test, default: "23:14:15"] ...> Arke.Core.Parameter.new(%{type: :time, opts: params}) ## Return %Arke.Core.Parameter.Time{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "time" do end end defmodule Arke.Core.Parameter.DateTime do @moduledoc """ Module that define the struct of a DateTime by extending the Arke.Core.Parameter.base_parameters(). ## Accepted values Date accepts the following format as values: - string => "YYYY-MM-DDTHH:MM:SSZ" | "YYYY-MM-DD HH:MM:SSZ" | "YYYY-MM-DD HH:MM:SS" (separator must be - hyphen for Date and colon : for Time) - sigil => ~U[YYYY-MM-DDTHH:MM:SSZ] | ~U[YYYY-MM-DD HH:MM:SSZ] | ~N[YYYY-MM-DDTHH:MM:SSZ] | ~N[YYYY-MM-DD HH:MM:SSZ] | ~N[YYYY-MM-DD HH:MM:SS] (separator must be - hyphen for Date and colon : for Time) - struct => %DateTime{} | %NaiveDateTime{} The T separator is optional. If no offset is provided (Z will be added at the end) {arke_struct} = Parameter.Date ## Element added - `default` => [values](#module-accepted-values) => default value ## Example iex> params = [id: :time_test, default: "1999-12-12 09:08:07"] ...> Arke.Core.Parameter.new(%{type: :datetime, opts: params}) ## Return %Arke.Core.Parameter.DateTime{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "datetime" do end end defmodule Arke.Core.Parameter.Link do @moduledoc """ Module that define the struct of a Link by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.Link ## Element added - `link` => Link => link handler ## Example iex> params = [id: :dict_test, default: %{default_key: default_value}] ...> Arke.Core.Parameter.Dict(%{type: :dict, opts: params}) ## Return %Arke.Core.Parameter.Link{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "link" do end end defmodule Arke.Core.Parameter.Dynamic do @moduledoc """ Module that define the struct of a Dynamic by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.Dynamic ## Return %Arke.Core.Parameter.Dynamic{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "dynamic" do end end defmodule Arke.Core.Parameter.Binary do @moduledoc """ Module that define the struct of a Binary by extending the Arke.Core.Parameter.base_parameters() {arke_struct} = Parameter.Binary ## Return %Arke.Core.Parameter.Binary{} """ alias Arke.Core.Parameter alias Arke.Boundary.ParameterManager use Arke.System arke id: "binary" do end end