我有一个表示持久化记录的类型.我想有一个非常相似的类型,表示应该发布的数据,以创建新的记录.

这是完整的类型:

data Record = Reading
  { id: UUID
  , value: String
  ...
  }

除了将由数据库自动生成的"id"之外,"new"类型是相同的.我如何定义这种类型?我正在使用Servant来定义API.

我目前的策略是在类型和所有字段前加上"new"前缀,这是可行的,但对于多字段模型是不必要的.我还看到了嵌套策略,其中我有一个公共的共享类型.我也考虑过将ID设置为可选,但我真的不想发布它.

推荐答案

您可以使用类似于Higher Kinded Data的方法来实现这一点.

首先,一些进口:

{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
module Example where

import Data.Functor.Identity
import Data.Proxy
import Data.UUID 
import Data.Aeson
import GHC.Generics

然后,使用更高的同类类型参数定义记录:

data Record f = Record  { recordId :: f UUID, recordValue :: String } deriving (Generic)

Identity Functor给你的是这个记录的一个变体,always has是一个ID.

type RecordWithId = Record Identity

使用Maybe会给出一个ID为optional的变量.

type RecordWithOptionalId = Record Maybe 

Proxy可以用作具有单个不感兴趣的"单位"值的函数值.(并且没有包装类型的值).这使我们可以为没有ID的Record创建一个类型.

type RecordWithoutId = Record (Proxy)

我们的Record可以得到Show.

deriving instance (Show (f UUID)) => Show (Record f)

正如您所预期的那样,需要在Aeson instances中传递omitNothingFields = TrueallowOmitedFields = True才能解析RecordWithoutId.这确实需要一个版本的Aeson&>=2.2.0.0(在 compose 本文时,该版本比最新的Stackage Snapshot更新).如果此版本绑定不适用于您,您可能可以手动实现Aeson实例.

instance (ToJSON (f UUID)) => ToJSON (Record f) where
    toJSON = genericToJSON defaultOptions { omitNothingFields = True, allowOmitedFields = True }

instance (FromJSON (f UUID)) => FromJSON (Record f) where
    parseJSON = genericParseJSON defaultOptions { omitNothingFields = True, allowOmitedFields = True }

使用ID编码值:

ghci> import qualified Data.ByteString.Lazy.Char8 as BL
ghci> BL.putStrLn $ encode (Record {recordId = Identity nil, recordValue = "value" })
{"recordId":"00000000-0000-0000-0000-000000000000","recordValue":"value"}

对没有ID的值进行编码:

ghci> BL.putStrLn $ encode (Record {recordId = Proxy, recordValue = "value" })
{"recordValue":"value"}

对没有ID的值进行解码

ghci> decode "{\"recordValue\":\"value\"}" :: Maybe RecordWithoutId
Just (Record {recordId = Proxy, recordValue = "value"})

Postgresql相关问答推荐

为什么更新不设置较晚的结束时间?

让Docker Compose Container等待容器PostgreSQL并恢复

如何返回old_ids和重复行的映射';来自PostgreSQL函数的s new_id

是否可以在 postgres jsonb 列中的列表上创建索引

pgadmin db 限制服务器属性不起作用

Postgres 唯一 JSON 数组聚合值

PostgreSQL:please specify covering index name是什么意思

全文搜索(Postgres)与Elastic search

PostgreSQL 中基于时间戳的移动平均线

PostgreSQL 中的 DATEADD 等效项

在 PostgreSQL 中表示Sparse稀疏数据

Postgres 外键on update和on delete选项如何工作?

Rails 验证数组中的值

在 PostgreSQL 中的表上禁用 DELETE?

PostgreSQL 表变量

使用 Hibernate 注释映射 PostgreSQL 串行类型

如何在 JPA 中使用 Postgres JSONB 数据类型?

提高查询速度:simple SELECT in big postgres table

如何为本地 Rails 元素设置 Postgres 数据库?

如何在 PostgreSQL 中获取数组的最后一个元素?