如何创建类似于此ADTs
的 Yesod Persistent 实体:
import Data.Ratio
data Work = Work { name :: String
, payment :: WorkPayment
, duration :: WorkDuration }
data WorkPayment = WorkPaymentUndefined
| WorkPaymentEstimated { workPaymentEstimatedUnity :: TemporalUnity
, workPaymentEstimatedValue :: Ratio Int }
| WorkPaymentTotal { workPaymentTotalValue :: Ratio Int }
data WorkDuration = WorkDurationUndefined
| WorkDurationEstimated { workDurationEstimatedUnity :: TemporalUnity
, workDurationEstimatedQuantity :: Int }
| WorkDurationPermanent
data TemporalUnity = Hour | Day | Week | Month
使用分离的模块可以避免使用长名称,但我更喜欢将它们放在一起用于此示例。
对于简单的Enums
来说,这看起来非常简单,但我无法弄清楚这种情况下的表格如同像MySQL这样的关系数据库
答案 0 :(得分:1)
要使用Persistent存储ADT,您只需要告诉Persistent如何从数据库序列化/反序列化该值。为此,请将其设为PersistField
的实例(将其转换为基本类型,如Text
或ByteString
)和PersistFieldSql
(以指定数据库的类型)要使用的栏目。)
您可以选择(反)序列化数据。我想编码/解码到二进制值会更快,但我推荐JSON,因为:
to/fromPersistValueJSON
。以下是一个例子:
-- Add this extension to derive To/FromJSON instances; see Data.Aeson for details
{-# LANGUAGE DeriveGeneric #-}
module Models.Work where
import Database.Persist.Sql (PersistFieldSql(..))
import ClassyPrelude.Yesod
import Data.Aeson
data TemporalUnity = Hour | Day | Week | Month deriving (Generic)
instance FromJSON TemporalUnity
instance ToJSON TemporalUnity
data WorkDuration = WorkDurationUndefined
| WorkDurationEstimated { workDurationEstimatedUnity :: TemporalUnity
, workDurationEstimatedQuantity :: Int }
| WorkDurationPermanent deriving (Generic)
instance FromJSON WorkDuration
instance ToJSON WorkDuration
-- Store the values as as SqlString. The actual column type will be dependent on the database backend. SqlString will be something like varchar/text types.
-- You can also use PersistByteString, which might be faster
instance PersistFieldSql WorkDuration where
sqlType _ = SqlString
instance PersistField WorkDuration where
toPersistValue = toPersistValueJSON
fromPersistValue = fromPersistValueJSON
以下是从Postgres中选择的内容:
foo=# SELECT * FROM "user";
id | ident | password | duration
----+--------+----------+-------------------------------------------------------------------------------------------------------
5 | foo123 | | {"tag":"WorkDurationPermanent","contents":[]}
6 | bar456 | | {"tag":"WorkDurationEstimated","workDurationEstimatedQuantity":1,"workDurationEstimatedUnity":"Hour"}
我不太熟悉MySQL或Postgres中的原生JSON支持,但如果您想根据基础JSON数据进行查询,可能需要调查一下。