在 snap 中使用具有持久数据类型的类型安全路由

Posted

技术标签:

【中文标题】在 snap 中使用具有持久数据类型的类型安全路由【英文标题】:Using type safe routes with persistent datatypes in snap 【发布时间】:2015-08-08 22:36:15 【问题描述】:

我有一个使用 Persistent 进行存储的 Snap 应用程序,我正在尝试为 Persistent 中定义的数据类型生成类型安全的路由。我正在使用snap-web-routes package:。

我有以下创建GroupGroupId 数据类型的模板Haskell 函数:

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

在我的Application.hs 我有:

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

文档建议:

instance PathInfo AppUrl

考虑到上面的Generic 推导,我需要做的只是这件事

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

我的假设是这个错误表明 Haskell 不知道如何使用 Persistent 的数据类型自动创建实例定义。

我的下一个尝试是手动定义实例:

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

我似乎无法弄清楚如何构造 GroupId 数据类型。

从Yesod的优秀Persistent tutorial我知道数据类型定义为:

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

但后来我遇到了一个问题,因为BackendKey 没有公开,所以我无法导入它并创建自己的实例。我似乎找不到在 Persistent 中创建这种数据类型的公共 API。

【问题讨论】:

【参考方案1】:

The documentation for SqlBackend 表明关联的数据类型 BackendKey 被实例化为 SqlBackend as

data BackendKey SqlBackend = SqlBackendKey 
    unSqlBackendKey :: Int64

按照以下示例的思路编写您自己的PathInfo 实例应该是足够的信息:

-# LANGUAGE TypeFamilies #-

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

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

bar :: Int64 -> BackendKey SqlBackend
bar = SqlBackendKey

【讨论】:

数据类型是类私有的,没有暴露,所以我不能真正导入它。 @jvans:不,你为什么会这样想?我在回答中添加了一个小例子。 啊不知道我为什么这么想。一定是误读了错误信息。感谢您的帮助!

以上是关于在 snap 中使用具有持久数据类型的类型安全路由的主要内容,如果未能解决你的问题,请参考以下文章

第六阶段·数据库MySQL及NoSQL实践 第2章·Redis

Yesod 持久代码的类型类约束

具有核心数据的多个持久性存储

RabbitMQ集群

具有 Mysql JSON 类型的 Spring Data

具有实体框架和空间数据的持久无知域