Stop At leaking into user tables (instead use it only on internal tables) (also rename it to Context)

This commit is contained in:
Shane 2021-03-05 01:35:12 +00:00
parent 7aeb652e61
commit 8fb5051c1d
No known key found for this signature in database
GPG Key ID: C1D5BF1DE4F6D319
2 changed files with 170 additions and 159 deletions

View File

@ -49,13 +49,14 @@ module Rel8
, HigherKindedTable
, GHigherKindedTable(..)
, Congruent
, KContext
, Context
-- ** Table schemas
, Column
, OuterJoin
, TableSchema(..)
, ColumnSchema
, At(..)
-- * Expressions
, Expr
@ -661,10 +662,17 @@ writing higher-kinded data types is usually more convenient. See also:
-}
class HigherKindedTable (Columns t) => Table (context :: Type -> Type) (t :: Type) | t -> context where
type Columns t :: (Type -> Type) -> Type
type Columns t :: KContext -> Type
toColumns :: t -> Columns t context
fromColumns :: Columns t context -> t
toColumns :: t -> Columns t (Context context)
fromColumns :: Columns t (Context context) -> t
data KContext where
Context :: (Type -> Type) -> KContext
type Context = 'Context
{-| Higher-kinded data types.
@ -712,94 +720,94 @@ data MyType f = MyType { fieldA :: Column f T }
@
-}
class HigherKindedTable (t :: (Type -> Type) -> Type) where
class HigherKindedTable (t :: KContext -> Type) where
type HField t = (field :: Type -> Type) | field -> t
type HConstrainTable t (c :: Type -> Constraint) :: Constraint
hfield :: t f -> HField t x -> C f x
htabulate :: forall f. (forall x. HField t x -> C f x) -> t f
htraverse :: forall f g m. Applicative m => (forall x. C f x -> m (C g x)) -> t f -> m (t g)
hdicts :: forall c. HConstrainTable t c => t (Dict c)
hdbtype :: t (Dict DBType)
hfield :: t (Context f) -> HField t x -> C f x
htabulate :: forall f. (forall x. HField t x -> C f x) -> t (Context f)
htraverse :: forall f g m. Applicative m => (forall x. C f x -> m (C g x)) -> t (Context f) -> m (t (Context g))
hdicts :: forall c. HConstrainTable t c => t (Context (Dict c))
hdbtype :: t (Context (Dict DBType))
type HField t = GenericHField t
type HConstrainTable t c = HConstrainTable (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t IsColumn) ()))) c
type HConstrainTable t c = HConstrainTable (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context IsColumn)) ()))) c
default hfield
:: forall f x
. ( Generic (t f)
. ( Generic (t (Context f))
, HField t ~ GenericHField t
, Congruent (WithShape f (Rep (t IsColumn)) (Rep (t f) ())) (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ()))
, HField (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ()))) ~ HField (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t IsColumn) ())))
, HigherKindedTable (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ())))
, Table f (WithShape f (Rep (t IsColumn)) (Rep (t f) ()))
, Congruent (WithShape f (Rep (t (Context IsColumn))) (Rep (t (Context f)) ())) (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))
, HField (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))) ~ HField (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context IsColumn)) ())))
, HigherKindedTable (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ())))
, Table f (WithShape f (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))
)
=> t f -> HField t x -> C f x
=> t (Context f) -> HField t x -> C f x
hfield x (GenericHField i) =
hfield (toColumns (WithShape @f @(Rep (t IsColumn)) (GHC.Generics.from @_ @() x))) i
hfield (toColumns (WithShape @f @(Rep (t (Context IsColumn))) (GHC.Generics.from @_ @() x))) i
default htabulate
:: forall f
. ( Generic (t f)
. ( Generic (t (Context f))
, HField t ~ GenericHField t
, Congruent (WithShape f (Rep (t IsColumn)) (Rep (t f) ())) (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ()))
, HField (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ()))) ~ HField (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t IsColumn) ())))
, HigherKindedTable (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ())))
, Table f (WithShape f (Rep (t IsColumn)) (Rep (t f) ()))
, Congruent (WithShape f (Rep (t (Context IsColumn))) (Rep (t (Context f)) ())) (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))
, HField (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))) ~ HField (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context IsColumn)) ())))
, HigherKindedTable (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ())))
, Table f (WithShape f (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))
)
=> (forall a. HField t a -> C f a) -> t f
=> (forall a. HField t a -> C f a) -> t (Context f)
htabulate f =
to @_ @() $ forgetShape @f @(Rep (t IsColumn)) $ fromColumns $ htabulate (f . GenericHField)
to @_ @() $ forgetShape @f @(Rep (t (Context IsColumn))) $ fromColumns $ htabulate (f . GenericHField)
default htraverse
:: forall f g m
. ( Applicative m
, Generic (t f)
, Generic (t g)
, Congruent (WithShape f (Rep (t IsColumn)) (Rep (t f) ())) (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ()))
, HigherKindedTable (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ())))
, Table f (WithShape f (Rep (t IsColumn)) (Rep (t f) ()))
, Table g (WithShape g (Rep (t IsColumn)) (Rep (t g) ()))
, Congruent (WithShape g (Rep (t IsColumn)) (Rep (t g) ())) (WithShape IsColumn (Rep (t IsColumn)) (Rep (t f) ()))
, Generic (t (Context f))
, Generic (t (Context g))
, Congruent (WithShape f (Rep (t (Context IsColumn))) (Rep (t (Context f)) ())) (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))
, HigherKindedTable (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ())))
, Table f (WithShape f (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))
, Table g (WithShape g (Rep (t (Context IsColumn))) (Rep (t (Context g)) ()))
, Congruent (WithShape g (Rep (t (Context IsColumn))) (Rep (t (Context g)) ())) (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context f)) ()))
)
=> (forall a. C f a -> m (C g a)) -> t f -> m (t g)
=> (forall a. C f a -> m (C g a)) -> t (Context f) -> m (t (Context g))
htraverse f x =
fmap (to @_ @() . forgetShape @g @(Rep (t IsColumn)) . fromColumns)
fmap (to @_ @() . forgetShape @g @(Rep (t (Context IsColumn))) . fromColumns)
$ htraverse f
$ toColumns
$ WithShape @f @(Rep (t IsColumn))
$ WithShape @f @(Rep (t (Context IsColumn)))
$ GHC.Generics.from @_ @() x
default hdicts
:: forall c
. ( Generic (t (Dict c))
, Table (Dict c) (WithShape (Dict c) (Rep (t IsColumn)) (Rep (t (Dict c)) ()))
, HConstrainTable (Columns (WithShape (Dict c) (Rep (t IsColumn)) (Rep (t (Dict c)) ()))) c
. ( Generic (t (Context (Dict c)))
, Table (Dict c) (WithShape (Dict c) (Rep (t (Context IsColumn))) (Rep (t (Context (Dict c))) ()))
, HConstrainTable (Columns (WithShape (Dict c) (Rep (t (Context IsColumn))) (Rep (t (Context (Dict c))) ()))) c
)
=> t (Dict c)
=> t (Context (Dict c))
hdicts =
to @_ @() $
forgetShape @(Dict c) @(Rep (t IsColumn)) $
forgetShape @(Dict c) @(Rep (t (Context IsColumn))) $
fromColumns $
hdicts @(Columns (WithShape (Dict c) (Rep (t IsColumn)) (Rep (t (Dict c)) ()))) @c
hdicts @(Columns (WithShape (Dict c) (Rep (t (Context IsColumn))) (Rep (t (Context (Dict c))) ()))) @c
default hdbtype ::
( Generic (t (Dict DBType))
, Table (Dict DBType) (WithShape (Dict DBType) (Rep (t IsColumn)) (Rep (t (Dict DBType)) ()))
( Generic (t (Context (Dict DBType)))
, Table (Dict DBType) (WithShape (Dict DBType) (Rep (t (Context IsColumn))) (Rep (t (Context (Dict DBType))) ()))
)
=> t (Dict DBType)
=> t (Context (Dict DBType))
hdbtype =
to @_ @() $
forgetShape @(Dict DBType) @(Rep (t IsColumn)) $
forgetShape @(Dict DBType) @(Rep (t (Context IsColumn))) $
fromColumns $
hdbtype @(Columns (WithShape (Dict DBType) (Rep (t IsColumn)) (Rep (t (Dict DBType)) ())))
hdbtype @(Columns (WithShape (Dict DBType) (Rep (t (Context IsColumn))) (Rep (t (Context (Dict DBType))) ())))
hmap :: HigherKindedTable t => (forall x. C f x -> C g x) -> t f -> t g
hmap :: HigherKindedTable t => (forall x. C f x -> C g x) -> t (Context f) -> t (Context g)
hmap f t = htabulate $ f <$> hfield t
hzipWith :: HigherKindedTable t => (forall x. C f x -> C g x -> C h x) -> t f -> t g -> t h
hzipWith :: HigherKindedTable t => (forall x. C f x -> C g x -> C h x) -> t (Context f) -> t (Context g) -> t (Context h)
hzipWith f t u = htabulate $ f <$> hfield t <*> hfield u
@ -868,103 +876,103 @@ In @rel8@ we try hard to always know what @f@ is, which means holes should
mention precise types, rather than the @Column@ type family. You should only
need to be aware of the type family when defining your table types.
-}
type family Column (context :: At (Type -> Type)) (a :: Type) :: Type where
Column ('At Identity) a = a
Column ('At f) a = f a
type family Column (context :: (Type -> Type)) (a :: Type) :: Type where
Column Identity a = a
Column f a = f a
type family OuterJoin (context :: At (Type -> Type)) (t :: At (Type -> Type) -> Type) :: Type where
OuterJoin ('At Identity) t = Maybe (t ('At Identity))
OuterJoin ('At Expr) t = MaybeTable (t ('At Expr))
OuterJoin ('At ColumnSchema) t = HMaybeTable (GRep t) ColumnSchema
type family OuterJoin (context :: Type -> Type) (t :: (Type -> Type) -> Type) :: Type where
OuterJoin Identity t = Maybe (t Identity)
OuterJoin Expr t = MaybeTable (t Expr)
OuterJoin f t = HMaybeTable (GRep t) (Context f)
-- | The @C@ newtype simply wraps 'Column', but this allows us to work around
-- injectivity problems of functions that return type family applications.
newtype C f x = MkC { toColumn :: Column ('At f) x }
newtype C f x = MkC { toColumn :: Column f x }
-- | Lift functions that map between 'Column's to functions that map between
-- 'C's.
mapC :: (Column ('At f) x -> Column ('At g) y) -> C f x -> C g y
mapC :: (Column f x -> Column g y) -> C f x -> C g y
mapC f (MkC x) = MkC $ f x
-- | Effectfully map from one column to another.
traverseC :: Applicative m => (Column ('At f) x -> m (Column ('At g) y)) -> C f x -> m (C g y)
traverseC :: Applicative m => (Column f x -> m (Column g y)) -> C f x -> m (C g y)
traverseC f (MkC x) = MkC <$> f x
-- | Zip two columns together.
zipCWith :: (Column ('At f) x -> Column ('At g) y -> Column ('At h) z) -> C f x -> C g y -> C h z
zipCWith :: (Column f x -> Column g y -> Column h z) -> C f x -> C g y -> C h z
zipCWith f (MkC x) (MkC y) = MkC (f x y)
-- | Zip two columns together under an effectful context.
zipCWithM :: Applicative m => (Column ('At f) x -> Column ('At g) y -> m (Column ('At h) z)) -> C f x -> C g y -> m (C h z)
zipCWithM :: Applicative m => (Column f x -> Column g y -> m (Column h z)) -> C f x -> C g y -> m (C h z)
zipCWithM f (MkC x) (MkC y) = MkC <$> f x y
class HigherKindedTable (GRep t) => GHigherKindedTable (t :: At (Type -> Type) -> Type) where
type GRep t :: (Type -> Type) -> Type
type GRep t = GColumns (Rep (t ('At Expr)))
class HigherKindedTable (GRep t) => GHigherKindedTable (t :: (Type -> Type) -> Type) where
type GRep t :: KContext -> Type
type GRep t = GColumns (Rep (t Expr))
toExprs :: t ('At Expr) -> GRep t Expr
fromExprs :: GRep t Expr -> t ('At Expr)
toExprs :: t Expr -> GRep t (Context Expr)
fromExprs :: GRep t (Context Expr) -> t Expr
default toExprs
:: ( GColumns (Rep (t ('At Expr))) ~ GRep t
, GHigherKindedTableImpl Expr (Rep (t ('At Expr)))
, Generic (t ('At Expr))
:: ( GColumns (Rep (t Expr)) ~ GRep t
, GHigherKindedTableImpl Expr (Rep (t Expr))
, Generic (t Expr)
)
=> t ('At Expr) -> GRep t Expr
toExprs = ghigherKindedTo @Expr @(Rep (t ('At Expr))) . GHC.Generics.from @_ @()
=> t Expr -> GRep t (Context Expr)
toExprs = ghigherKindedTo @Expr @(Rep (t Expr)) . GHC.Generics.from @_ @()
default fromExprs
:: ( GColumns (Rep (t ('At Expr))) ~ GRep t
, GHigherKindedTableImpl Expr (Rep (t ('At Expr)))
, Generic (t ('At Expr))
:: ( GColumns (Rep (t Expr)) ~ GRep t
, GHigherKindedTableImpl Expr (Rep (t Expr))
, Generic (t Expr)
)
=> GRep t Expr -> t ('At Expr)
fromExprs = to @_ @() . ghigherKindedFrom @Expr @(Rep (t ('At Expr)))
=> GRep t (Context Expr) -> t Expr
fromExprs = to @_ @() . ghigherKindedFrom @Expr @(Rep (t Expr))
toColumnSchemas :: t ('At ColumnSchema) -> GRep t ColumnSchema
fromColumnSchemas :: GRep t ColumnSchema -> t ('At ColumnSchema)
toColumnSchemas :: t ColumnSchema -> GRep t (Context ColumnSchema)
fromColumnSchemas :: GRep t (Context ColumnSchema) -> t ColumnSchema
default toColumnSchemas
:: ( GColumns (Rep (t ('At ColumnSchema))) ~ GRep t
, GHigherKindedTableImpl ColumnSchema (Rep (t ('At ColumnSchema)))
, Generic (t ('At ColumnSchema))
:: ( GColumns (Rep (t ColumnSchema)) ~ GRep t
, GHigherKindedTableImpl ColumnSchema (Rep (t ColumnSchema))
, Generic (t ColumnSchema)
)
=> t ('At ColumnSchema) -> GRep t ColumnSchema
toColumnSchemas = ghigherKindedTo @ColumnSchema @(Rep (t ('At ColumnSchema))) . GHC.Generics.from @_ @()
=> t ColumnSchema -> GRep t (Context ColumnSchema)
toColumnSchemas = ghigherKindedTo @ColumnSchema @(Rep (t ColumnSchema)) . GHC.Generics.from @_ @()
default fromColumnSchemas
:: ( GColumns (Rep (t ('At ColumnSchema))) ~ GRep t
, GHigherKindedTableImpl ColumnSchema (Rep (t ('At ColumnSchema)))
, Generic (t ('At ColumnSchema))
:: ( GColumns (Rep (t ColumnSchema)) ~ GRep t
, GHigherKindedTableImpl ColumnSchema (Rep (t ColumnSchema))
, Generic (t ColumnSchema)
)
=> GRep t ColumnSchema -> t ('At ColumnSchema)
fromColumnSchemas = to @_ @() . ghigherKindedFrom @ColumnSchema @(Rep (t ('At ColumnSchema)))
=> GRep t (Context ColumnSchema) -> t ColumnSchema
fromColumnSchemas = to @_ @() . ghigherKindedFrom @ColumnSchema @(Rep (t ColumnSchema))
glit :: t ('At Identity) -> t ('At Expr)
glit :: t Identity -> t Expr
default glit
:: ( Generic (t ('At Identity))
, Generic (t ('At Expr))
, GSerializable (Rep (t ('At Expr))) (Rep (t ('At Identity)))
:: ( Generic (t Identity)
, Generic (t Expr)
, GSerializable (Rep (t Expr)) (Rep (t Identity))
)
=> t ('At Identity) -> t ('At Expr)
glit = to @_ @() . glitImpl @(Rep (t ('At Expr))) @(Rep (t ('At Identity))) . GHC.Generics.from @_ @()
=> t Identity -> t Expr
glit = to @_ @() . glitImpl @(Rep (t Expr)) @(Rep (t Identity)) . GHC.Generics.from @_ @()
growParser :: Applicative f => (forall a. Typeable a => FieldParser a -> FieldParser (f a)) -> RowParser (f (t ('At Identity)))
growParser :: Applicative f => (forall a. Typeable a => FieldParser a -> FieldParser (f a)) -> RowParser (f (t Identity))
default growParser
:: ( Generic (t ('At Identity))
, GSerializable (Rep (t ('At Expr))) (Rep (t ('At Identity)))
:: ( Generic (t Identity)
, GSerializable (Rep (t Expr)) (Rep (t Identity))
, Applicative f
)
=> (forall a. Typeable a => FieldParser a -> FieldParser (f a))
-> RowParser (f (t ('At Identity)))
growParser f = fmap (to @_ @()) <$> growParserImpl @(Rep (t ('At Expr))) @(Rep (t ('At Identity))) f
-> RowParser (f (t Identity))
growParser f = fmap (to @_ @()) <$> growParserImpl @(Rep (t Expr)) @(Rep (t Identity)) f
class GSerializable (expr :: Type -> Type) (haskell :: Type -> Type) where
@ -991,9 +999,9 @@ instance Serializable expr haskell => GSerializable (K1 i expr) (K1 i haskell) w
class GHigherKindedTableImpl (context :: Type -> Type) (rep :: Type -> Type) where
type GColumns rep :: (Type -> Type) -> Type
ghigherKindedTo :: rep x -> GColumns rep context
ghigherKindedFrom :: GColumns rep context -> rep x
type GColumns rep :: KContext -> Type
ghigherKindedTo :: rep x -> GColumns rep (Context context)
ghigherKindedFrom :: GColumns rep (Context context) -> rep x
instance GHigherKindedTableImpl context f => GHigherKindedTableImpl context (M1 i c f) where
@ -1013,15 +1021,12 @@ instance Table context a => GHigherKindedTableImpl context (K1 i a) where
ghigherKindedFrom = K1 . fromColumns
data At a = At a
class Helper f t where
helperTo :: t ('At f) -> GRep t f
helperFrom :: GRep t f -> t ('At f)
helperTo :: t f -> GRep t (Context f)
helperFrom :: GRep t (Context f) -> t f
instance (x ~ 'At f, GHigherKindedTable t, Helper f t) => Table f (t x) where
instance (x ~ f, GHigherKindedTable t, Helper f t) => Table f (t x) where
type Columns (t x) = GRep t
toColumns = helperTo
fromColumns = helperFrom
@ -1046,7 +1051,7 @@ but this will violate the injectivity of the HField type (as there might be
two 't's with the same 'Rep'). This newtype restores that injectivity.
-}
newtype GenericHField t a where
GenericHField :: HField (Columns (WithShape IsColumn (Rep (t IsColumn)) (Rep (t IsColumn) ()))) a -> GenericHField t a
GenericHField :: HField (Columns (WithShape IsColumn (Rep (t (Context IsColumn))) (Rep (t (Context IsColumn)) ()))) a -> GenericHField t a
{-| To facilitate generic deriving for higher-kinded table, we work through
@ -1109,26 +1114,26 @@ type family IsColumnApplication (a :: Type) :: Bool where
'nestedTable :: t f' fields in higher kinded tables.
-}
class (isColumnApplication ~ IsColumnApplication shape, HigherKindedTable (K1Columns isColumnApplication shape a)) => K1Helper (isColumnApplication :: Bool) (context :: Type -> Type) (shape :: Type) (a :: Type) where
type K1Columns isColumnApplication shape a :: (Type -> Type) -> Type
toColumnsHelper :: a -> K1Columns isColumnApplication shape a context
fromColumnsHelper :: K1Columns isColumnApplication shape a context -> a
type K1Columns isColumnApplication shape a :: KContext -> Type
toColumnsHelper :: a -> K1Columns isColumnApplication shape a (Context context)
fromColumnsHelper :: K1Columns isColumnApplication shape a (Context context) -> a
instance (Table context a, IsColumnApplication shape ~ 'False) => K1Helper 'False context shape a where
instance (Table f a, IsColumnApplication shape ~ 'False) => K1Helper 'False f shape a where
type K1Columns 'False shape a = Columns a
toColumnsHelper = toColumns
fromColumnsHelper = fromColumns
instance (DBType a, f ~ context, g ~ Column ('At context) a) => K1Helper 'True context (IsColumn a) g where
instance (DBType a, g ~ Column f a) => K1Helper 'True f (IsColumn a) g where
type K1Columns 'True (IsColumn a) g = HIdentity a
toColumnsHelper = HIdentity
fromColumnsHelper = unHIdentity
-- | Any 'HigherKindedTable' is also a 'Table'.
instance (HigherKindedTable t, f ~ g) => Table f (t g) where
type Columns (t g) = t
instance (HigherKindedTable t, f ~ g) => Table f (t (Context g)) where
type Columns (t (Context g)) = t
toColumns = id
fromColumns = id
@ -1137,7 +1142,7 @@ instance (HigherKindedTable t, f ~ g) => Table f (t g) where
deriving of higher-kinded tables with more than 1 field (it deals with the
@:*:@ case).
-}
data HPair x y (f :: Type -> Type) = HPair { hfst :: x f, hsnd :: y f }
data HPair x y (f :: KContext) = HPair { hfst :: x f, hsnd :: y f }
deriving stock (Generic)
@ -1173,7 +1178,8 @@ instance (Table f a, Table f b) => Table f (a, b) where
{-| A single-column higher-kinded table. This is primarily useful for
facilitating generic-deriving of higher kinded tables.
-}
newtype HIdentity a f = HIdentity { unHIdentity :: Column ('At f) a }
data HIdentity a context where
HIdentity :: { unHIdentity :: Column f a } -> HIdentity a (Context f)
data HIdentityField x y where
@ -1189,7 +1195,7 @@ instance DBType a => HigherKindedTable (HIdentity a) where
hdicts = HIdentity Dict
hdbtype = HIdentity Dict
htraverse :: forall f g m. Applicative m => (forall x. C f x -> m (C g x)) -> HIdentity a f -> m (HIdentity a g)
htraverse :: forall f g m. Applicative m => (forall x. C f x -> m (C g x)) -> HIdentity a (Context f) -> m (HIdentity a (Context g))
htraverse f (HIdentity a) = HIdentity . toColumn @g <$> f (MkC a :: C f a)
@ -1218,19 +1224,19 @@ their to be multiple expression types. Usually this is not the case, but for
@ExprFor a' a@), or just @Expr (Maybe a)@ (if @a@ is a single column).
-}
class Table Expr expr => ExprFor expr haskell
instance {-# OVERLAPPABLE #-} (DBType b, a ~ Expr b) => ExprFor a b
instance DBType a => ExprFor (Expr (Maybe a)) (Maybe a)
instance (ExprFor a b, Table Expr a) => ExprFor (MaybeTable a) (Maybe b)
instance (a ~ ListTable x, Table Expr (ListTable x), ExprFor x b) => ExprFor a [b]
instance (a ~ NonEmptyTable x, Table Expr (NonEmptyTable x), ExprFor x b) => ExprFor a (NonEmpty b)
instance (a ~ (a1, a2), ExprFor a1 b1, ExprFor a2 b2) => ExprFor a (b1, b2)
instance (HigherKindedTable t, a ~ t Expr, identity ~ Identity) => ExprFor a (t identity)
instance (GHigherKindedTable t, a ~ t ('At Expr), identity ~ ('At Identity)) => ExprFor a (t identity)
instance {-# OVERLAPPABLE #-} (DBType b, a ~ Expr b) => ExprFor a b
instance DBType a => ExprFor (Expr (Maybe a)) (Maybe a)
instance (ExprFor a b, Table Expr a) => ExprFor (MaybeTable a) (Maybe b)
instance (a ~ ListTable x, Table Expr (ListTable x), ExprFor x b) => ExprFor a [b]
instance (a ~ NonEmptyTable x, Table Expr (NonEmptyTable x), ExprFor x b) => ExprFor a (NonEmpty b)
instance (a ~ (a1, a2), ExprFor a1 b1, ExprFor a2 b2) => ExprFor a (b1, b2)
instance (HigherKindedTable t, a ~ t (Context Expr), identity ~ (Context Identity)) => ExprFor a (t identity)
instance (GHigherKindedTable t, a ~ t Expr, identity ~ Identity) => ExprFor a (t identity)
-- | Any higher-kinded records can be @SELECT@ed, as long as we know how to
-- decode all of the records constituent part's.
instance (s ~ t, expr ~ Expr, identity ~ Identity, HigherKindedTable t) => Serializable (s expr) (t identity) where
instance (s ~ t, expr ~ Context Expr, identity ~ Context Identity, HigherKindedTable t) => Serializable (s expr) (t identity) where
rowParser :: forall f. Applicative f => (forall a. Typeable a => FieldParser a -> FieldParser (f a)) -> RowParser (f (t identity))
rowParser inject = getCompose $ htraverse (traverseC getComposeOuter) $ hmap f hdbtype
where
@ -1243,7 +1249,7 @@ instance (s ~ t, expr ~ Expr, identity ~ Identity, HigherKindedTable t) => Seria
(MkC Dict, MkC x) -> MkC $ monolit x
instance (s ~ t, expr ~ 'At Expr, identity ~ 'At Identity, GHigherKindedTable t) => Serializable (s expr) (t identity) where
instance (s ~ t, expr ~ Expr, identity ~ Identity, GHigherKindedTable t) => Serializable (s expr) (t identity) where
lit = glit
rowParser f = growParser f
@ -1303,7 +1309,7 @@ data MaybeTable t where
MaybeTable
:: { -- | Check if this @MaybeTable@ is null. In other words, check if an outer
-- join matched any rows.
nullTag :: Expr ( Maybe Bool )
nullTag :: Expr (Maybe Bool)
, table :: t
}
-> MaybeTable t
@ -1321,7 +1327,7 @@ instance Monad MaybeTable where
data HMaybeTable g f = HMaybeTable
{ hnullTag :: Column ('At f) (Maybe Bool)
{ hnullTag :: HIdentity (Maybe Bool) f
, htable :: g f
}
deriving stock Generic
@ -1331,8 +1337,8 @@ data HMaybeTable g f = HMaybeTable
instance Table Expr a => Table Expr (MaybeTable a) where
type Columns (MaybeTable a) = HMaybeTable (Columns a)
toColumns (MaybeTable x y) = HMaybeTable x (toColumns y)
fromColumns (HMaybeTable x y) = MaybeTable x (fromColumns y)
toColumns (MaybeTable x y) = HMaybeTable (HIdentity x) (toColumns y)
fromColumns (HMaybeTable (HIdentity x) y) = MaybeTable x (fromColumns y)
-- | Perform case analysis on a 'MaybeTable'. Like 'maybe'.
@ -2292,7 +2298,7 @@ traverseAggrExpr f = \case
-- | A @ListTable@ value contains zero or more instances of @a@. You construct
-- @ListTable@s with 'many' or 'listAgg'.
newtype ListTable a = ListTable (Columns a (ComposeInner Expr []))
newtype ListTable a = ListTable (Columns a (Context (ComposeInner (Context Expr) [])))
instance (f ~ Expr, Table f a) => Table f (ListTable a) where
@ -2347,7 +2353,7 @@ many = fmap (maybeTable mempty id) . optional . aggregate . fmap listAgg
-- | A @NonEmptyTable@ value contains one or more instances of @a@. You construct
-- @NonEmptyTable@s with 'some' or 'nonEmptyAgg'.
newtype NonEmptyTable a = NonEmptyTable (Columns a (ComposeInner Expr NonEmpty))
newtype NonEmptyTable a = NonEmptyTable (Columns a (Context (ComposeInner (Context Expr) NonEmpty)))
instance (f ~ Expr, Table f a) => Table f (NonEmptyTable a) where
@ -2487,27 +2493,26 @@ class c (f a) => ComposeConstraint c f a
instance c (f a) => ComposeConstraint c f a
newtype ComposeInner f g a = ComposeInner
{ getComposeInner :: Column ('At f) (g a)
}
data ComposeInner context g a where
ComposeInner :: { getComposeInner :: Column f (g a) } -> ComposeInner (Context f) g a
traverseComposeInner :: forall f g t m a. Applicative m
=> (forall x. C f x -> m (C g x))
-> C (ComposeInner f t) a -> m (C (ComposeInner g t) a)
-> C (ComposeInner (Context f) t) a -> m (C (ComposeInner (Context g) t) a)
traverseComposeInner f (MkC (ComposeInner a)) =
mapC ComposeInner <$> f (MkC @_ @(t a) a)
zipComposeInnerWith :: forall f g h t a. ()
=> (forall x. C f x -> C g x -> C h x)
-> C (ComposeInner f t) a -> C (ComposeInner g t) a -> C (ComposeInner h t) a
-> C (ComposeInner (Context f) t) a -> C (ComposeInner (Context g) t) a -> C (ComposeInner (Context h) t) a
zipComposeInnerWith f (MkC (ComposeInner a)) (MkC (ComposeInner b)) =
mapC ComposeInner $ f (MkC @_ @(t a) a) (MkC @_ @(t a) b)
newtype ComposeOuter f g a = ComposeOuter
{ getComposeOuter :: f (Column ('At g) a)
{ getComposeOuter :: f (Column g a)
}
@ -2515,7 +2520,7 @@ data HComposeField f t a where
HComposeField :: HField t a -> HComposeField f t (f a)
newtype HComposeTable g t f = HComposeTable (t (ComposeInner f g))
newtype HComposeTable g t (f :: KContext) = HComposeTable (t (Context (ComposeInner f g)))
instance (HigherKindedTable t, forall a. DBType a => DBType (f a)) => HigherKindedTable (HComposeTable f t) where
@ -2529,8 +2534,15 @@ instance (HigherKindedTable t, forall a. DBType a => DBType (f a)) => HigherKind
htraverse f (HComposeTable t) = HComposeTable <$> htraverse (traverseComposeInner f) t
hdicts :: forall c. HConstrainTable t (ComposeConstraint c f) => HComposeTable f t (Dict c)
hdicts :: forall c. HConstrainTable t (ComposeConstraint c f) => HComposeTable f t (Context (Dict c))
hdicts = HComposeTable $ hmap (mapC \Dict -> ComposeInner Dict) (hdicts @_ @(ComposeConstraint c f))
hdbtype :: HComposeTable f t (Dict DBType)
hdbtype :: HComposeTable f t (Context (Dict DBType))
hdbtype = HComposeTable $ hmap (mapC \Dict -> ComposeInner Dict) hdbtype
data Tab f = Tab
{ foo :: Column f Bool
, bar :: Column f Int64
}
deriving (Generic, GHigherKindedTable)

View File

@ -44,7 +44,6 @@ import qualified Database.Postgres.Temp as TmpPostgres
import GHC.Generics ( Generic )
import Hedgehog ( property, (===), forAll, cover, diff, evalM, PropertyT, TestT, test, Gen )
import qualified Hedgehog.Gen as Gen
import Rel8 ( At(..) )
import qualified Hedgehog.Range as Range
import qualified Rel8
import Test.Tasty
@ -131,12 +130,12 @@ data TestTable f = TestTable
deriving anyclass Rel8.GHigherKindedTable
deriving stock instance Eq (TestTable ('At Identity))
deriving stock instance Ord (TestTable ('At Identity))
deriving stock instance Show (TestTable ('At Identity))
deriving stock instance Eq (TestTable Identity)
deriving stock instance Ord (TestTable Identity)
deriving stock instance Show (TestTable Identity)
testTableSchema :: Rel8.TableSchema ( TestTable ('At Rel8.ColumnSchema) )
testTableSchema :: Rel8.TableSchema (TestTable Rel8.ColumnSchema)
testTableSchema =
Rel8.TableSchema
{ tableName = "test_table"
@ -530,9 +529,9 @@ data TwoTestTables f =
deriving anyclass Rel8.GHigherKindedTable
deriving stock instance Eq (TwoTestTables ('At Identity))
deriving stock instance Ord (TwoTestTables ('At Identity))
deriving stock instance Show (TwoTestTables ('At Identity))
deriving stock instance Eq (TwoTestTables Identity)
deriving stock instance Ord (TwoTestTables Identity)
deriving stock instance Show (TwoTestTables Identity)
testNestedTables :: IO TmpPostgres.DB -> TestTree
@ -565,7 +564,7 @@ testMaybeTableApplicative = databasePropertyTest "MaybeTable (<*>)" \transaction
(as, []) -> selected === (Nothing <$ as)
(as, bs) -> sort selected === sort (Just <$> liftA2 (,) as bs)
where
genRows :: PropertyT IO [TestTable ('At Identity)]
genRows :: PropertyT IO [TestTable Identity]
genRows = forAll do
Gen.list (Range.linear 0 10) $ liftA2 TestTable (Gen.text (Range.linear 0 10) Gen.unicode) (pure True)
@ -577,7 +576,7 @@ rollingBack connection m =
m `finally` liftIO (rollback connection)
genTestTable :: Gen (TestTable ('At Identity))
genTestTable :: Gen (TestTable Identity)
genTestTable = do
testTableColumn1 <- Gen.text (Range.linear 0 5) Gen.alphaNum
testTableColumn2 <- Gen.bool
@ -659,9 +658,9 @@ newtype HKNestedPair f = HKNestedPair { pairOne :: (TestTable f, TestTable f) }
deriving stock Generic
deriving anyclass Rel8.GHigherKindedTable
deriving stock instance Eq (HKNestedPair ('At Identity))
deriving stock instance Ord (HKNestedPair ('At Identity))
deriving stock instance Show (HKNestedPair ('At Identity))
deriving stock instance Eq (HKNestedPair Identity)
deriving stock instance Ord (HKNestedPair Identity)
deriving stock instance Show (HKNestedPair Identity)
testSelectNestedPairs :: IO TmpPostgres.DB -> TestTree
@ -694,9 +693,9 @@ data NestedMaybeTable f = NestedMaybeTable
deriving anyclass Rel8.GHigherKindedTable
deriving stock instance Eq (NestedMaybeTable ('At Identity))
deriving stock instance Ord (NestedMaybeTable ('At Identity))
deriving stock instance Show (NestedMaybeTable ('At Identity))
deriving stock instance Eq (NestedMaybeTable Identity)
deriving stock instance Ord (NestedMaybeTable Identity)
deriving stock instance Show (NestedMaybeTable Identity)
testNestedMaybeTable :: IO TmpPostgres.DB -> TestTree