packages feed

genvalidity-persistent-1.0.0.0: src/Data/GenValidity/Persist.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Data.GenValidity.Persist where

import Data.GenValidity
import Data.GenValidity.Containers
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import Data.Validity.Containers
import Data.Validity.Persist ()
import Database.Persist
import Database.Persist.Sql
import Test.QuickCheck

instance ToBackendKey SqlBackend record => GenValid (Key record) where
  genValid = toSqlKey <$> genValid
  shrinkValid = fmap toSqlKey . shrinkValid . fromSqlKey

instance (GenValid a, ToBackendKey SqlBackend a) => GenValid (Entity a) where
  genValid = Entity <$> genValid <*> genValid
  shrinkValid (Entity k v) = [Entity k' v' | (k', v') <- shrinkValid (k, v)]

validsWithSeperateIDs ::
  forall a.
  (ToBackendKey SqlBackend a, GenValid a) =>
  Gen [Entity a]
validsWithSeperateIDs = genValidsWithSeperateIDs genValid

genValidsWithSeperateIDs ::
  forall a.
  (PersistEntity a, ToBackendKey SqlBackend a) =>
  Gen a ->
  Gen [Entity a]
genValidsWithSeperateIDs gen =
  sized $ \n -> do
    list <- arbPartition n
    go list
  where
    go :: [Int] -> Gen [Entity a]
    go [] = pure []
    go (s : ss) = do
      es <- go ss
      resize s $ do
        ei <- genValid `suchThat` (`notElem` map entityKey es)
        e <- gen
        pure $ Entity ei e : es

genSeperateIdsForNE ::
  forall a.
  (PersistEntity a, ToBackendKey SqlBackend a, GenValid a) =>
  NonEmpty a ->
  Gen (NonEmpty (Entity a))
genSeperateIdsForNE (a :| as) = do
  es <- genSeperateIdsFor as
  i <- genValid `suchThat` (`notElem` map entityKey es)
  pure (Entity i a :| es)

genSeperateIds ::
  forall a.
  (PersistEntity a, ToBackendKey SqlBackend a) =>
  Gen [Key a]
genSeperateIds = genSeperate genValid

genSeperateIdsFor ::
  forall a.
  (ToBackendKey SqlBackend a, GenValid a) =>
  [a] ->
  Gen [Entity a]
genSeperateIdsFor [] = pure []
genSeperateIdsFor (a : as) = NE.toList <$> genSeperateIdsForNE (a :| as)

shrinkValidWithSeperateIds ::
  (PersistEntity a, ToBackendKey SqlBackend a, GenValid a) =>
  [Entity a] ->
  [[Entity a]]
shrinkValidWithSeperateIds = filter (distinctOrd . map entityKey) . shrinkValid