Автоматическое создание `PersistEntity` для уже существующих типов - PullRequest
3 голосов
/ 17 января 2020

Мотивация: я хочу использовать MongoDB для хранения данных. Постоянная библиотека, похоже, является единственной высокоуровневой библиотекой Haskell, поддерживающей MongoDB. Мой проект уже определил типы, представляющие строки (документы) любой базы данных.

Типичным использованием постоянного является определение вашего типа через бит шаблона Haskell, например:

{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE QuasiQuotes                #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeFamilies               #-}
import Database.Persist
import Database.Persist.TH
import Database.Persist.Sqlite
import Control.Monad.IO.Class (liftIO)

mkPersist mongoSettings [persistLowerCase|
Person
    name String
    age Int
    deriving Show
|]

Тем не менее, у меня уже есть типы значительных размеров в коде, похожем на:

newtype Name = Name String deriving (Show, Etc, Etc)
data Person = Person
                 { name :: Name, age :: Int } deriving (Show, Etc, Etc)

Так что в идеале я бы получал свои PersistEntity и, возможно, даже PersistField экземпляры через уменьшенный бит TH, такой как :

mkPersistFromType mongoSettings ''Person

Однако функции TH, такой как mkPersistFromType, нет. Написание экземпляров классов вручную утомительно - они очень длинные. Какой правильный путь вперед? Есть ли где-нибудь mkPersistFromType, которого я не видел, или мне самому написать?

1 Ответ

1 голос
/ 21 января 2020

Обратите внимание, что mkPersist - это просто функция, и она возвращает список объявлений для добавления в исходный файл. Таким образом, вы можете свободно обрабатывать эти объявления и, например, удалять ненужные.

Вот пример, в котором я отфильтровываю все объявления данных:

myMkPersist settings = do
  filter wanted <$> mkPersist settings [persistLowerCase|
    Person
      name String
    |]
  where
  wanted DataD{} = False
  wanted _ = True

Обратите внимание, что myMkPersist должно быть определяется в отдельном файле из-за ограничения стадии. В основном файле вы используете эту функцию:

data Person = Person
  { personName :: String
  }

myMkPersist mongoSettings

Также вы можете проверить вывод на mkPersist, чтобы увидеть, как именно вы хотите пост-обработку объявлений, вы можете сделать это с помощью -ddump-splices опция Cli.

...