lpsmith / postgresql-simple

Mid-level client library for accessing PostgreSQL from Haskell
Other
206 stars 71 forks source link

instance (FromField a) => FromRow (Map (Either Int Text) a) #209

Open clord opened 7 years ago

clord commented 7 years ago

One of our APIs queries one of a number of tables, and return all of the columns (I know, wonderful design)

In a runtime language one might marshal the row to a dictionary and then write it out as JSON.

postgresql-simple does not seem to have easy support for capturing a row as a Map, so I'm experimentally working on writing instance (FromField a) => FromRow (Map (Either Int Text) a), where the Either is the name or the column number depending on if the name is available for that column. I don't think my hacky version is production-ready yet but such an instance might be useful to have in the library itself. Or perhaps I'm missing a more obvious way to do this?

lpsmith commented 7 years ago

Sorry for not responding earlier.

I've taken this approach on a few of my projects. e.g.

data AttrName a = AttrName !ByteString a

instance FromField a => FromField (AttrName a) where
   fromField f mv = AttrName (fromJust (name f)) <$> fromField f mv

Uhh, I'm not sure when name returns Nothing. I don't think it does, because the postgres convention is that unnamed columns are provided the name column1, column2, etc, but don't quote me on that. The underlying libpq fname C call would return Nothing when called on null pointer, but that shouldn't ever happen in haskell-land with vanilla postgresql-simple. So the fact that name returns Maybe ByteString instead of ByteString might just be a minor thing I overlooked in the API.

In any case, it would probably be more efficient to handle column1 etc as an integer; whether or not that makes a tangible difference in your use case, I don't know. It would definitely be more efficient to split the columns into two maps, though, one for ints, the other for descriptive names

lpsmith commented 7 years ago

As for the possibility of including AttrName in postgresql-simple, or take it one step further with instance (FromField a) => FromRow (Map Text a), I don't know, I haven't thought about it much. Maybe? I suppose it all depends on how often people are writing this sort of thing, and to what extent we can accommodate most similar use cases with one approach.