Haskell Servant中如何为含Vector字段的类型同时派生FromRow与FromForm?
解决方案
针对你遇到的Vector String无法同时满足FromRow(postgresql-simple)和FromForm(Servant)的问题,有以下几种可行方案:
方案一:自定义Vector String的FromHttpApiData实例
既然[String]已经有现成的FromHttpApiData实例,我们可以基于它实现Vector String的实例,直接复用List的解析逻辑再转成Vector:
import Data.Vector (Vector) import qualified Data.Vector as V import Web.HttpApiData (FromHttpApiData(..)) instance FromHttpApiData (Vector String) where parseQueryParam = fmap V.fromList . parseQueryParam parseUrlPiece = fmap V.fromList . parseUrlPiece parseHeader = fmap V.fromList . parseHeader
实现这个实例后,你就可以为Reading派生Generic的FromForm实例了,所有字段的类型都满足FromHttpApiData要求。
方案二:参数化Reading类型的authors字段
通过将authors的类型抽象为参数,你可以分别为数据库和API场景定义专用的类型别名,并派生对应的实例:
import Data.Vector (Vector) import qualified Data.Vector as V import Web.FormUrlEncoded (FromForm) import Database.PostgreSQL.Simple.FromRow (FromRow) import Data.Time.Calendar (Day) data Reading a = Reading { title :: String , authors :: a , startDate :: Day , endDate :: Maybe Day } deriving (Eq, Show, Generic) -- 数据库操作专用类型,派生FromRow type DbReading = Reading (Vector String) deriving instance FromRow DbReading -- API表单专用类型,派生FromForm type ApiReading = Reading [String] deriving instance FromForm ApiReading
在API端点使用ApiReading接收请求,之后通过V.fromList将[String]转换为Vector String,再构造DbReading存入数据库;反之从数据库读取时,也可以用V.toList转换为List用于API响应。
方案三:直接使用[String]同时满足两个需求
实际上postgresql-simple的FromRow完全支持[String]类型——它会自动将PostgreSQL的数组类型映射为Haskell的List。如果你没有必须使用Vector的特殊需求(比如性能优化、特定容器操作),直接把authors的类型改为[String]是最简洁的方案:
data Reading = Reading { title :: String , authors :: [String] , startDate :: Day , endDate :: Maybe Day } deriving (Eq, Show, Generic, FromRow, FromForm)
这样无需额外代码,就能同时派生FromRow和FromForm实例,完美适配数据库和API场景。
内容的提问来源于stack exchange,提问作者Razumov
相关产品推荐
相关产品推荐

