zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

duration.ex (3429B)


      1 # Zenflows is designed to implement the Valueflows vocabulary,
      2 # written and maintained by srfsh <info@dyne.org>.
      3 # Copyright (C) 2021-2023 Dyne.org foundation <foundation@dyne.org>.
      4 #
      5 # This program is free software: you can redistribute it and/or modify
      6 # it under the terms of the GNU Affero General Public License as published by
      7 # the Free Software Foundation, either version 3 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU Affero General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU Affero General Public License
     16 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
     17 
     18 defmodule Zenflows.VF.Duration do
     19 @moduledoc """
     20 Represents an interval between two DateTime values.
     21 """
     22 
     23 use Zenflows.DB.Schema
     24 
     25 alias Ecto.Changeset
     26 alias Zenflows.DB.Schema
     27 alias Zenflows.VF.TimeUnitEnum
     28 
     29 @type t() :: %__MODULE__{
     30 	unit_type: TimeUnitEnum.t(),
     31 	numeric_duration: Decimal.t(),
     32 }
     33 
     34 @primary_key false
     35 embedded_schema do
     36 	field :unit_type, TimeUnitEnum
     37 	field :numeric_duration, :decimal
     38 end
     39 
     40 @doc """
     41 The cast allows you to split the virtual map field into its appropriate
     42 fields.  An example usage is demonstraited in `Zenflows.VF.RecipeProcess`
     43 and `Zenflows.VF.ScenarioDefinition` modules.
     44 """
     45 @spec cast(Changeset.t(), atom()) :: Changeset.t()
     46 def cast(cset, key) do
     47 	case Changeset.fetch_change(cset, key) do
     48 		{:ok, params} ->
     49 			case changeset(params) do
     50 				%{valid?: true} = cset_dur ->
     51 					cset
     52 					|> Changeset.put_change(:"#{key}_unit_type",
     53 						Changeset.fetch_change!(cset_dur, :unit_type))
     54 					|> Changeset.put_change(:"#{key}_numeric_duration",
     55 						Changeset.fetch_change!(cset_dur, :numeric_duration))
     56 				cset_dur ->
     57 					cset_dur.errors
     58 					|> Enum.reduce(cset, fn {field, {msg, _opts}}, acc ->
     59 						Changeset.add_error(acc, key, "#{field}: #{msg}")
     60 					end)
     61 			end
     62 		:error ->
     63 			# Ecto seems to convert the params' keys to string
     64 			# whether they were originally string or atom.
     65 			strkey = "#{key}"
     66 			case cset.params do
     67 				# If, for example, `key` is
     68 				# `:has_duration`, and it's set to `nil`,
     69 				# this will set the associated fields to
     70 				# `nil` as well.
     71 				%{^strkey => nil} ->
     72 					cset
     73 					|> Changeset.force_change(:"#{key}_unit_type", nil)
     74 					|> Changeset.force_change(:"#{key}_numeric_duration", nil)
     75 				_ ->
     76 					cset
     77 			end
     78 	end
     79 end
     80 
     81 @doc """
     82 Propagates the virtual map field `key` with the associated fields
     83 as a %Duration{} struct.  Useful for GraphQL types as can be seen in
     84 `Zenflows.VF.ScenarioDefinition.Type` and `Zenflows.VF.RecipeProcess.Type`.
     85 """
     86 @spec preload(Schema.t(), atom()) :: Schema.t()
     87 def preload(schema, key) do
     88 	unit_type = Map.get(schema, :"#{key}_unit_type")
     89 	numeric_duration = Map.get(schema, :"#{key}_numeric_duration")
     90 	if unit_type && numeric_duration do
     91 		%{schema | key => %__MODULE__{
     92 			unit_type: unit_type,
     93 			numeric_duration: numeric_duration,
     94 		}}
     95 	else
     96 		schema
     97 	end
     98 end
     99 
    100 @cast ~w[unit_type numeric_duration]a
    101 @reqr @cast
    102 
    103 @spec changeset(Schema.params()) :: Changeset.t()
    104 defp changeset(params) do
    105 	%__MODULE__{}
    106 	|> Changeset.cast(params, @cast)
    107 	|> Changeset.validate_required(@reqr)
    108 	|> Changeset.validate_number(:numeric_duration, greater_than_or_equal_to: 0)
    109 end
    110 end