bitemyapp / esqueleto

New home of Esqueleto, please file issues so we can get things caught up!
BSD 3-Clause "New" or "Revised" License
372 stars 107 forks source link

`SqlSelect` instances for `a :& b` #267

Closed ivanbakel closed 3 years ago

ivanbakel commented 3 years ago

Should a :& b have a SqlSelect instance, based on that of (a, b)? This has come up for me when using the experimental API, since I do something like

select $ do
  e <- from ... -- Here, the 'from' is polymorphic and user-supplied
  ... -- Using a polymorphic @e :: rec@
  pure e -- Returning @rec@

In the above example, where the from is a join, rec becomes a :& b, but since Esqueleto expects you to split the :& and return (a, b) instead, there's no appropriate instance for running the select.

The instance could look something like this:

toJoin :: (a, b) -> (a :& b)
toJoin (a, b) = (a :& b)

fromJoin :: (a :& b) -> (a, b)
fromJoin (a :& b) = (a, b)

instance (SqlSelect a ra, SqlSelect b rb) => SqlSelect (a :& b) (ra :& rb) where
    sqlSelectCols esc = sqlSelectCols esc . fromJoin
    sqlSelectColCount = sqlSelectColCount . fromJoinProxy
      where
       fromJoinProxy :: Proxy (a :& b) -> Proxy (a, b)
       fromJoinProxy Proxy = Proxy
    sqlSelectProcessRow = fmap toJoin . sqlSelectProcessRow

This is an orphan I'm using to make my code compile, but I don't know if it's the intended way.

belevy commented 3 years ago

There is no reason for the instance to not exist. It would tend to encourage very large anonymous tuples but i can definitely see advantages. @parsonsmatt thoughts?

parsonsmatt commented 3 years ago

Hey, anything that means we use less (,) tuples is good by me!