MscmpSystEnums (mscmp_syst_enums v0.1.0)

A framework for user configurable 'list of values' functionality.

List of values can serve two purposes in business systems:

  1. Making selections between optional system behaviors for some given entity or calculation.

  2. Selection of categorization for informational/reporting purposes.

When supporting the first purpose such choices benefit from being well defined and closely matched to the functional choices available. The second purpose, however, is often times better served by a finer grained set of selection values which are user defined rather than chosen ahead of time by the application developer. This component offers a solution for those cases when these two needs diverge, allowing the system developers to create a well defined list of choices matched to system capabilities while at the same time allowing users to establish a more extensive and nuance set of choices matching their informational needs without have to create duplicative fields for a given master or transactional data type.

Concepts

Understanding the following concepts is required for effective use of this Component.

Enumerations (Enum)

The Enumeration identifies a specific list of values used in the system as well as carrying configuration for the Enum. Configuration points include information about if a given Enum was created by the system developers ("System Defined") or is a custom, user defined Enum and to what extent the Enum is "User Maintainable".

Functional Types

Enums may optionally have defined "Functional Types" which are intended for cases where the Enum provides choices between differing system behaviors. The key idea is that the Functional Types are tightly coupled with the distinct behaviors allowed by the system. Functional types are then assigned to each of the available list of value options so that when the user selects a value from the list, they are also selecting a Functional Type which the option should invoke.

For an example of Functional Type purpose, consider a system which enables certain capabilities when a given master record is either "Active" or "Inactive". "Active" and "Inactive" would be the Functional Types recognized by the system, but for the users of the application more nuanced categorization may be desireable. In this example, perhaps the users want to categorize "Inactive" records by inactive for what reason (e.g. "In Progress", "Cancelled", "Obsolete"). All of these values are for system behavioral purposes "Inactive" but the extended information can help users understand why records have been made "Inactive", perhaps establishing a more complex life-cycle of record management.

If Functional Types have been defined for an Enum, each available value defined for the Enum must also be mapped to one of the Enum's Functional Types.

Enumeration Item (Enum Items)

These are the actual values which, when grouped together, define the available values in the list of values which the Enum represents. Enum Items establish the text displayed to the user, whether the Enum Item itself is system defined and/or user maintainable, and, if required by the Enum, what Functional Type is associated with the Enum Item.

If a Functional Type assignment is required by the parent Enum, the multiplicity of Enum Items to Functional Types is Zero or Many to One. This means that the system doesn't require that all defined Functional Types of an Enum be mapped to an Enum Item and that many Enum Items can refer to the same Functional Type.

Being able to assign multiple Enum Items to the same Functional Type allows for the fine grained information capture which might be desired for a particular parent record while invoking the same system functionality for multiple options.

Naturally, if a Functional Type has no associated Enum Items defined, that functionality will be unreachable by users of the application. This can be a desirable outcome in some business application scenarios.

Technical Implementation

Enums, Functional Types, and Enum Items are persisted in the database so that these configuration are durable. When the application starts, all of the Enum data is loaded into a GenServer backed ETS table. Processes will read Enums data directly from the ETS table as needed. Changes to the Enums are not directly written to the ETS table, but are processed by the GenServer which ensures that the changes are updated in the ETS table, but are also persisted to the database.

This design assumes that Enum data is read often, but changed infrequently.

Summary

Enumerations

Create a new user defined enumeration, optionally including functional type and enumeration item definitions.

Deletes a user defined enumeration and its child functional type and enumeration item records.

Returns true if the requested enumeration is system defined, false otherwise.

Returns true if the requested enumeration is user maintainable, false otherwise.

Retrieves all values associated with the requested enumeration.

Retrieves all values for all enumerations.

Changes the values of an existing enumeration.

Enumeration Functional Types

Creates a new user defined functional type.

Deletes a user defined enumeration functional type record.

Returns the internal name of the functional type to which the given Enum Item record belongs.

Returns the list of Enumeration Functional Types associated with the requested enumeration.

Change the values of an existing enumeration functional type record.

Enumeration items

Creates a new user defined enumeration item.

Deletes a user defined enumeration item record.

Finds the default enumeration item for the requested enumeration or for the enumeration functional type.

Returns an Enumeration Item record from the named Enumeration as identified by its id value.

Returns an Enumeration Item record from the named Enumeration as identified by its name.

Returns the list of Enumeration Items associated with the requested enumeration.

Returns the list of Enumeration Items associated with the requested enumeration sorted by their sort_order value.

Change the values of an existing enumeration item record.

Runtime

Returns a child specification for the Enumerations Service.

Retrieves the runtime configuration of a previously started Enumerations Service.

Retrieves the name of the currently set Enumerations Service instance.

Establishes the currently active Enumerations Service instance for the current process.

Starts an instance of the Enumerations Service.

Terminates a running instance of the Enums service.

Enumerations

create(enum_params)

@spec create(MscmpSystEnums.Types.enum_params()) ::
  :ok | {:error, Mserror.EnumsError.t()}

Create a new user defined enumeration, optionally including functional type and enumeration item definitions.

Parameters

Examples

iex> example_enumeration =
...>   %{
...>      internal_name: "example_create",
...>      display_name: "Create Example Enum",
...>      user_description: "Demonstrate enumeration creation.",
...>      functional_types: [
...>        %{
...>          internal_name: "example_create_functional_type",
...>          display_name: "Create Example Enum / Functional Type",
...>          external_name: "Functional Type",
...>          user_description: "Demonstrate Functional Type Creation"
...>        }
...>      ],
...>      enum_items: [
...>        %{
...>          internal_name: "example_create_item",
...>          display_name: "Create Example Enum / Enum Item",
...>          external_name: "Enum Item",
...>          user_description: "Demonstration of enumeration item creation.",
...>          enum_default: true,
...>          functional_type_default: false,
...>          functional_type_name: "example_create_functional_type"
...>        }
...>      ]
...>    }
iex> MscmpSystEnums.create(example_enumeration)
:ok

delete(enum_name)

@spec delete(MscmpSystEnums.Types.enum_name()) ::
  :ok | {:error, Mserror.EnumsError.t()}

Deletes a user defined enumeration and its child functional type and enumeration item records.

You cannot delete a system defined enumeration nor can you delete an enumeration that has been referenced in other application data records.

Parameters

  • enum_name - the enumeration which is to be deleted by the function.

get_syst_defined(enum_name)

@spec get_syst_defined(MscmpSystEnums.Types.enum_name()) :: boolean()

Returns true if the requested enumeration is system defined, false otherwise.

Parameters

  • enum_name - the name of the enumeration to test as being system defined.

Examples

iex> MscmpSystEnums.get_syst_defined("example_enumeration")
false

get_user_maintainable(enum_name)

@spec get_user_maintainable(MscmpSystEnums.Types.enum_name()) :: boolean()

Returns true if the requested enumeration is user maintainable, false otherwise.

Parameters

  • enum_name - the name of the enumeration to test as being user maintainable.

Examples

iex> MscmpSystEnums.get_user_maintainable( "example_enumeration")
true

get_values(enum_name)

Retrieves all values associated with the requested enumeration.

Parameters

  • enum_name - the name of the enumeration for which to retrieve values.

The successful return of this function is an instance of the Msdata.SystEnums struct containing the values requested.

Examples

iex> MscmpSystEnums.get_values("example_enumeration")

list_all()

@spec list_all() :: [Msdata.SystEnums.t()]

Retrieves all values for all enumerations.

This function returns all other enumeration metadata, such as the records' IDs, descriptions, etc. Also included is association data for the enum_items field and the functional_type association of each item.

Examples

iex> MscmpSystEnums.list_all()

set_values(enum_name, enum_params)

Changes the values of an existing enumeration.

You can change the following fields using the this function:

  • internal_name - Note that you cannot change the internal name of a system defined enumeration.

  • display_name

  • user_description

  • default_user_options

Other fields of the Msdata.SystEnums data type may not be modified via this module. Also note that only the enumeration value itself can be modified. Changes to functional type or enumeration item records must be addressed individually.

Parameters

  • enum_name - the enumeration which is being modified.

  • enum_params - a map of type MscmpSystEnums.Types.enum_params/0 which establishes the data values which are to be changed.

Enumeration Functional Types

create_functional_type(enum_name, functional_type_params)

Creates a new user defined functional type.

User defined functional types may only be added to user defined enumerations.

Parameters

  • enum_name - the Enumeration to which the new functional type will be a child.

  • functional_type_params - a map of type t:Types.enum_functional_type_params/0 which establishes the data values for the new functional type.

delete_functional_type(enum_name, functional_type_name)

Deletes a user defined enumeration functional type record.

You cannot delete a system defined functional type nor can you delete a functional type which is still referenced by enumeration item records.

Parameters

  • enum_name - the enumeration which is is the parent of the functional type to be deleted.

  • enum_functional_type_name- the target functional type of the delete operation.

get_functional_type_by_item_id(enum_name, enum_item_id)

Returns the internal name of the functional type to which the given Enum Item record belongs.

Parameters

  • enum_name - the name of the enumeration to which the Enum Item ID belongs.

  • enum_item_id - the record ID of the Enum Item record of interest.

Example

iex> example_enum_item = MscmpSystEnums.get_item_by_name(
...>   "example_enumeration",
...>   "example_enum_item_one")
iex> MscmpSystEnums.get_functional_type_by_item_id(
...>   "example_enumeration",
...>   example_enum_item.id)
"example_enum_func_type_1"

list_functional_types(enum_name)

@spec list_functional_types(MscmpSystEnums.Types.enum_name()) :: [
  Msdata.SystEnumFunctionalTypes.t()
]

Returns the list of Enumeration Functional Types associated with the requested enumeration.

Parameters

  • enum_name - the name of the enumeration for which to retrieve the list of enumeration functional types.

set_functional_type_values(enum_name, functional_type_name, functional_type_params)

Change the values of an existing enumeration functional type record.

The following fields may be changed using this function:

  • internal_name - Note that you cannot change the internal name of a system defined functional type.

  • display_name

  • external_name

  • user_description

Other fields of the Msdata.SystEnumFunctionalTypes data type may not be modified via this module.

Parameters

  • enum_name- the enumeration which is parent to the functional type being modified.

  • functional_type_name - the specific functional type which will be updated.

  • functional_type_params - a map of type MscmpSystEnums.Types.enum_functional_type_params/0 which establishes the data values which are to be changed.

Enumeration items

create_item(enum_name, enum_item_params)

Creates a new user defined enumeration item.

User defined enumeration items may be added to either user defined enumerations or system defined enumerations which are also marked user maintainable.

Parameters

  • enum_name -the enumeration to which the new enumeration item will be a child.

  • enum_item_params - a map of type MscmpSystEnums.Types.enum_item_params/0 which establishes the data values for the new enumeration item.

delete_item(enum_name, enum_item_name)

Deletes a user defined enumeration item record.

You cannot delete a system defined enumeration item nor can you delete an an enumeration item record which has been referenced in application data.

Parameters

  • enum_name - the enumeration which is is the parent of the enumeration item to be deleted.

  • enum_item_name - the target functional type of the delete operation.

get_default_item(enum_name, opts \\ [])

Finds the default enumeration item for the requested enumeration or for the enumeration functional type.

When no qualifying options are specified, this function will return the enumeration item record which is marked as being default for the enumeration. If the functional_type_name option is used, then the function returns the record which is marked as default for the functional type.

Parameters

  • enum_name- the name of the enumeration for which to retrieve the default enumeration item.

  • opts - a keyword list of optional values.

Options

  • :functional_type_name (String.t/0) - The Internal Name of the Enumeration's Functional Type.

Examples

iex> %Msdata.SystEnumItems{
...>   internal_name: "example_enum_item_two"
...> } =
...>   MscmpSystEnums.get_default_item("example_enumeration")

iex> %Msdata.SystEnumItems{
...>   internal_name: "example_enum_item_one"
...> } =
...>   MscmpSystEnums.get_default_item(
...>     "example_enumeration",
...>     [functional_type_name: "example_enum_func_type_1"]
...>   )

get_item_by_id(enum_name, enum_item_id)

@spec get_item_by_id(MscmpSystEnums.Types.enum_name(), Ecto.UUID.t()) ::
  Msdata.SystEnumItems.t() | nil

Returns an Enumeration Item record from the named Enumeration as identified by its id value.

Other than using a different identifier to locate the enumeration item record, this function behaves the same as get_enum_by_name/2.

Parameters

  • enum_name - the name of the Enumeration that is parent to the target Enumeration Item record.

  • enum_item_id - the id value of the Enumeration Item record to return.

get_item_by_name(enum_name, enum_item_name)

Returns an Enumeration Item record from the named Enumeration as identified by its name.

Parameters

  • enum_name - the name of the Enumeration that is parent to the target Enumeration Item record.

  • enum_item_name - the name of the Enumeration Item record to return.

Examples

iex> %Msdata.SystEnumItems{
...>   internal_name: "example_enum_item_one"
...> } =
...>   MscmpSystEnums.get_item_by_name(
...>     "example_enumeration",
...>     "example_enum_item_one"
...>   )

list_items(enum_name)

Returns the list of Enumeration Items associated with the requested enumeration.

Parameters

  • enum_name- the name of the enumeration for which to retrieve the list of enumeration items.

list_sorted_items(enum_name)

@spec list_sorted_items(MscmpSystEnums.Types.enum_name()) :: [
  Msdata.SystEnumItems.t()
]

Returns the list of Enumeration Items associated with the requested enumeration sorted by their sort_order value.

In all other regards this function works the same MscmpSystEnums.list_items/1.

set_item_values(enum_name, enum_item_name, enum_item_params)

Change the values of an existing enumeration item record.

The following fields may be changed using this function:

  • internal_name - Note that you cannot change the internal name of a system defined enumeration item.

  • display_name

  • external_name

  • user_description

  • enum_default

  • functional_type_default

  • sort_order

  • user_options

Other fields of the Msdata.SystEnumItems data type may not be modified via this module.

Parameters

  • enum_name - the enumeration which is parent to the enumeration item.

  • enum_item_name - the specific enumeration item which will be updated.

  • enum_item_params - a map of type MscmpSystEnums.Types.enum_item_params/0 which establishes the data values which are to be changed.

Runtime

child_spec(opts)

@spec child_spec(Keyword.t()) :: Supervisor.child_spec()

Returns a child specification for the Enumerations Service.

Parameters

  • opts - A keyword list of options.

Options

  • :datastore_context_name (GenServer.name/0 or nil) - Specifies the name of the Datastore Context to be used by the Enumerations Service.

  • :debug (boolean/0) - If true, the GenServer backing the Service will be started in debug mode.

  • :timeout (timeout/0) - Timeout value for the start_link call. The default value is :infinity.

  • :hibernate_after (timeout/0) - If present, the GenServer process awaits any message for the specified time before hibernating. The timeout value is expressed in milliseconds.

  • :service_name (GenServer.name/0 or nil) - Required. The name to use for the GenServer backing this specific Service instance.

Examples

iex> MscmpSystEnums.child_spec(
...>   service_name: MyApp.EnumsService,
...>   datastore_context_name: MyApp.DatastoreContext)
%{
  id: MscmpSystEnums,
  start:
    {MscmpSystEnums,
     :start_link,
     [[timeout: :infinity, service_name: MyApp.EnumsService, datastore_context_name: MyApp.DatastoreContext]]},
}

get_runtime_config()

@spec get_runtime_config() :: map() | nil

Retrieves the runtime configuration of a previously started Enumerations Service.

Some services need a mechanism to return features such as :ets table names which are set at runtime. This function provides the mechanism by which such runtime configuration can be returned.

Returns

Returns a map containing the runtime configuration of the currently active Enumerations Service, or nil if no service is currently set.

Examples

Getting runtime configuration from the current service:

iex> old_service = MscmpSystEnums.put_service(TestSupport.get_enums_service_name())
iex> config = MscmpSystEnums.get_runtime_config()
iex> %{enums_table: table_id} = config
iex> is_reference(table_id)
true
iex> MscmpSystEnums.put_service(old_service)
iex> :ok
:ok

get_service()

@spec get_service() :: MscmpSystService.Types.service_name()

Retrieves the name of the currently set Enumerations Service instance.

See put_service/1 for more information about setting an active Enumeration Service name.

Returns

Returns the name of the currently set Enumerations Service name or nil if no Enumerations Service name has been set.

Examples

Retrieving a specific Enumerations Service name:

iex> MscmpSystEnums.put_service(:"MscmpSystEnums.TestSupportService")
...> MscmpSystEnums.get_service()
:"MscmpSystEnums.TestSupportService"

Retrieving a specific Enumerations Service name when no value is currently set for the process:

iex> MscmpSystEnums.put_service(nil)
...> MscmpSystEnums.get_service()
nil

put_service(service_name)

Establishes the currently active Enumerations Service instance for the current process.

Parameters

  • service_name - the name under which the Enumerations Service is started and by which it may be referenced. This is any name that may be used to reference a GenServer process. Additionally, this value may be set nil to clear the currently set Enumerations Service name.

Returns

Returns the name of the previously set Enumerations Service name or nil if no Enumerations Service name had been previously set.

Examples

Setting a specific Enumerations Service name:

iex> MscmpSystEnums.put_service(:"MscmpSystEnums.TestSupportService")
...> MscmpSystEnums.get_service()
:"MscmpSystEnums.TestSupportService"

Clearing a previously set specific Service Name:

iex> MscmpSystEnums.put_service(nil)
...> MscmpSystEnums.get_service()
nil

start_link(opts)

@spec start_link(Keyword.t()) ::
  {:ok, pid()} | :ignore | {:error, Mserror.EnumsError.t()}

Starts an instance of the Enumerations Service.

Starting the service establishes the required processes and pre-populates the service cache with data from the database. Most other functions in this module require that the service is started prior to use and will fail if the service is not started.

Parameters

  • opts - Options for the Enumerations Service. See the Options section below for more information.

Options

  • :datastore_context_name (GenServer.name/0 or nil) - Specifies the name of the Datastore Context to be used by the Enumerations Service.

  • :debug (boolean/0) - If true, the GenServer backing the Service will be started in debug mode.

  • :timeout (timeout/0) - Timeout value for the start_link call. The default value is :infinity.

  • :hibernate_after (timeout/0) - If present, the GenServer process awaits any message for the specified time before hibernating. The timeout value is expressed in milliseconds.

  • :service_name (GenServer.name/0 or nil) - Required. The name to use for the GenServer backing this specific Service instance.

terminate_service()

@spec terminate_service() :: :ok

Terminates a running instance of the Enums service.

Examples

> MscmpSystEnums.terminate_service()
:ok