jvans
jvans

Reputation: 2915

Using type safe routes with persistent datatypes in snap

I have a Snap application using Persistent for storage and I'm trying to generate type safe routes for data types defined in Persistent. I'm using the snap-web-routes package:.

I have the following Template Haskell function that creates the data type of Group and GroupId:

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
  Group
    name T.Text
    deriving Show
|]

In my Application.hs I have:

data AppUrl = AddLink GroupId deriving (Eq, Show, Read, Generic)

The doc's suggest that:

instance PathInfo AppUrl

is all i need to do given the Generic derivation above however this blows up with

No instance for (PathInfo (KeyBackend SqlBackend Group))
      arising from a use of ‘Web.Routes.PathInfo.$gdmtoPathSegments’

My assumption is that this error indicates that Haskell does not know how to auto create the instance definition with Persistent's data types.

My next attempt was to manually define the instance:

instance PathInfo AppUrl where
  toPathSegments   (AddLink groupId) = "add-link" : toPathPiece groupId : []
  fromPathSegments (x:y:[]) = ????

I can't seem to figure out how to construct the GroupId data type.

From Yesod's excellent Persistent tutorial I know that the datatype is defined as:

type GroupId = Key Group
newtype Key Group = GroupKey (BackendKey SqlBackend)

But then I run into a problem because BackendKey is not exposed so I can't import it and create my own instance. I can't seem to find a public API to create this data type in Persistent.

Upvotes: 2

Views: 149

Answers (1)

Cactus
Cactus

Reputation: 27626

The documentation for SqlBackend shows that the associated datatype BackendKey is instanciated for SqlBackend as

data BackendKey SqlBackend = SqlBackendKey {
    unSqlBackendKey :: Int64
}

Which should be enough information to write your own PathInfo instance, along the lines of the following example:

{-# LANGUAGE TypeFamilies #-}

import Database.Persist.Sql
import Data.Int (Int64)

foo :: BackendKey SqlBackend -> Int64
foo (SqlBackendKey key) = key

bar :: Int64 -> BackendKey SqlBackend
bar = SqlBackendKey

Upvotes: 1

Related Questions