-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
deriveEsqueletoRecord
does not handle polymorphic records
#383
Comments
I hand-derived some instances that ended up working out for this case. See for example the following minimal example. {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
module Lib where
import Control.Monad.Trans.State.Strict (evalStateT)
import Data.Bifunctor (first)
import Data.String (fromString)
import Database.Esqueleto.Experimental
import Database.Esqueleto.Record
import Database.Esqueleto.Internal.Internal
import Data.Proxy
data Record key = Record { key :: key, val :: Int }
data SqlRecord key = SqlRecord { key :: SqlExpr (Value key), val :: SqlExpr (Value Int) }
data SqlMaybeRecord key = SqlMaybeRecord { key :: SqlExpr (Value (Maybe key)), val :: SqlExpr (Value (Maybe Int)) }
instance PersistField (Key rec) => SqlSelect (SqlRecord (Key rec)) (Record (Key rec)) where
sqlSelectCols identInfo SqlRecord { key, val } =
sqlSelectCols identInfo (key :& val)
sqlSelectColCount _ = sqlSelectColCount
( Proxy
@( SqlExpr (Value (Key rec))
:& SqlExpr (Value Int)
)
)
sqlSelectProcessRow columns =
first
(fromString "Failed to parse Record: " <>)
(evalStateT process columns)
where
process = do
Value key <- takeColumns @(SqlExpr (Value (Key rec)))
Value val <- takeColumns @(SqlExpr (Value Int))
pure Record { key, val }
instance ToAliasReference (SqlRecord (Key rec)) where
toAliasReference ident SqlRecord { key, val } =
SqlRecord <$> toAliasReference ident key <*> toAliasReference ident val
instance ToAlias (SqlRecord (Key rec)) where
toAlias SqlRecord { key, val } =
SqlRecord <$> toAlias key <*> toAlias val
instance ToMaybe (SqlRecord (Key rec)) where
type ToMaybeT (SqlRecord (Key rec)) = SqlMaybeRecord (Key rec)
toMaybe SqlRecord { key, val } =
SqlMaybeRecord
{ key = just key
, val = just val
} I'm not actually certain if the |
Hmm. With a totally polymorphic field like I think you'd need the type parameter to not affect the conversion logic. Or, to delegate more fully. Consider: data R k = R { key :: k }
data SqlR k = SqlR { key :: k }
data SqlMaybeR k = SqlMaybeR { key :: k } Then I think our instance becomes: instance (SqlSelect sqlK valueK) => SqlSelect (SqlR sqlK) (R valueK) Which should work in more generality. I think a much easier alternative is if you can further constrain the type of data Record a = Record { key :: Key a } Now, we know that That may also simplify the rest of your code, as well. |
Consider the type:
We can't write
deriveEsqueletoRecord
here because there's a type error. We can't provide concrete things becausederiveEsqueletoRecord
takes aName
and not aType
, so we can't writederiveEsqueletoRecord @(Record Foo)
.Ideally we can support polymorphic records.
The text was updated successfully, but these errors were encountered: