tomjaguarpaw / haskell-opaleye

Other
605 stars 115 forks source link

Typesafe auto incrementing keys #373

Open reygoch opened 6 years ago

reygoch commented 6 years ago

I've been following the tutorial where it is described how to make a typesafe primary key with newtype. Problem is that I can't use that to work with optional primary key.

I've used the following to add some semantics to my code for now:

type PID a = Column PGInt4

type UserW = User'
  (Maybe (PID User))
  (Column PGText)
  (Column PGText)
  (Column PGText)

type UserR = User'
  (PID User)
  (Column PGText)
  (Column PGText)
  (Column PGText)

But that is not very type safe so I've created the following type:

newtype UserID' a = UserID a
  deriving ( Eq, Show )

type UserID = UserID' Int
type UserIDC = UserID' (Column PGInt4)

$(makeAdaptorAndInstance "pUserID" ''UserID')

Which I than use like this:

type UserW = User'
  (Maybe UserIDC)
  ...
type UserR = User'
  (UserIDC)
  ...

But when I try to define my table:

userT :: Table UserW UserR
userT = Table "User" $ pUser User
  { userId       = pUserID $ UserID $ tableColumn "id"
  , userType     = tableColumn "type"
  , userUsername = tableColumn "username"
  , userPassword = tableColumn "password"
  }

I get the following error which I can't figure out:

    * Couldn't match type `UserID' a1_00' with `Maybe UserIDC'      Expected type: Table UserW UserR
        Actual type: Table                       (User'
                          (UserID' a1_00) (Column PGText) (Column PGText) (Column PGText))                       (User'
                          (UserID' (Column PGInt4))                          (Column PGText)
                          (Column PGText)                          (Column PGText))
    * In the expression:        Table "User"
          $ pUser              User
                {userId = pUserID $ UserID $ tableColumn "id",
                 userType = tableColumn "type",                 userUsername = tableColumn "username",
                 userPassword = tableColumn "password"}      In an equation for `userT':          userT            = Table "User"
                $ pUser
                    User
                      {userId = pUserID $ UserID $ tableColumn "id",
                       userType = tableColumn "type",
                       userUsername = tableColumn "username",                                                              okst                       userPassword = tableColumn "password"}
tomjaguarpaw commented 6 years ago

This had me puzzled for a while! The Maybe needs to be inside the UserID', like this:

type UserIDC = UserID' (Column PGInt4)
type UserIDM = UserID' (Maybe (Column PGInt4))

$(makeAdaptorAndInstance "pUserID" ''UserID')

type UserW = User'
  (UserIDM)
  (Column PGText)

type UserR = User'
  (UserIDC)
  (Column PGText)

Thanks for raising this issue. It should probably mentioned explicitly in the tutorial.