【问题标题】:Haskell storing composed ADT with Persistent definitionsHaskell 使用持久定义存储组合的 ADT
【发布时间】:2016-05-29 16:01:53
【问题描述】:

我如何创建类似于ADTsYesod 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 之类的关系数据库

【问题讨论】:

    标签: database haskell functional-programming yesod


    【解决方案1】:

    要使用 Persistent 存储 ADT,您只需告诉 Persistent 如何从数据库中序列化/反序列化该值。为此,请将其设为PersistField 的实例(将其转换为TextByteString 等基本类型)和PersistFieldSql(指定要使用的数据库列的类型)。

    您有多种选择(反)序列化数据。我想编码/解码为二进制值会更快,但我推荐 JSON,因为:

    • 它在数据库级别是人类可读的
    • 一些数据库内置了对它的支持
    • 便携
    • 通过to/fromPersistValueJSON 将支持内置到 Persistent 中。

    这是一个例子:

    -- 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 数据进行查询,您可能需要研究一下。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 2015-04-02
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多