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

Running into non-exhaustive pattern match with groupBy #25

Closed
lierdakil opened this issue Apr 8, 2017 · 7 comments
Closed

Running into non-exhaustive pattern match with groupBy #25

lierdakil opened this issue Apr 8, 2017 · 7 comments

Comments

@lierdakil
Copy link

*** Exception: src/Database/Esqueleto/Internal/Sql.hs:1102:30-62: Non-exhaustive patterns in lambda

As far as I can tell, this happens when I use EntityId in groupBy where primary key is defined as Primary key instead of Id.

@bitemyapp
Copy link
Owner

bitemyapp commented Apr 8, 2017

I've only just given this a look, but it could be related to: prowdsponsor/esqueleto#87 or prowdsponsor/esqueleto#88

Otherwise it could just be an absent explicit composite key error.

I'm stuck in an airport right now. I'll do a more thorough peek around when I am home. If you have more information or a more complete repro please share it here.

@lierdakil
Copy link
Author

Here we go.

Boilerplate:

{-# LANGUAGE EmptyDataDecls             #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE QuasiQuotes                #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE ScopedTypeVariables        #-}
module Test where
import           Control.Monad.IO.Class  (liftIO)
import           Database.Esqueleto
import qualified Database.Persist.Sqlite as S
import           Database.Persist.TH

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    Primary name
    deriving Show
BlogPost
    title String
    authorId PersonId
    Primary title
    deriving Show
|]

main :: IO ()
main = S.runSqlite ":memory:" $ do
    runMigration migrateAll

    johnId <- insert $ Person "John Doe" $ Just 35
    janeId <- insert $ Person "Jane Doe" Nothing

    insert $ BlogPost "My fr1st p0st" johnId
    insert $ BlogPost "One more for good measure" johnId

    -- actual test code goes here

So, this works pretty much as one would expect:

    join <- select $ from $
      \ ( person `InnerJoin` post ) -> do
      on $ person ^. PersonId ==. post ^. BlogPostAuthorId
      return (person ^. PersonId, post ^. BlogPostId)
    liftIO $ print join

returns

[ (Value (PersonKey {unPersonKey = "John Doe"}),Value (BlogPostKey {unBlogPostKey = "My fr1st p0st"}))
, (Value (PersonKey {unPersonKey = "John Doe"}),Value (BlogPostKey {unBlogPostKey = "One more for good measure"}))
]

Now let's try to apply a group statement here:

    (join :: [(Value (Key Person), Value Int)]) <- select $ from $
      \ ( person `InnerJoin` post ) -> do
      on $ person ^. PersonId ==. post ^. BlogPostAuthorId
      groupBy (person ^. PersonId)
      return (person ^. PersonId, count $ post ^. BlogPostId)
    liftIO $ print join

here I get

*** Exception: src/Database/Esqueleto/Internal/Sql.hs:1102:30-62: Non-exhaustive patterns in lambda

Okay. But avoiding PersonId in groupBy again works as expected:

    (join :: [(Value (Key Person), Value Int)]) <- select $ from $
      \ ( person `InnerJoin` post ) -> do
      on $ person ^. PersonId ==. post ^. BlogPostAuthorId
      groupBy (person ^. PersonName)
      return (person ^. PersonId, count $ post ^. BlogPostId)
    liftIO $ print join

yields

[(Value (PersonKey {unPersonKey = "John Doe"}),Value 2)]

Does this make sense? Intuitively, I would expect PersonId to be roughly equivalent to PersonName, since, well, albeit technically different types, these two reference the same column. But in practice it turns out it's not the case. I would accept a type error, of course, but runtime error seems entirely out of the left field, doesn't it?

As far as I can tell, this should be relatively straightforward to fix, but I'm not familiar enough with either persistent or esqueleto code base to say what that fix should actually be.

@lierdakil
Copy link
Author

P.S. You may notice that prowdsponsor/esqueleto#88 didn't update makeGroupBy, while it did update makeHaving, makeWhere and makeOrderBy

@alebon
Copy link

alebon commented Apr 25, 2017

Same issue here :/

@bitemyapp
Copy link
Owner

@lierdakil @alebon Friends, Russians, countrymen...lend me your ears. I have a PR over yonder. If you could confirm that this fixes the issue for you, I'd be very grateful.

Tho', I'm already grateful because you made this bug a lot easier to suss out. Thank you!

@bitemyapp
Copy link
Owner

No reply so I am going forward with this, hopefully it sorts you out.

@bitemyapp
Copy link
Owner

http://hackage.haskell.org/package/esqueleto-2.5.2 is now released, please let me know if this fixed your problem. Thank you again for the very detailed and helpful bug report!

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

3 participants