如何将类型序列化到指定的数据库列

时间:2019-04-16 02:04:42

标签: haskell postgresql-simple

我在haskell应用程序中使用了postgresql-simple,并且我希望能够将数据类型序列化到数据库中的行,该行没有该数据类型中使用的记录字段的一对一映射因为我在其他数据类型中使用它们。 (我对Haskell还是相当陌生,但我认为这涉及使用Identifier数据构造函数。)

示例我有一个数据库表Users,其中有以下几列:user_id,电子邮件,名称,密码,地址,电话号码

现在我有一种具有以下格式的类型:

data UserDetails = UserDetails {
  user_id :: Int,
  email :: Text,
  phone_number :: Maybe (Text),
  password :: Text,
  name :: Maybe (Text),
  address :: Maybe (Text),
} deriving (Show, Generic, FromRow)

我可以为此类型实现一个通用的ToRow,因为记录字段与列名相同,但是我想要生成一个ToRow实例,该类型为:

data UserEditDetails = UserEditDetails {
  ued_email :: Maybe (Email),
  ued_phone_number :: Maybe (Text),
  ued_address :: Maybe (Text),
  ued_name :: Maybe (Text),
} deriving (Show, Generic)

我将如何实现这种ToRow实例,或更笼统地说,如何编写类似于以下伪代码的ToRow实例

instance ToRow UserEditDetails where
  toRow a = (columnname, ued_email a)... etc

希望它具有类似于Aeson的功能,您可以轻松编写以下内容:

instance ToJSON Login where
  toJSON = genericToJSON defaultOptions { fieldLabelModifier = drop 4 }

但是我还没有找到这个。

1 个答案:

答案 0 :(得分:0)

postgresql-simple对数据库列名没有任何关注。它只是期望ToRow / FromRow实例序列化或反序列化的列数和顺序将与SQL查询中的列数和顺序匹配。您可以为ToRow UserEditDetails使用通用实例,只要您要为其提供查询以正确顺序匹配四列。例如,如果您具有以下定义和通用ToRow实例:

data UserEditDetails = UserEditDetails
  { ued_email :: Maybe Text
  , ued_phone_number :: Maybe Text
  , ued_address :: Maybe Text
  , ued_name :: Maybe Text
  } deriving (Show, Generic, ToRow)

然后,我相信以下查询会正常工作:

do let q = "update user_table set email=?, phone_number=?, address=?, name=? "
           ++ "where user_id=?"
   execute conn q $ (UserEditDetails
                      (Just "me@example.invalid")
                      (Just "555-1212")
                      (Just "123 Fake Street")
                      (Just "Bob Jones"))
                    :. Only (15 :: Int)  -- user_id 15

请注意,来自FromRowToRow的通用实例等效于:

instance ToRow UserEditDetails where
  toRow (UserEditDetails a b c d) = [toField a, toField b, toField c, toField d]
instance FromRow UserEditDetails where
  fromRow = UserEditDetails <$> field <*> field <*> field <*> field

这些字段是匿名的,无论如何都无处提供特定的数据库列。