Migrating between two Components

0 views
Skip to first unread message

Gísli Kristjánsson

unread,
Nov 9, 2009, 5:47:00 PM11/9/09
to HAppS
Hi everyone,

I have not found this question asked before but I might be mistaken -
so I'm sorry if I'm repeating a question to which the answer is a
general knowledge.

I'm trying to split my AppState into two Components. So before I had:

instance Component AppState where
type Dependencies AppState = End
initialValue = AppState {
blogs = [],
....

Now what I want to do is create a special Component for blogs like
this:

instance Component AppState where
type Dependencies AppState = Blogs :+:End
initialValue = AppState {
....


instance Component Blogs where
type Dependencies Blogs = End
initialValue = []

The question is how do I migrate between these two components?

stepcut

unread,
Nov 9, 2009, 6:12:42 PM11/9/09
to HAppS
As far as I know, there is not especially fancy way of doing this.

What I do is make a special version of my app that haskell the old
AppState, the new AppState and the Blogs components.
The special version simple:
1. starts up and loads the state into the old AppState
2. runs code I wrote which copies the data from old AppState to new
AppState and Blogs
3. creates a checkpoint
4. shutsdown

After that I can run a normal version of my app that just has new
AppState and Blogs.

it would be nice if there was something more elegant in place, but
this does the job for now. The problem is that it doesn't work well
for projects like gitit. That is because gitit users will expect to
just get a new version from upstream and have migration happen
automatically.

- jeremy

Gísli Kristjánsson

unread,
Nov 9, 2009, 6:37:46 PM11/9/09
to HAppS
Thanks Jeremy. Seems logical.

One question though. With this method you lose the possibility of auto-
migrating from whatever version your data is in to the latest version.
Does it make sense to have external "migrators" to declutter your
(Data) Models.

I don't have many versions of my Models but I'm seeing a very scary
future with too many files for every Model where it's going to be very
hard to figure out what changed where. I've even thought about some
sort of serializer to JSON/XML/... files (just in case) because I
don't fully trust the black-box-magic of Happstack-Data. That way I'll
at least have a away to transform my data into whatever structure
should something happen. How does that strike you?

stepcut

unread,
Nov 10, 2009, 3:05:32 PM11/10/09
to HAppS
Hello,

You do lose the possibility of auto-migration across the component
changes. I have not thought about it very hard, but I believe that is
mostly due to no one having writing code to handle this case yet. I
don't believe it is a fundamentally undoable thing.

You could use external migrators if you want. The solution I proposed
is really just an external migrator I believe?

Figuring out how to manage your migration history over large, long-
term projects is an area that could use more brain power. Happstack
provides the low-level functionality needed (though it is missing the
cross component migration), but effective policies and helpers for
making state migration easier are still needed. I know of 3 different
policies/systems, but none of them make me happy at the moment.

Back in the day, the checkpoint files were actually serialized as XML.
But that code has disappeared. If you use deriveNewData or deriveAll
so that all your State types are instances of Default and syb-with-
class then there are a few ways you could go about export XML or
JSON.

For XML you can use the existing toXml functionality:

{-# LANGUAGE DeriveDataTypeable, FlexibleInstances,
MultiParamTypeClasses, FlexibleContexts, TemplateHaskell,
UndecidableInstances #-}
module X where

import Happstack.Data
import Happstack.State

$(deriveAll [''Eq, ''Ord, ''Read, ''Show, ''Default]
[d|
data Foo = Foo X | Bar Int
data X = X String
|])

export :: Foo -> IO ()
export foo = putStrLn $ toString $ toXml foo

example output:

*X Control.Monad> export (Foo (X "hi"))
<foo haskellTypeVersion="0" haskellType="Foo"
><x haskellTypeVersion="0" haskellType="X"
><![CDATA[hi]]></x></foo>
*X Control.Monad>

Should be possible to implement a similar thing for JSON as well. You
would then just add something to your app which does an 'ask' on the
current state, and then calls export to save it.

The other option is to implement a new saver which saves the data as
XML instead of serialized byte strings. It would be similar to:

happstack/happstack-state/src/Happstack/State/Saver/Impl/File.hs

except that it would use XML instead of Binary.

Hope this gets you started! Thanks for your help!

- jeremy
Reply all
Reply to author
Forward
0 new messages