Some Plumbing Fixes

June 30, 2010

GravatarBy Michael Snoyman

As I've said, the main feature goal for the 0.4.0 release of Yesod is widgets. However, before I get started on that feature, there's a number of issues that I wanted to address. These are improvements that introduce breaking changes in the API, and so must wait for a major release.

persistent: split up PersistEntity

Version 0.0.0 of persistent had a typeclass called PersistEntity. Without getting into details, this typeclass essentially defined exactly how a datatype could be persisted to a particular database. Some advantages to this approach are:

  • You could have any datatype for the key that the backend required.
  • In theory, any backend could be written; it just required some template haskell code.

However, there are some major disadvantages to this approach:

  • It requires a large amount of template haskell code.
  • A datatype could only have a single PersistEntity instance, meaning it could only be persisted to a single backend.
  • Type signatures could become appallingly difficult.

So instead, persistent 0.1.0 will split up the work into two type classes: PersistEntity and PersistBackend. The former gives information on a datatype, such as what columns exist, how it can be sorted, unique keys, etc. It contains nothing backend specific. The latter typeclass is for each backend- like Sqlite and Postgresql. It is implemented without any TH code.

One downside is that a new backend must deal with the information provided by the PersistEntity typeclass. If it needs extra information that's not there, it won't work. I'm not so worried about this one, since I'm currently the only backend writer, and if someone else wants to write a backend that requires more information than is currently available in PersistEntity, I can just add it later.

The other downside is that database keys are all required to be Int64s. In practice, I don't think this is a problem at all: the only backend I know of that would really prefer a different key is Amazon SimpleDB, and even there I'm sure an Int64 would work.

web-routes-quasi: major overhaul

When Jeremy Shaw put together web-routes, I thought that web-routes-quasi would interact with it very well. Unfortunately, as the complexity of the package began to grow, I realized that it was really just becoming tailor-made for Yesod. This was a sub-optimal situation. And each new release of web-routes-quasi just added more Yesod-specific features.

This release (0.5.0) will be different. It no longer defines a QuasiSite datatype; we reuse the Site datatype from web-routes. It also cleanly exposes different TH functions for the four relevant declarations it provides for: creating the type-safe URL datatype, the parse function, the render function and the dispatch function.

The main reason I decided to start on this rewrite is to allow the dispatch function to return values still inside the Handler monad. Previously, web-routes-quasi would unwrap that monad itself, using a provided explode function. The plus was this provided a nice way to deal with the difference in type signature to subsite handlers (GHandler sub master) and master site handlers (GHandler master master); unfortunately, it made it difficult to provide features like authorization.

So now web-routes-quasi simply promotes the subsite handler functions into master site handler function. It needs three pieces of information to do this:

  • The master site argument to subsite argument conversion function.
  • The subsite route to master site route constructor.
  • The subsite route that was created.

The first of these is provided by the user when declaring routes; the last two are handled automatically by web-routes-quasi.

yesod: No more ContT

It seems now that migrating over to ContT for the Handler monad was a mistake. In particular, it has a broken MonadCatchIO instance, which leads to a number of annoying bugs (seg faults in sqlite because it double-frees memory). Of course, I still hate the ErrorT transformer, both for the super-class requirement and the orphan Monad instance.

So I've created a new package: neither. I originally thought of the name as a joke; in fact, my wife (a Greek/Latin major) helped me come up with a great datatype:

data Neither a b = Sinister a | Dexter b

However, it now provides three useful datatypes: AEither for an applicative-style either type, which combines Lefts via mappend; MEither for a monad instance; and MEitherT for a monad transformer. And you can use them all without any orphan instances. It also provides both mtl and transformers instances of MonadIO, MonadTrans and MonadCatchIO.

Also, as a result of really hideous error messages, I've switched GHandler to be a newtype instead of a type.

yesod TODO: merge Yesod.Form and Yesod.Formable

These two modules currently provide related functionality: the former is for getting GET and POST parameters without generating HTML forms. The latter is for generating HTML forms and automated parsing of POST parameters. It shouldn't be too difficult to combine the two together.

Other changes

I've added Facebook support to the authenticate repo, and passed that support up to the Yesod.Helpers.Auth module. It keeps track of the access token for you, so you can easily make requests against the Facebook graph API.


comments powered by Disqus