large-generics-0.1.0.0: test/Test/Record/Generic/Infra/Examples.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
-- | Standard Haskell records with a hand-written Generic instance
--
-- @large-records@ and @large-anon@ provide different record representations,
-- but here we want to test the generics infrastructure independent from these
-- libraries. The definitions here are simple, not intended to check for core
-- size; we do that in large-records and large-anon.
--
-- These definitions serve as a simple example of how the 'Generic' class might
-- be instantiated, and are used as a basis for testing.
module Test.Record.Generic.Infra.Examples (
-- * Simple
SimpleRecord(..)
, exampleSimpleRecord
-- * With type parameters
, ParamRecord(..)
, exampleParamRecord
-- * Higher-kinded
, Regular(..)
, Irregular(..)
, MultiFun(..)
, exampleRegular
, exampleIrregular
-- * Beam-like
, MixinTable(..)
, FullTable(..)
, PrimaryKey(..)
, exampleMixinTable
) where
import Data.Kind
import qualified GHC.Generics as GHC
import qualified Generics.SOP as SOP
import Test.QuickCheck
import Data.Record.Generic
import Data.Record.Generic.Rep.Internal (noInlineUnsafeCo)
import qualified Data.Record.Generic.Rep.Internal as Rep
import Test.Record.Generic.Infra.Beam.Mini
import Data.Functor.Identity
{-------------------------------------------------------------------------------
Simple record
-------------------------------------------------------------------------------}
data SimpleRecord = MkSimpleRecord {
simpleRecordField1 :: Word
, simpleRecordField2 :: Bool
}
deriving (Show, Eq, GHC.Generic) -- GHC generics for the GhcGenerics tests
exampleSimpleRecord :: SimpleRecord
exampleSimpleRecord = MkSimpleRecord 5 True
class (c Word, c Bool) => ConstraintsSimpleRecord c where
instance (c Word, c Bool) => ConstraintsSimpleRecord c where
instance Generic SimpleRecord where
type Constraints SimpleRecord = ConstraintsSimpleRecord
type MetadataOf SimpleRecord = '[ '("simpleRecordField1", Word)
, '("simpleRecordField2", Bool)
]
from MkSimpleRecord{..} = Rep.unsafeFromListAny [
I $ noInlineUnsafeCo simpleRecordField1
, I $ noInlineUnsafeCo simpleRecordField2
]
to rep =
let { [ I (noInlineUnsafeCo -> simpleRecordField1)
, I (noInlineUnsafeCo -> simpleRecordField2)
] = Rep.toListAny rep }
in MkSimpleRecord{..}
dict :: forall c.
ConstraintsSimpleRecord c
=> Proxy c -> Rep (Dict c) SimpleRecord
dict _ = Rep.unsafeFromListAny [
noInlineUnsafeCo (Dict :: Dict c Word)
, noInlineUnsafeCo (Dict :: Dict c Bool)
]
metadata _ = Metadata {
recordName = "SimpleRecord"
, recordConstructor = "MkSimpleRecord"
, recordSize = 2
, recordFieldMetadata = Rep.unsafeFromListAny [
noInlineUnsafeCo $
FieldMetadata (Proxy @"simpleRecordField1") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"simpleRecordField2") FieldLazy
]
}
instance Arbitrary SimpleRecord where
arbitrary = MkSimpleRecord <$> arbitrary <*> arbitrary
shrink (MkSimpleRecord f1 f2) = concat [
[ MkSimpleRecord f1' f2
| f1' <- shrink f1
]
, [ MkSimpleRecord f1 f2'
| f2' <- shrink f2
]
]
{-------------------------------------------------------------------------------
Record with some type arguments (but not higher-kinded)
-------------------------------------------------------------------------------}
data ParamRecord a b = MkParamRecord {
paramRecordField1 :: Word
, paramRecordField2 :: Bool
, paramRecordField3 :: Char
, paramRecordField4 :: a
, paramRecordField5 :: [b]
}
deriving (Eq, Ord, Show, GHC.Generic)
instance SOP.Generic (ParamRecord a b)
-- For comparison purposes only
class (c Word, c Bool, c Char, c a, c [b]) => ConstraintsParamRecord a b c
instance (c Word, c Bool, c Char, c a, c [b]) => ConstraintsParamRecord a b c
instance Generic (ParamRecord a b) where
type Constraints (ParamRecord a b) = ConstraintsParamRecord a b
type MetadataOf (ParamRecord a b) = '[ '("paramRecordField1", Word)
, '("paramRecordField2", Bool)
, '("paramRecordField3", Char)
, '("paramRecordField4", a)
, '("paramRecordField5", [b])
]
from MkParamRecord{..} = Rep.unsafeFromListAny [
I $ noInlineUnsafeCo paramRecordField1
, I $ noInlineUnsafeCo paramRecordField2
, I $ noInlineUnsafeCo paramRecordField3
, I $ noInlineUnsafeCo paramRecordField4
, I $ noInlineUnsafeCo paramRecordField5
]
to rep =
let { [ I (noInlineUnsafeCo -> paramRecordField1)
, I (noInlineUnsafeCo -> paramRecordField2)
, I (noInlineUnsafeCo -> paramRecordField3)
, I (noInlineUnsafeCo -> paramRecordField4)
, I (noInlineUnsafeCo -> paramRecordField5)
] = Rep.toListAny rep }
in MkParamRecord{..}
dict :: forall c.
ConstraintsParamRecord a b c
=> Proxy c -> Rep (Dict c) (ParamRecord a b)
dict _ = Rep.unsafeFromListAny [
noInlineUnsafeCo (Dict :: Dict c Word)
, noInlineUnsafeCo (Dict :: Dict c Bool)
, noInlineUnsafeCo (Dict :: Dict c Char)
, noInlineUnsafeCo (Dict :: Dict c a)
, noInlineUnsafeCo (Dict :: Dict c [b])
]
metadata _ = Metadata {
recordName = "ParamRecord"
, recordConstructor = "MkParamRecord"
, recordSize = 5
, recordFieldMetadata = Rep.unsafeFromListAny [
noInlineUnsafeCo $
FieldMetadata (Proxy @"paramRecordField1") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"paramRecordField2") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"paramRecordField3") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"paramRecordField4") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"paramRecordField5") FieldLazy
]
}
exampleParamRecord :: ParamRecord () Float
exampleParamRecord = MkParamRecord 5 True 'c' () [3.14]
{-------------------------------------------------------------------------------
Higher kinded record: regular
-------------------------------------------------------------------------------}
-- | Regular example: all fields have an @f@ parameter
data Regular f = MkRegular {
regularField1 :: f Int
, regularField2 :: f Bool
, regularField3 :: f String
}
exampleRegular :: Regular I
exampleRegular = MkRegular {
regularField1 = I 5
, regularField2 = I True
, regularField3 = I "a"
}
deriving instance (Show (f Int), Show (f Bool), Show (f String)) => Show (Regular f)
deriving instance (Eq (f Int), Eq (f Bool), Eq (f String)) => Eq (Regular f)
class (c (f Int), c (f Bool), c (f String)) => ConstraintsRegular f c
instance (c (f Int), c (f Bool), c (f String)) => ConstraintsRegular f c
instance Generic (Regular f) where
type Constraints (Regular f) = ConstraintsRegular f
type MetadataOf (Regular f) = '[ '("regularField1", f Int)
, '("regularField1", f Bool)
, '("regularField3", f String)
]
from MkRegular{..} = Rep.unsafeFromListAny [
I $ noInlineUnsafeCo regularField1
, I $ noInlineUnsafeCo regularField2
, I $ noInlineUnsafeCo regularField3
]
to rep =
let { [ I (noInlineUnsafeCo -> regularField1)
, I (noInlineUnsafeCo -> regularField2)
, I (noInlineUnsafeCo -> regularField3)
] = Rep.toListAny rep }
in MkRegular{..}
dict :: forall c.
ConstraintsRegular f c
=> Proxy c -> Rep (Dict c) (Regular f)
dict _ = Rep.unsafeFromListAny [
noInlineUnsafeCo (Dict :: Dict c (f Int))
, noInlineUnsafeCo (Dict :: Dict c (f Bool))
, noInlineUnsafeCo (Dict :: Dict c (f String))
]
metadata _ = Metadata {
recordName = "Regular"
, recordConstructor = "MkRegular"
, recordSize = 3
, recordFieldMetadata = Rep.unsafeFromListAny [
noInlineUnsafeCo $
FieldMetadata (Proxy @"regularField1") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"regularField2") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"regularField3") FieldLazy
]
}
{-------------------------------------------------------------------------------
Higher kinded record: irregular
-------------------------------------------------------------------------------}
-- | Irregular example: not all fields have an @f@ parameter
data Irregular f = MkIrregular {
irregularField1 :: f Int
, irregularField2 :: f Bool
, irregularField3 :: String
}
exampleIrregular :: Irregular I
exampleIrregular = MkIrregular {
irregularField1 = I 1234
, irregularField2 = I True
, irregularField3 = "hi"
}
deriving instance (Show (f Int), Show (f Bool)) => Show (Irregular f)
deriving instance (Eq (f Int), Eq (f Bool)) => Eq (Irregular f)
class (c (f Int), c (f Bool), c String) => ConstraintsIrregular f c
instance (c (f Int), c (f Bool), c String) => ConstraintsIrregular f c
instance Generic (Irregular f) where
type Constraints (Irregular f) = ConstraintsIrregular f
type MetadataOf (Irregular f) = '[ '("irregularField1", f Int)
, '("irregularField1", f Bool)
, '("irregularField3", String)
]
from MkIrregular{..} = Rep.unsafeFromListAny [
I $ noInlineUnsafeCo irregularField1
, I $ noInlineUnsafeCo irregularField2
, I $ noInlineUnsafeCo irregularField3
]
to rep =
let { [ I (noInlineUnsafeCo -> irregularField1)
, I (noInlineUnsafeCo -> irregularField2)
, I (noInlineUnsafeCo -> irregularField3)
] = Rep.toListAny rep }
in MkIrregular{..}
dict :: forall c.
ConstraintsIrregular f c
=> Proxy c -> Rep (Dict c) (Irregular f)
dict _ = Rep.unsafeFromListAny [
noInlineUnsafeCo (Dict :: Dict c (f Int))
, noInlineUnsafeCo (Dict :: Dict c (f Bool))
, noInlineUnsafeCo (Dict :: Dict c String)
]
metadata _ = Metadata {
recordName = "Irregular"
, recordConstructor = "MkIrregular"
, recordSize = 3
, recordFieldMetadata = Rep.unsafeFromListAny [
noInlineUnsafeCo $
FieldMetadata (Proxy @"irregularField1") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"irregularField2") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"irregularField3") FieldLazy
]
}
{-------------------------------------------------------------------------------
Higher kinded record: multiple functors
-------------------------------------------------------------------------------}
data MultiFun f g = MkMultiFun {
multiFunField1 :: f Int
, multiFunField2 :: g Bool
, multiFunField3 :: String
}
deriving instance (Show (f Int), Show (g Bool)) => Show (MultiFun f g)
deriving instance (Eq (f Int), Eq (g Bool)) => Eq (MultiFun f g)
class (c (f Int), c (g Bool), c String) => ConstraintsMultiFun f g c
instance (c (f Int), c (g Bool), c String) => ConstraintsMultiFun f g c
instance Generic (MultiFun f g) where
type Constraints (MultiFun f g) = ConstraintsMultiFun f g
type MetadataOf (MultiFun f g) = '[ '("multiFunField1", f Int)
, '("multiFunField1", g Bool)
, '("multiFunField3", String)
]
from MkMultiFun{..} = Rep.unsafeFromListAny [
I $ noInlineUnsafeCo multiFunField1
, I $ noInlineUnsafeCo multiFunField2
, I $ noInlineUnsafeCo multiFunField3
]
to rep =
let { [ I (noInlineUnsafeCo -> multiFunField1)
, I (noInlineUnsafeCo -> multiFunField2)
, I (noInlineUnsafeCo -> multiFunField3)
] = Rep.toListAny rep }
in MkMultiFun{..}
dict :: forall c.
ConstraintsMultiFun f g c
=> Proxy c -> Rep (Dict c) (MultiFun f g)
dict _ = Rep.unsafeFromListAny [
noInlineUnsafeCo (Dict :: Dict c (f Int))
, noInlineUnsafeCo (Dict :: Dict c (g Bool))
, noInlineUnsafeCo (Dict :: Dict c String)
]
metadata _ = Metadata {
recordName = "MultiFun"
, recordConstructor = "MkMultiFun"
, recordSize = 3
, recordFieldMetadata = Rep.unsafeFromListAny [
noInlineUnsafeCo $
FieldMetadata (Proxy @"multiFunField1") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"multiFunField2") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"multiFunField3") FieldLazy
]
}
{-------------------------------------------------------------------------------
Beam-like mixin table
This is the simpler case, because it contains only Columnar fields.
-------------------------------------------------------------------------------}
data MixinTable (f :: Type -> Type) = MkMixinTable {
mixinTableField1 :: Columnar f Char
, mixinTableField2 :: Columnar f Double
}
exampleMixinTable :: MixinTable Identity
exampleMixinTable = MkMixinTable {
mixinTableField1 = 'a'
, mixinTableField2 = 3.14
}
deriving instance ( Show (Columnar f Char)
, Show (Columnar f Double)
) => Show (MixinTable f)
deriving instance ( Eq (Columnar f Char)
, Eq (Columnar f Double)
) => Eq (MixinTable f)
class (c (Columnar f Char), c (Columnar f Double)) => ConstraintsMixinTable f c
instance (c (Columnar f Char), c (Columnar f Double)) => ConstraintsMixinTable f c
instance Generic (MixinTable f) where
type Constraints (MixinTable f) = ConstraintsMixinTable f
type MetadataOf (MixinTable f) = '[ '("mixinTableField1", Columnar f Char)
, '("mixinTableField2", Columnar f Double)
]
from MkMixinTable{..} = Rep.unsafeFromListAny [
I $ noInlineUnsafeCo mixinTableField1
, I $ noInlineUnsafeCo mixinTableField2
]
to rep =
let { [ I (noInlineUnsafeCo -> mixinTableField1)
, I (noInlineUnsafeCo -> mixinTableField2)
] = Rep.toListAny rep }
in MkMixinTable{..}
dict :: forall c.
ConstraintsMixinTable f c
=> Proxy c -> Rep (Dict c) (MixinTable f)
dict _ = Rep.unsafeFromListAny [
noInlineUnsafeCo (Dict :: Dict c (Columnar f Char))
, noInlineUnsafeCo (Dict :: Dict c (Columnar f Double))
]
metadata _ = Metadata {
recordName = "MixinTable"
, recordConstructor = "MkMixinTable"
, recordSize = 2
, recordFieldMetadata = Rep.unsafeFromListAny [
noInlineUnsafeCo $
FieldMetadata (Proxy @"mixinTableField1") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"mixinTableField2") FieldLazy
]
}
{-------------------------------------------------------------------------------
Beam-like full table example
-------------------------------------------------------------------------------}
data FullTable (f :: Type -> Type) = MkFullTable {
fullTableField1 :: PrimaryKey FullTable f
, fullTableField2 :: Columnar f Bool
, fullTableField3 :: MixinTable f
}
data instance PrimaryKey FullTable f = PrimA (Columnar f Int)
deriving instance Show (Columnar f Int) => Show (PrimaryKey FullTable f)
deriving instance Eq (Columnar f Int) => Eq (PrimaryKey FullTable f)
deriving instance ( Show (Columnar f Int)
, Show (Columnar f Bool)
, Show (Columnar f Char)
, Show (Columnar f Double)
) => Show (FullTable f)
deriving instance ( Eq (Columnar f Int)
, Eq (Columnar f Bool)
, Eq (Columnar f Char)
, Eq (Columnar f Double)
) => Eq (FullTable f)
class ( c (PrimaryKey FullTable f)
, c (Columnar f Bool)
, c (MixinTable f)
) => ConstraintsFullTable f c
instance ( c (PrimaryKey FullTable f)
, c (Columnar f Bool)
, c (MixinTable f)
) => ConstraintsFullTable f c
instance Generic (FullTable f) where
type Constraints (FullTable f) = ConstraintsFullTable f
type MetadataOf (FullTable f) = '[ '("fullTableField1", PrimaryKey FullTable f)
, '("fullTableField2", Columnar f Bool)
, '("fullTableField3", MixinTable f)
]
from MkFullTable{..} = Rep.unsafeFromListAny [
I $ noInlineUnsafeCo fullTableField1
, I $ noInlineUnsafeCo fullTableField2
, I $ noInlineUnsafeCo fullTableField3
]
to rep =
let { [ I (noInlineUnsafeCo -> fullTableField1)
, I (noInlineUnsafeCo -> fullTableField2)
, I (noInlineUnsafeCo -> fullTableField3)
] = Rep.toListAny rep }
in MkFullTable{..}
dict :: forall c.
ConstraintsFullTable f c
=> Proxy c -> Rep (Dict c) (FullTable f)
dict _ = Rep.unsafeFromListAny [
noInlineUnsafeCo (Dict :: Dict c (PrimaryKey FullTable f))
, noInlineUnsafeCo (Dict :: Dict c (Columnar f Bool))
, noInlineUnsafeCo (Dict :: Dict c (MixinTable f))
]
metadata _ = Metadata {
recordName = "FullTable"
, recordConstructor = "MkFullTable"
, recordSize = 3
, recordFieldMetadata = Rep.unsafeFromListAny [
noInlineUnsafeCo $
FieldMetadata (Proxy @"fullTableField1") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"fullTableField2") FieldLazy
, noInlineUnsafeCo $
FieldMetadata (Proxy @"fullTableField3") FieldLazy
]
}