Skip to content
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

Add newtyped write field example to TutorialBasic #543

Open
tomjaguarpaw opened this issue Feb 13, 2022 · 0 comments
Open

Add newtyped write field example to TutorialBasic #543

tomjaguarpaw opened this issue Feb 13, 2022 · 0 comments

Comments

@tomjaguarpaw
Copy link
Owner

Issue reported by James Walker, thanks James!

Similarly to #539, having a Maybe inside a newtype can cause confusion. The tutorial should explicitly demonstrate an optional newtype (especially because primary keys are optional and wrapping them in newtypes is common).

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

import Opaleye
import Data.Profunctor.Product.TH

data User' id name surname = User
   { pkUser :: id
   , name :: name
   , surname :: surname
   }

$(makeAdaptorAndInstance "pUser" ''User')

-- | Polymorphic user ID type
newtype UserId' a = UserId a
$(makeAdaptorAndInstance "pUserId" ''UserId')

-- | User ID field type
type UserIdField = UserId' (Field SqlInt4)

type UserRead = User'
   UserIdField
   (Field SqlText)
   (Field SqlText)

type UserWrite = User'
   (Maybe UserIdField)
   (Field SqlText)
   (Field SqlText)

userTable :: Table UserWrite UserRead
userTable = table "User"
   (pUser User { pkUser    = pUserId (UserId (tableField "PkUser"))
               , name      = tableField "Name"
               , surname = tableField "Surname"
               })

-- We get the error
--
--    • Couldn't match type ‘UserId' a1_00’ with ‘Maybe UserIdField’
--
-- Inference proceeded as follows
--
-- tableField "PkUser" :: InferrableTableField w n r => TableFields w (Field_ n r)
--
-- pUserId (UserId (tableField "PkUser"))
--  :: InferrableTableField w n r => TableFields (UserId' w) (UserId (Field_ n r))
--
-- userTable :: InferrableTableField w n r
--   => Table (User' (UserId' w) (Field SqlText) (Field SqlText)) UserRead
--
-- But the specified type is
--
-- Table
-- (User'
--    (Maybe UserIdField)
--    (Field SqlText)
--    (Field SqlText))
-- UserRead
--
-- and (Maybe UserIdField) does not match (UserId' w)


-- The fix is to put the `Maybe` inside the `UserId'`:

type UserIdWriteField = UserId' (Maybe (Field SqlInt4))

type FixedUserWrite = User'
   UserIdWriteField
   (Field SqlText)
   (Field SqlText)

fixedUserTable :: Table FixedUserWrite UserRead
fixedUserTable = table "User"
   (pUser User { pkUser    = pUserId (UserId (tableField "PkUser"))
               , name      = tableField "Name"
               , surname = tableField "Surname"
               })
```Add newtyped write field example to TutorialBasic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant