-
Notifications
You must be signed in to change notification settings - Fork 57
Migrating from Heist 0.12 to 0.13
The biggest change in 0.13 is that all the splice type signatures change.
[(Text, a)]
becomes
Splices a
We did this because a list really isn't the proper representation of splices because it doesn't have the right semantics. A list doesn't define behavior for repeated keys. What we really want is a map. Also, the syntax for lists of isn't all that great. The Splices data type gives provides a more concise way of defining splices while at the same time making semantics explicit.
The old syntax looked like this:
userISplices AuthUser{..} =
[ ("userId", I.textSplice $ maybe "-" unUid userId)
, ("userLogin", I.textSplice userLogin)
, ("userEmail", I.textSplice $ fromMaybe "-" userEmail)
]
With the Splices
data type, it becomes this:
userISplices AuthUser{..} = do
"userId" ## I.textSplice (maybe "-" unUid userId)
"userLogin" ## I.textSplice userLogin
"userEmail" ## I.textSplice (fromMaybe "-" userEmail)
The ##
function forces the splice to be inserted even if that splice has already been defined. There is also another function #?
that does not overwrite an existing splice. A third function #!
calls error of the splice already exists. This is useful for getting early warning if you're unknowingly overwriting splices.
Before, if you used the ++
operator to concatenate lists of splices, you'll have to change that to the appropriate unionWith
or mappend
. The list cons function :
should be replaced by insert
. Any use of an empty list of splices should change to noSplices
or mempty
.
The compiled splice API changed drastically. We developed a high level compiled splice API that does not use the Promise
type at all. Some of the existing higher level functions changed or disappeared. If you were doing anything that relied on manual use of the Promise
type, we highly recommend trying to reformulate to use our high level API. However there are some things that still require using Promise
directly. If you need that, you can import the Heist.Compiled.LowLevel
module.
We removed most of the functions that operated on lists of splices if there was also a version that operated on a single splice. This simplifies the API. It is a little more verbose than before, but we're trying to find the right balance of convenience and API complexity.
pureSplices
and textSplices
---> mapS pureSplice
and mapS textSplice
In general, any occurrence of Promise a
will become RuntimeSplice m a
.
Promise a -> C.Splice m
becomes RuntimeSplice m a -> C.Splice m
If you had a code snipped like this in 0.12...
foo :: Promise Blah -> C.Splice m
foo blahPromise = return $ yieldRuntime $ do
v <- getPromise blahPromise
...
bar = do
p <- newEmptyPromise
...
foo p
...it would look something like this in 0.13
foo :: RuntimeSplice m Blah -> C.Splice m
foo getBlah = return $ yieldRuntime $ do
v <- getBlah
...
bar = do
p <- newEmptyPromise
...
foo (getPromise p)
And depending on what you were doing, you might not even need to create a Promise
in bar
. The most likely scenario is that you would have some function in your runtime monad that returns a Blah. In that case it's even easier:
blahMaker :: m Blah
bar = do
...
foo (lift blahMaker)
The promiseChildren
function is a combination of runChildren and codeGen.
Any uses of the defer
function will usually just disappear (modulo the correct changes everywhere else).