Add documentation + add `sameForVersion` function
parent
dbbd009a58
commit
1fcb754e55
|
@ -1,4 +1,4 @@
|
||||||
module Internal.Api.SendMessageEvent.V1.Api exposing (sendMessageEventV1, sendMessageEventV2, SendMessageEventOutputV1, SendMessageEventInputV1)
|
module Internal.Api.SendMessageEvent.Api exposing (sendMessageEventV1, sendMessageEventV2, SendMessageEventOutputV1, SendMessageEventInputV1)
|
||||||
|
|
||||||
import Internal.Api.Request as R
|
import Internal.Api.Request as R
|
||||||
import Internal.Api.SendMessageEvent.V1.SpecObjects as SO1
|
import Internal.Api.SendMessageEvent.V1.SpecObjects as SO1
|
||||||
|
|
|
@ -2,9 +2,6 @@ module Internal.Api.SendMessageEvent.Main exposing (..)
|
||||||
|
|
||||||
import Internal.Api.SendMessageEvent.Api as Api
|
import Internal.Api.SendMessageEvent.Api as Api
|
||||||
import Internal.Tools.VersionControl as VC
|
import Internal.Tools.VersionControl as VC
|
||||||
import Internal.Tools.Exceptions as X
|
|
||||||
import Task exposing (Task)
|
|
||||||
|
|
||||||
|
|
||||||
sendMessageEvent : List String -> Maybe (SendMessageEventInput -> SendMessageEventOutput)
|
sendMessageEvent : List String -> Maybe (SendMessageEventInput -> SendMessageEventOutput)
|
||||||
sendMessageEvent versions =
|
sendMessageEvent versions =
|
||||||
|
@ -12,78 +9,23 @@ sendMessageEvent versions =
|
||||||
{ current = Api.sendMessageEventV1
|
{ current = Api.sendMessageEventV1
|
||||||
, version = "r0.0.0"
|
, version = "r0.0.0"
|
||||||
}
|
}
|
||||||
|> VC.addMiddleLayer
|
|> VC.sameForVersion "r0.0.1"
|
||||||
{ downcast = identity
|
|> VC.sameForVersion "r0.1.0"
|
||||||
, current = Api.sendMessageEventV1
|
|> VC.sameForVersion "r0.2.0"
|
||||||
, upcast = identity
|
|> VC.sameForVersion "r0.3.0"
|
||||||
, version = "r0.0.1"
|
|> VC.sameForVersion "r0.5.0"
|
||||||
}
|
|> VC.sameForVersion "r0.6.0"
|
||||||
|> VC.addMiddleLayer
|
|> VC.sameForVersion "r0.6.1"
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV1
|
|
||||||
, upcast = identity
|
|
||||||
, version = "r0.1.0"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV1
|
|
||||||
, upcast = identity
|
|
||||||
, version = "r0.2.0"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV1
|
|
||||||
, upcast = identity
|
|
||||||
, version = "r0.3.0"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV1
|
|
||||||
, upcast = identity
|
|
||||||
, version = "r0.5.0"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV1
|
|
||||||
, upcast = identity
|
|
||||||
, version = "r0.6.0"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV1
|
|
||||||
, upcast = identity
|
|
||||||
, version = "r0.6.1"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|> VC.addMiddleLayer
|
||||||
{ downcast = identity
|
{ downcast = identity
|
||||||
, current = Api.sendMessageEventV2
|
, current = Api.sendMessageEventV2
|
||||||
, upcast = identity
|
, upcast = identity
|
||||||
, version = "v1.1"
|
, version = "v1.1"
|
||||||
}
|
}
|
||||||
|> VC.addMiddleLayer
|
|> VC.sameForVersion "v1.2"
|
||||||
{ downcast = identity
|
|> VC.sameForVersion "v1.3"
|
||||||
, current = Api.sendMessageEventV2
|
|> VC.sameForVersion "v1.4"
|
||||||
, upcast = identity
|
|> VC.sameForVersion "v1.5"
|
||||||
, version = "v1.2"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV2
|
|
||||||
, upcast = identity
|
|
||||||
, version = "v1.3"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV2
|
|
||||||
, upcast = identity
|
|
||||||
, version = "v1.4"
|
|
||||||
}
|
|
||||||
|> VC.addMiddleLayer
|
|
||||||
{ downcast = identity
|
|
||||||
, current = Api.sendMessageEventV2
|
|
||||||
, upcast = identity
|
|
||||||
, version = "v1.5"
|
|
||||||
}
|
|
||||||
|> VC.mostRecentFromVersionList versions
|
|> VC.mostRecentFromVersionList versions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
module Internal.Tools.DecodeExtra exposing (opField, opFieldWithDefault)
|
module Internal.Tools.DecodeExtra exposing (opField, opFieldWithDefault)
|
||||||
|
|
||||||
|
{-| Module that helps while decoding JSON.
|
||||||
|
|
||||||
|
|
||||||
|
# Optional field decoders
|
||||||
|
|
||||||
|
@docs opField, opFieldWithDefault
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
import Json.Decode as D
|
import Json.Decode as D
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
module Internal.Tools.EncodeExtra exposing (..)
|
module Internal.Tools.EncodeExtra exposing (maybeObject)
|
||||||
|
|
||||||
|
{-| Module that helps with encoding objects into JSON.
|
||||||
|
|
||||||
|
|
||||||
|
# Optional body object
|
||||||
|
|
||||||
|
@docs maybeObject
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
import Json.Encode as E
|
import Json.Encode as E
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
module Internal.Tools.VersionControl exposing
|
||||||
|
( VersionControl, withBottomLayer
|
||||||
|
, MiddleLayer, addMiddleLayer
|
||||||
|
, toDict, fromVersion, fromVersionList
|
||||||
|
, mostRecentFromVersionList, sameForVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
{-| This module helps you create multiple functions for different (spec) versions
|
||||||
|
while still having only one input, one output.
|
||||||
|
|
||||||
|
The module can be best described as a layered version type.
|
||||||
|
|
||||||
|
|----------------------------------------------|
|
||||||
|
| VersionControl |
|
||||||
|
| input output |
|
||||||
|
| | ^ |
|
||||||
|
|---------------------- | -------------- | ----|
|
||||||
|
| |
|
||||||
|
|---------------------- | -------------- | ----|
|
||||||
|
| MiddleLayer v3 | | |
|
||||||
|
| [---> current ---] |
|
||||||
|
| | | |
|
||||||
|
| downcast upcast |
|
||||||
|
| | ^ |
|
||||||
|
|---------------------- | -------------- | ----|
|
||||||
|
| |
|
||||||
|
|---------------------- | -------------- | ----|
|
||||||
|
| MiddleLayer v2 | | |
|
||||||
|
| [---> current ---] |
|
||||||
|
| | | |
|
||||||
|
| downcast upcast |
|
||||||
|
| | ^ |
|
||||||
|
|---------------------- | -------------- | ----|
|
||||||
|
| |
|
||||||
|
|---------------------- | -------------- | ----|
|
||||||
|
| BottomLayer v1 | | |
|
||||||
|
| \---> current ---/ |
|
||||||
|
| |
|
||||||
|
|----------------------------------------------|
|
||||||
|
|
||||||
|
This method means you will only need to write one downcast, one current and one upcast
|
||||||
|
whenever you introduce a new version. This means you can instantly update all functions
|
||||||
|
without having to write every version!
|
||||||
|
|
||||||
|
The VersionControl keeps a `Dict` type but also tracks the version order.
|
||||||
|
This way, you can either get the VersionControl type to render the function for
|
||||||
|
the most recent supported version, or you can choose for yourself which version
|
||||||
|
you prefer to use.
|
||||||
|
|
||||||
|
|
||||||
|
# Making VersionControl
|
||||||
|
|
||||||
|
@docs VersionControl, withBottomLayer
|
||||||
|
|
||||||
|
|
||||||
|
# Adding more versions
|
||||||
|
|
||||||
|
@docs MiddleLayer, addMiddleLayer
|
||||||
|
|
||||||
|
|
||||||
|
# Getting functions
|
||||||
|
|
||||||
|
@docs toDict, fromVersion, mostRecentFromVerionList, fromVersionList
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Dict exposing (Dict)
|
||||||
|
|
||||||
|
|
||||||
|
{-| The bottom layer is the final version option.
|
||||||
|
|
||||||
|
If even this version is not approved, there will be no function to execute.
|
||||||
|
|
||||||
|
-}
|
||||||
|
type alias BottomLayer cin cout =
|
||||||
|
{ current : cin -> cout, version : String }
|
||||||
|
|
||||||
|
|
||||||
|
{-| The middle layer is an optional function to execute.
|
||||||
|
|
||||||
|
If the version is approved, it is executed - otherwise, the next version will be considered.
|
||||||
|
|
||||||
|
-}
|
||||||
|
type alias MiddleLayer cin cout din dout =
|
||||||
|
{ current : cin -> cout
|
||||||
|
, downcast : cin -> din
|
||||||
|
, upcast : dout -> cout
|
||||||
|
, version : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| The VersionControl layer is the layer that keeps track of all potential versions.
|
||||||
|
-}
|
||||||
|
type VersionControl cin cout
|
||||||
|
= VersionControl
|
||||||
|
{ latestVersion : cin -> cout
|
||||||
|
, order : List String
|
||||||
|
, versions : Dict String (cin -> cout)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Add an extra version to the VersionControl. This will completely change the input and output
|
||||||
|
of every function, as all functions will abide by the most recent version's specifics.
|
||||||
|
-}
|
||||||
|
addMiddleLayer : MiddleLayer cin cout din dout -> VersionControl din dout -> VersionControl cin cout
|
||||||
|
addMiddleLayer { current, downcast, upcast, version } (VersionControl d) =
|
||||||
|
VersionControl
|
||||||
|
{ latestVersion = current
|
||||||
|
, order = version :: d.order
|
||||||
|
, versions =
|
||||||
|
d.versions
|
||||||
|
|> Dict.map (\_ f -> downcast >> f >> upcast)
|
||||||
|
|> Dict.insert version current
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Provided that a version has been passed to the VersionControl, you will receive the appropriate version.
|
||||||
|
-}
|
||||||
|
fromVersion : String -> VersionControl a b -> Maybe (a -> b)
|
||||||
|
fromVersion version (VersionControl { versions }) =
|
||||||
|
Dict.get version versions
|
||||||
|
|
||||||
|
|
||||||
|
{-| Provided a list of versions, this function will provide a list of compatible versions to you in your preferred order.
|
||||||
|
|
||||||
|
If you just care about getting the most recent function, you will be better off using `mostRecentFromVersionList`,
|
||||||
|
but this function can help if you care about knowing which Matrix spec version you're using.
|
||||||
|
|
||||||
|
-}
|
||||||
|
fromVersionList : List String -> VersionControl a b -> List ( String, a -> b )
|
||||||
|
fromVersionList versionList vc =
|
||||||
|
List.filterMap
|
||||||
|
(\version ->
|
||||||
|
vc
|
||||||
|
|> fromVersion version
|
||||||
|
|> Maybe.map (\f -> ( version, f ))
|
||||||
|
)
|
||||||
|
versionList
|
||||||
|
|
||||||
|
|
||||||
|
{-| Get a dict of all available functions.
|
||||||
|
-}
|
||||||
|
toDict : VersionControl a b -> Dict String (a -> b)
|
||||||
|
toDict (VersionControl d) =
|
||||||
|
d.versions
|
||||||
|
|
||||||
|
|
||||||
|
{-| Get the most recent event based on a list of versions.
|
||||||
|
-}
|
||||||
|
mostRecentFromVersionList : List String -> VersionControl a b -> Maybe (a -> b)
|
||||||
|
mostRecentFromVersionList versionList ((VersionControl { order }) as vc) =
|
||||||
|
order
|
||||||
|
|> List.filter (\o -> List.member o versionList)
|
||||||
|
|> List.filterMap (\v -> fromVersion v vc)
|
||||||
|
|> List.head
|
||||||
|
|
||||||
|
{-| Sometimes, no changes are needed and a function works just the same as the one in the previous version.
|
||||||
|
In that case, you can amend with a `sameForVersion` function to indicate that the spec is
|
||||||
|
identical for this version.
|
||||||
|
-}
|
||||||
|
sameForVersion : String -> VersionControl a b -> VersionControl a b
|
||||||
|
sameForVersion version (VersionControl data) =
|
||||||
|
VersionControl
|
||||||
|
{ data
|
||||||
|
| order = version :: data.order
|
||||||
|
, versions = Dict.insert version data.latestVersion data.versions
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| You cannot create an empty VersionControl layer, you must always start with a BottomLayer
|
||||||
|
and then stack MiddleLayer types on top until you've reached the version that you're happy with.
|
||||||
|
-}
|
||||||
|
withBottomLayer : BottomLayer a b -> VersionControl a b
|
||||||
|
withBottomLayer { current, version } =
|
||||||
|
VersionControl
|
||||||
|
{ latestVersion = current
|
||||||
|
, order = List.singleton version
|
||||||
|
, versions = Dict.singleton version current
|
||||||
|
}
|
Loading…
Reference in New Issue