Search code examples
haskellesqueleto

How do I filter Just field in Esqueleto?


With the following Persistent schema,

Picture
  bytes ByteString
  desc Text Maybe

I want to query SELECT id, desc FROM picture WHERE desc IS NOT NULL. But

previews :: SqlPersistT Handler [(E.Value (Key Picture), E.Value Text)]
previews = E.select $ from $ \pics -> do
  where_ $ pics ?. PictureDesc E.!=. nothing
  return ( pics ^. PictureId
         , pics ?. PictureDesc
         )

• Couldn't match type ‘Maybe (Entity Picture)’
                 with ‘Entity Picture’
  Expected type: SqlExpr (Entity Picture)
    Actual type: SqlExpr (Maybe (Entity Picture))
• In the first argument of ‘(^.)’, namely ‘pics’

How do I achieve the previews' signature?


Solution

  • You tried to use the (?.) operator to get a non-Maybe Value from a Maybe field in a non-Maybe entity, but what it does is to get you a Maybe Value from a non-Maybe field in a Maybe entity. Here, your entity actually isn't Maybe because it isn't the result of an outer join.

    I don't think returning a Value Text is possible without unsafe functions, since filtering with where_ doesn't change the type of the nullable field to be non-nullable. (There ought to be a projection operator that does what you want to do, in my opinion.)

    So you could do this

    previews :: SqlPersistT Handler [(Value (Key Picture), Value (Maybe Text))]
    previews = select $ from $ \pics -> do
      where_ $ not_ . isNothing $ pics ^. PictureDesc
      return ( pics ^. PictureId
             , pics ^. PictureDesc
             )
    

    or remove the Maybe, using Control.Arrow's second and Data.Maybe's fromJust, although there might be a more elegant way:

    previews' :: SqlPersistT Handler [(Value (Key Picture), Value Text)]
    previews' = do
      xs <- select $ from $ \pics -> do
        where_ $ not_ . isNothing $ pics ^. PictureDesc
        return ( pics ^. PictureId
               , (pics ^. PictureDesc)
               )
      return (map (second $ fmap fromJust) xs)
    

    I haven't run this code, only compiled it.