DEPRECATED - Please see elm-slate/command
Provides helper functions for writing Slate Entity Command Processors.
Since the Elm Package Manager doesn't allow for Native code and most everything we write at Panoramic Software has some native code in it, you have to install this library directly from GitHub, e.g. via elm-github-install or some equivalent mechanism. It's just not worth the hassle of putting libraries into the Elm package manager until it allows native code.
The Command Procesor
is the main engine for processing Commands
in Slate
.
A Command
is typically the output of an API. It consists of the following:
- A list of events in their JSON format
- OPTIONAL list of entity ids to lock
- OPTIONAL Validator Tagger
A single Command
can optionally lock one or more entities, optionally perform a validation via the Slate Query Engine, and upon successful validation, write multiple events to the Slate database. These events are written contigously since blocks of events written to the Slate database are done serially.
Locking entities and validation are mutually dependent, i.e. they both exist or neither. Any other configuration will result in a crash.
There are many times that the Command Processor
will crash when something goes wrong. This is to prevent mistakes in programming corrupting a WRITE-ONCE-READ-MANY database.
Deletes and Updates are not allowed in Slate's database. So we must take great care when writing to the database, because once written, it's there forever.
The idea of making Impossible States Impossible won't work everywhere in Slate. This idea is great but doesn't work when you're dealing on the borders of the Functional and the Non-functional world, e.g. Slate code and the database.
The mapping of Elm records to JSON data stored in the Slate database will eventually involve a String. This mapping can't be validated by the compiler because it's not Elm.
Code has been employed to crash BEFORE inconsistent data can be written to the Slate database or if an API is validating without locking, etc.
Imagine a case where a Bank Account Entity
has a Command to withdraw
money from the account. Here's a case where you want to validate that the account has enough money in it.
But to do so would involve reading many records from the database most likely using the Slate Query Engine. Certainly, not a simple function call.
So a Validator Tagger
is passed to delegate this complex process to the Parent
of the Command Processor
module. The Parent
could and should delegate this to another module since there are many states and perhaps many asynchronous calls involved in retreiving the data necessary to validate a single Command.
When the overhead to retrieve validation data is high, caching can be employed, making a separate Validation Module
even more attractive.
Parent's Tagger that will result in calling this modules update function.
type alias RouteToMeTagger msg =
Msg -> msg
Tagger for command errors.
type alias CommandErrorTagger msg =
( CommandId, String ) -> msg
Tagger for command success.
type alias CommandSuccessTagger msg =
CommandId -> msg
Command Processor's Config
type alias Config msg =
{ routeToMeTagger : RouteToMeTagger msg
, errorTagger : ErrorTagger ( CommandId, String ) msg
, logTagger : LogTagger ( CommandId, String ) msg
, commandErrorTagger : CommandErrorTagger msg
, commandSuccessTagger : CommandSuccessTagger msg
}
Initialize command helper
init : Config msg -> ( Model msg, Cmd msg )
init config
Process command.
process : Config msg -> DbConnectionInfo -> Maybe (ValidateTagger Msg msg) -> List String -> List EntityReference -> Model msg -> ( Model msg, Cmd msg, CommandId )
process config dbConnectionInfo maybeValidateTagger lockEntityIds events model
See slate-test-entities. In particular, Test.App
.